```python
pip install cvxpy==1.1.18
```

    Collecting cvxpy==1.1.18
      Downloading cvxpy-1.1.18-cp37-cp37m-manylinux_2_24_x86_64.whl (2.7 MB)
         |████████████████████████████████| 2.7 MB 5.0 MB/s
    Requirement already satisfied: osqp>=0.4.1 in /usr/local/lib/python3.7/dist-packages (from cvxpy==1.1.18) (0.6.2.post0)
    Requirement already satisfied: ecos>=2 in /usr/local/lib/python3.7/dist-packages (from cvxpy==1.1.18) (2.0.10)
    Requirement already satisfied: numpy>=1.15 in /usr/local/lib/python3.7/dist-packages (from cvxpy==1.1.18) (1.19.5)
    Requirement already satisfied: scs>=1.1.6 in /usr/local/lib/python3.7/dist-packages (from cvxpy==1.1.18) (3.0.1)
    Requirement already satisfied: scipy>=1.1.0 in /usr/local/lib/python3.7/dist-packages (from cvxpy==1.1.18) (1.4.1)
    Requirement already satisfied: qdldl in /usr/local/lib/python3.7/dist-packages (from osqp>=0.4.1->cvxpy==1.1.18) (0.1.5.post0)
    Installing collected packages: cvxpy
      Attempting uninstall: cvxpy
        Found existing installation: cvxpy 1.0.31
        Uninstalling cvxpy-1.0.31:
          Successfully uninstalled cvxpy-1.0.31
    Successfully installed cvxpy-1.1.18

```python
from sympy import *
import numpy as np

n = 6

x1, x2, x3, x4, x5, x6 = symbols('x1 x2 x3 x4 x5 x6', commutative=False)

g = (x1 + x2 + x3 + x4 + x5 + x6)

beta = ( 1 + g + g**2 ).expand().args
```

```python
gamma = [None] * len(beta)
```

```python
for l in range(len(beta)):
    order = beta[l].args

    flag = True
    for _ in range(len( order) ):
        flag = False
        if isinstance(order[_], Integer):
            flag = True

    if not flag:
        # revert
        gamma[l] = prod( list ( ( order )[::-1] ) )
    else:
        gamma[l] = beta[l]

```

```python
B1 = [beta[i] * x1 *  gamma[j] for i in range(len(beta)) for j in range(len(beta))]
B2 = [beta[i] * x2 *  gamma[j] for i in range(len(beta)) for j in range(len(beta))]
B3 = [beta[i] * x3 *  gamma[j] for i in range(len(beta)) for j in range(len(beta))]
B4 = [beta[i] * x4 *  gamma[j] for i in range(len(beta)) for j in range(len(beta))]
B5 = [beta[i] * x5 *  gamma[j] for i in range(len(beta)) for j in range(len(beta))]
B6 = [beta[i] * x6 *  gamma[j] for i in range(len(beta)) for j in range(len(beta))]
B7 = [beta[i] *  gamma[j] for i in range(len(beta)) for j in range(len(beta))]
```

```python
S = 1 + g +  g**2 + g**3 + g**4 +  g**5
```

```python
Args = list( S.expand().args )
```

```python
len(Args)
```

    9331

```python
Args_dict = {}

for i in range(len(Args)):
    Args_dict[Args[i]] = i

def find_basis(B):
    Z =  np.zeros(len(B), dtype=int)
    for l in range(len(B)):
        Z[l] = Args_dict[B[l]]
    return Z

```

```python
Z1 = find_basis(B1).reshape(len(beta), len(beta))
Z2 = find_basis(B2).reshape(len(beta), len(beta))
Z3 = find_basis(B3).reshape(len(beta), len(beta))
Z4 = find_basis(B4).reshape(len(beta), len(beta))
Z5 = find_basis(B5).reshape(len(beta), len(beta))
Z6 = find_basis(B6).reshape(len(beta), len(beta))
Z7 = find_basis(B7).reshape(len(beta), len(beta))

# very slow, should optimize.
```

```python
U = [Z1, Z2, Z3, Z4, Z5, Z6, Z7]
```

```python
import itertools

perm = list(itertools.permutations([x1,x2,x3,x4,x5, x6], 4))
```

```python
T = ( sum([prod(perm[_]) for _ in range(len(perm))]) ).expand().args
```

```python
G = find_basis(T)
```

```python
A = [None] * len(Args)

for index in range(len(Args)):
    A[index] = np.zeros( ( (n+1) * len(beta) + 1,  (n+1) * len(beta) + 1) )
    M = np.zeros((len(beta), len(beta)))
    for k in range(n+1):
        start = 1 + k * len(beta)
        final = 1 + (k + 1) * len(beta)
        P = U[k] == index
        if k < n:
            M += P
            A[index][ start:final, start:final ] = P
        else:
            A[index][ start:final, start:final ] = n * P - M
```

```python
A[0][0, 0] = -1
```

```python
import cvxpy as cp
import numpy as np

# Generate a random SDP.
p = len(Args)

C = np.zeros(((n+1) * len(beta) + 1, (n+1) * len(beta) + 1))
C[0,0]=1
b = np.zeros(p)
b[G] = -1

# Define and solve the CVXPY problem.
# Create a symmetric matrix variable.
X = cp.Variable(((n+1) * len(beta) + 1, (n+1) * len(beta) + 1), symmetric=True)
# The operator >> denotes matrix inequality.
constraints = [X >> 0]
constraints += [
    cp.trace(A[i] @ X) == b[i] for i in range(p)
]
prob = cp.Problem(cp.Minimize(cp.trace(C @ X)),
                  constraints)
prob.solve(verbose=True)

# Print result.
print("The optimal value is", prob.value)
print("A solution X is")
print(X.value)
```

    ===============================================================================
                                         CVXPY
                                        v1.1.18
    ===============================================================================
    (CVXPY) Jan 23 05:36:33 AM: Your problem has 91204 variables, 9332 constraints, and 0 parameters.
    (CVXPY) Jan 23 05:36:34 AM: It is compliant with the following grammars: DCP, DQCP
    (CVXPY) Jan 23 05:36:34 AM: (If you need to solve this problem multiple times, but with different data, consider using parameters.)
    (CVXPY) Jan 23 05:36:34 AM: CVXPY will first compile your problem; then, it will invoke a numerical solver to obtain a solution.
    -------------------------------------------------------------------------------
                                      Compilation
    -------------------------------------------------------------------------------
    (CVXPY) Jan 23 05:36:35 AM: Compiling problem (target solver=SCS).
    (CVXPY) Jan 23 05:36:35 AM: Reduction chain: Dcp2Cone -> CvxAttr2Constr -> ConeMatrixStuffing -> SCS
    (CVXPY) Jan 23 05:36:35 AM: Applying reduction Dcp2Cone
    (CVXPY) Jan 23 05:36:36 AM: Applying reduction CvxAttr2Constr
    (CVXPY) Jan 23 05:36:37 AM: Applying reduction ConeMatrixStuffing
    (CVXPY) Jan 23 05:39:34 AM: Applying reduction SCS
    (CVXPY) Jan 23 05:39:39 AM: Finished problem compilation (took 1.853e+02 seconds).
    -------------------------------------------------------------------------------
                                    Numerical solver
    -------------------------------------------------------------------------------
    (CVXPY) Jan 23 05:39:39 AM: Invoking solver SCS  to obtain a solution.
    ------------------------------------------------------------------
    	       SCS v3.0.0 - Splitting Conic Solver
    	(c) Brendan O'Donoghue, Stanford University, 2012
    ------------------------------------------------------------------
    problem:  variables n: 45753, constraints m: 55084
    cones: 	  z: primal zero / dual free vars: 9331
    	  s: psd vars: 45753, ssize: 1
    settings: eps_abs: 1.0e-05, eps_rel: 1.0e-05, eps_infeas: 1.0e-07
    	  alpha: 1.50, scale: 1.00e-01, adaptive_scale: 1
    	  max_iters: 100000, normalize: 1, warm_start: 0
    	  acceleration_lookback: 10, acceleration_interval: 10
    lin-sys:  sparse-direct
    	  nnz(A): 69587, nnz(P): 0
    ------------------------------------------------------------------
     iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
    ------------------------------------------------------------------
         0| 2.71e+01  1.00e+00  3.41e+01 -1.00e+01  1.00e-01  3.32e-02
       250| 1.48e-01  1.62e-03  8.88e-04  3.50e+02  2.83e-02  3.67e+00
       500| 1.24e-01  4.60e-04  6.64e-04  3.55e+02  2.83e-02  7.28e+00
       750| 3.59e-02  7.80e-05  3.13e-04  3.57e+02  2.83e-02  1.10e+01
      1000| 3.90e-02  7.51e-05  5.52e-04  3.57e+02  2.83e-02  1.47e+01
      1250| 4.12e-02  4.50e-05  3.60e-04  3.58e+02  2.83e-02  1.84e+01
      1500| 4.36e-02  1.32e-04  3.72e-04  3.58e+02  2.83e-02  2.21e+01
      1750| 2.07e+03  4.18e+01  1.69e-03  3.72e+02  2.83e-02  2.58e+01
      2000| 4.35e-02  4.58e-05  3.01e-04  3.58e+02  2.83e-02  2.95e+01
      2250| 4.36e-02  3.23e-05  2.95e-04  3.58e+02  2.83e-02  3.32e+01
      2500| 4.36e-02  3.08e-05  2.78e-04  3.58e+02  2.83e-02  3.69e+01
      2750| 4.36e-02  2.99e-05  2.66e-04  3.58e+02  2.83e-02  4.06e+01
      3000| 4.36e-02  2.84e-05  2.52e-04  3.58e+02  2.83e-02  4.43e+01
      3250| 4.36e-02  2.73e-05  2.39e-04  3.58e+02  2.83e-02  4.80e+01
      3500| 4.36e-02  2.60e-05  2.26e-04  3.58e+02  2.83e-02  5.17e+01
      3750| 4.36e-02  2.48e-05  2.13e-04  3.59e+02  2.83e-02  5.54e+01
      4000| 4.36e-02  2.36e-05  2.00e-04  3.59e+02  2.83e-02  5.92e+01
      4250| 4.36e-02  2.24e-05  1.87e-04  3.59e+02  2.83e-02  6.29e+01
      4500| 2.41e+01  4.88e-01  2.13e-02  2.34e+02  2.83e-02  6.66e+01
      4750| 4.36e-02  1.99e-05  1.61e-04  3.59e+02  2.83e-02  7.03e+01
      5000| 4.36e-02  1.87e-05  1.47e-04  3.59e+02  2.83e-02  7.40e+01
      5250| 4.37e-02  1.75e-05  1.34e-04  3.59e+02  2.83e-02  7.77e+01
      5500| 4.37e-02  1.63e-05  1.21e-04  3.59e+02  2.83e-02  8.14e+01
      5750| 4.37e-02  1.51e-05  1.08e-04  3.59e+02  2.83e-02  8.51e+01
      6000| 4.37e-02  1.39e-05  9.54e-05  3.59e+02  2.83e-02  8.87e+01
      6250| 4.37e-02  1.26e-05  8.24e-05  3.59e+02  2.83e-02  9.24e+01
      6500| 4.37e-02  1.14e-05  6.95e-05  3.60e+02  2.83e-02  9.61e+01
      6750| 4.37e-02  1.02e-05  5.66e-05  3.60e+02  2.83e-02  9.99e+01
      7000| 4.37e-02  9.02e-06  4.36e-05  3.60e+02  2.83e-02  1.04e+02
      7250| 1.18e+02  2.39e+00  3.43e-01  1.34e+02  2.83e-02  1.07e+02
      7500| 4.37e-02  6.60e-06  1.77e-05  3.60e+02  2.83e-02  1.11e+02
      7750| 4.37e-02  5.40e-06  4.76e-06  3.60e+02  2.83e-02  1.15e+02
      7875| 3.30e-04  5.26e-06  6.12e-05  3.60e+02  2.83e-02  1.17e+02
    ------------------------------------------------------------------
    status:  solved
    timings: total: 1.17e+02s = setup: 1.44e-01s + solve: 1.17e+02s
    	 lin-sys: 1.57e+01s, cones: 9.10e+01s, accel: 1.71e+00s
    ------------------------------------------------------------------
    objective = 360.000317
    ------------------------------------------------------------------
    -------------------------------------------------------------------------------
                                        Summary
    -------------------------------------------------------------------------------
    (CVXPY) Jan 23 05:41:37 AM: Problem status: optimal
    (CVXPY) Jan 23 05:41:37 AM: Optimal value: 3.600e+02
    (CVXPY) Jan 23 05:41:37 AM: Compilation took 1.853e+02 seconds
    (CVXPY) Jan 23 05:41:37 AM: Solver (including time spent in interface) took 1.169e+02 seconds
    The optimal value is 360.00028650857746
    A solution X is
    [[360.00028651   0.           0.         ...   0.           0.
        0.        ]
     [  0.          98.98597187 -60.88376714 ...   0.           0.
        0.        ]
     [  0.         -60.88376714  49.55637348 ...   0.           0.
        0.        ]
     ...
     [  0.           0.           0.         ...   0.94285431   0.41599914
        0.41599914]
     [  0.           0.           0.         ...   0.41599914   0.94285431
        0.41599914]
     [  0.           0.           0.         ...   0.41599914   0.41599914
        0.94285431]]

```python
import cvxpy as cp
import numpy as np

# Generate a random SDP.
p = len(Args)

C = np.zeros(((n+1) * len(beta) + 1, (n+1) * len(beta) + 1))
C[0,0]=1
b = np.zeros(p)
b[G] = 1

# Define and solve the CVXPY problem.
# Create a symmetric matrix variable.
X = cp.Variable(((n+1) * len(beta) + 1, (n+1) * len(beta) + 1), symmetric=True)
# The operator >> denotes matrix inequality.
constraints = [X >> 0]
constraints += [
    cp.trace(A[i] @ X) == b[i] for i in range(p)
]
prob = cp.Problem(cp.Minimize(cp.trace(C @ X)),
                  constraints)
prob.solve(verbose=True)

# Print result.
print("The optimal value is", prob.value)
print("A solution X is")
print(X.value)
```

    ===============================================================================
                                         CVXPY
                                        v1.1.18
    ===============================================================================
    (CVXPY) Jan 23 05:53:27 AM: Your problem has 91204 variables, 9332 constraints, and 0 parameters.
    (CVXPY) Jan 23 05:53:27 AM: It is compliant with the following grammars: DCP, DQCP
    (CVXPY) Jan 23 05:53:27 AM: (If you need to solve this problem multiple times, but with different data, consider using parameters.)
    (CVXPY) Jan 23 05:53:27 AM: CVXPY will first compile your problem; then, it will invoke a numerical solver to obtain a solution.
    -------------------------------------------------------------------------------
                                      Compilation
    -------------------------------------------------------------------------------
    (CVXPY) Jan 23 05:53:28 AM: Compiling problem (target solver=SCS).
    (CVXPY) Jan 23 05:53:28 AM: Reduction chain: Dcp2Cone -> CvxAttr2Constr -> ConeMatrixStuffing -> SCS
    (CVXPY) Jan 23 05:53:28 AM: Applying reduction Dcp2Cone
    (CVXPY) Jan 23 05:53:29 AM: Applying reduction CvxAttr2Constr
    (CVXPY) Jan 23 05:53:30 AM: Applying reduction ConeMatrixStuffing
    (CVXPY) Jan 23 05:56:33 AM: Applying reduction SCS
    (CVXPY) Jan 23 05:56:39 AM: Finished problem compilation (took 1.915e+02 seconds).
    -------------------------------------------------------------------------------
                                    Numerical solver
    -------------------------------------------------------------------------------
    (CVXPY) Jan 23 05:56:39 AM: Invoking solver SCS  to obtain a solution.
    ------------------------------------------------------------------
    	       SCS v3.0.0 - Splitting Conic Solver
    	(c) Brendan O'Donoghue, Stanford University, 2012
    ------------------------------------------------------------------
    problem:  variables n: 45753, constraints m: 55084
    cones: 	  z: primal zero / dual free vars: 9331
    	  s: psd vars: 45753, ssize: 1
    settings: eps_abs: 1.0e-05, eps_rel: 1.0e-05, eps_infeas: 1.0e-07
    	  alpha: 1.50, scale: 1.00e-01, adaptive_scale: 1
    	  max_iters: 100000, normalize: 1, warm_start: 0
    	  acceleration_lookback: 10, acceleration_interval: 10
    lin-sys:  sparse-direct
    	  nnz(A): 69587, nnz(P): 0
    ------------------------------------------------------------------
     iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
    ------------------------------------------------------------------
         0| 2.72e+01  1.00e+00  3.41e+01 -1.01e+01  1.00e-01  2.93e-02
       250| 1.27e-01  7.16e-03  1.25e-01  1.24e+02  1.00e-01  3.66e+00
       500| 6.73e-02  4.78e-03  5.66e-02  1.47e+02  1.00e-01  7.32e+00
       750| 4.69e-02  4.59e-03  3.03e-02  1.55e+02  1.00e-01  1.10e+01
      1000| 7.51e-02  3.17e-03  2.16e-02  1.66e+02  3.15e-02  1.46e+01
      1250| 1.57e-01  9.53e-05  5.73e-03  1.75e+02  8.54e-03  1.82e+01
      1500| 2.13e-01  8.21e-05  3.38e-03  1.75e+02  8.54e-03  2.19e+01
      1750| 2.16e-01  2.55e-05  3.41e-03  1.77e+02  8.54e-03  2.55e+01
      2000| 1.96e-01  2.67e-05  3.15e-03  1.78e+02  8.54e-03  2.91e+01
      2250| 1.83e-01  3.05e-05  3.04e-03  1.79e+02  8.54e-03  3.29e+01
      2500| 1.68e-01  2.91e-05  2.91e-03  1.80e+02  8.54e-03  3.65e+01
      2750| 5.24e-02  6.69e-05  2.63e-03  1.81e+02  8.54e-03  4.02e+01
      3000| 5.43e-02  6.71e-05  2.39e-03  1.81e+02  8.54e-03  4.38e+01
      3250| 8.11e-02  5.82e-04  2.38e-03  1.83e+02  8.54e-03  4.74e+01
      3500| 5.31e-02  2.84e-05  2.14e-03  1.83e+02  8.54e-03  5.11e+01
      3750| 5.23e-02  2.25e-05  2.11e-03  1.84e+02  8.54e-03  5.47e+01
      4000| 5.18e-02  2.22e-05  2.06e-03  1.84e+02  8.54e-03  5.83e+01
      4250| 5.14e-02  2.18e-05  2.02e-03  1.84e+02  8.54e-03  6.19e+01
      4500| 5.09e-02  2.14e-05  1.97e-03  1.85e+02  8.54e-03  6.55e+01
      4750| 5.04e-02  2.11e-05  1.93e-03  1.85e+02  8.54e-03  6.91e+01
      5000| 5.11e-02  1.99e-05  1.52e-03  1.86e+02  8.54e-03  7.27e+01
      5250| 4.89e-02  1.78e-05  1.59e-03  1.86e+02  8.54e-03  7.63e+01
      5500| 4.07e+02  3.52e+00  7.13e-04  2.13e+02  8.54e-03  8.00e+01
      5750| 4.78e-02  1.73e-05  1.53e-03  1.87e+02  8.54e-03  8.37e+01
      6000| 4.71e-02  1.72e-05  1.51e-03  1.87e+02  8.54e-03  8.73e+01
      6250| 4.66e-02  1.69e-05  1.49e-03  1.87e+02  8.54e-03  9.11e+01
      6500| 4.61e-02  1.67e-05  1.46e-03  1.88e+02  8.54e-03  9.47e+01
      6750| 4.56e-02  1.65e-05  1.44e-03  1.88e+02  8.54e-03  9.83e+01
      7000| 4.52e-02  1.63e-05  1.41e-03  1.88e+02  8.54e-03  1.02e+02
      7250| 4.47e-02  1.61e-05  1.39e-03  1.88e+02  8.54e-03  1.06e+02
      7500| 4.42e-02  1.59e-05  1.37e-03  1.89e+02  8.54e-03  1.09e+02
      7750| 4.37e-02  1.57e-05  1.35e-03  1.89e+02  8.54e-03  1.13e+02
      8000| 4.33e-02  1.55e-05  1.33e-03  1.89e+02  8.54e-03  1.16e+02
      8250| 2.67e+03  2.31e+01  1.31e-02  2.47e+02  8.54e-03  1.20e+02
      8500| 4.24e-02  1.52e-05  1.29e-03  1.90e+02  8.54e-03  1.24e+02
      8750| 4.20e-02  1.50e-05  1.27e-03  1.90e+02  8.54e-03  1.27e+02
      9000| 4.16e-02  1.48e-05  1.25e-03  1.90e+02  8.54e-03  1.31e+02
      9250| 4.12e-02  1.47e-05  1.18e-03  1.90e+02  8.54e-03  1.35e+02
      9500| 4.07e-02  1.45e-05  1.22e-03  1.91e+02  8.54e-03  1.38e+02
      9750| 4.03e-02  1.44e-05  1.20e-03  1.91e+02  8.54e-03  1.42e+02
     10000| 3.99e-02  1.42e-05  1.18e-03  1.91e+02  8.54e-03  1.45e+02
     10250| 3.96e-02  1.40e-05  1.17e-03  1.91e+02  8.54e-03  1.49e+02
     10500| 3.92e-02  1.39e-05  1.15e-03  1.91e+02  8.54e-03  1.53e+02
     10750| 3.88e-02  1.37e-05  1.13e-03  1.92e+02  8.54e-03  1.56e+02
     11000| 1.23e+00  1.06e-02  1.22e-02  1.91e+02  8.54e-03  1.60e+02
     11250| 3.81e-02  1.34e-05  1.10e-03  1.92e+02  8.54e-03  1.63e+02
     11500| 3.77e-02  1.33e-05  1.09e-03  1.92e+02  8.54e-03  1.67e+02
     11750| 3.74e-02  1.32e-05  1.07e-03  1.92e+02  8.54e-03  1.71e+02
     12000| 3.70e-02  1.30e-05  1.06e-03  1.93e+02  8.54e-03  1.74e+02
     12250| 3.67e-02  1.29e-05  1.05e-03  1.93e+02  8.54e-03  1.78e+02
     12500| 3.64e-02  1.27e-05  1.03e-03  1.93e+02  8.54e-03  1.82e+02
     12750| 3.60e-02  1.26e-05  1.02e-03  1.93e+02  8.54e-03  1.85e+02
     13000| 3.57e-02  1.25e-05  1.01e-03  1.93e+02  8.54e-03  1.89e+02
     13250| 3.54e-02  1.24e-05  9.96e-04  1.93e+02  8.54e-03  1.92e+02
     13500| 3.51e-02  1.22e-05  9.84e-04  1.94e+02  8.54e-03  1.96e+02
     13750| 1.39e+02  1.21e+00  4.21e-03  2.00e+02  8.54e-03  2.00e+02
     14000| 3.45e-02  1.20e-05  9.61e-04  1.94e+02  8.54e-03  2.03e+02
     14250| 3.42e-02  1.19e-05  9.47e-04  1.94e+02  8.54e-03  2.07e+02
     14500| 3.39e-02  1.18e-05  9.36e-04  1.94e+02  8.54e-03  2.11e+02
     14750| 3.36e-02  1.17e-05  9.25e-04  1.94e+02  8.54e-03  2.15e+02
     15000| 3.33e-02  1.15e-05  9.14e-04  1.94e+02  8.54e-03  2.18e+02
     15250| 3.30e-02  1.14e-05  9.04e-04  1.95e+02  8.54e-03  2.22e+02
     15500| 3.28e-02  1.13e-05  8.91e-04  1.95e+02  8.54e-03  2.26e+02
     15750| 3.25e-02  1.12e-05  8.81e-04  1.95e+02  8.54e-03  2.29e+02
     16000| 3.22e-02  1.11e-05  8.73e-04  1.95e+02  8.54e-03  2.33e+02
     16250| 3.19e-02  1.10e-05  8.63e-04  1.95e+02  8.54e-03  2.37e+02
     16500| 8.17e+00  7.06e-02  2.04e-02  1.85e+02  8.54e-03  2.40e+02
     16750| 3.14e-02  1.08e-05  8.43e-04  1.95e+02  8.54e-03  2.44e+02
     17000| 3.12e-02  1.07e-05  8.35e-04  1.96e+02  8.54e-03  2.48e+02
     17250| 3.09e-02  1.06e-05  8.27e-04  1.96e+02  8.54e-03  2.51e+02
     17500| 3.07e-02  1.05e-05  8.17e-04  1.96e+02  8.54e-03  2.55e+02
     17750| 3.04e-02  1.04e-05  8.08e-04  1.96e+02  8.54e-03  2.59e+02
     18000| 3.02e-02  1.03e-05  7.99e-04  1.96e+02  8.54e-03  2.62e+02
     18250| 2.99e-02  1.02e-05  7.91e-04  1.96e+02  8.54e-03  2.66e+02
     18500| 2.97e-02  1.02e-05  7.83e-04  1.96e+02  8.54e-03  2.70e+02
     18750| 2.95e-02  1.00e-05  7.74e-04  1.96e+02  8.54e-03  2.73e+02
     19000| 2.92e-02  9.96e-06  7.65e-04  1.96e+02  8.54e-03  2.77e+02
     19250| 3.01e+02  2.61e+00  1.79e-03  2.00e+02  8.54e-03  2.81e+02
     19500| 2.88e-02  9.80e-06  7.50e-04  1.97e+02  8.54e-03  2.84e+02
     19750| 2.86e-02  9.69e-06  7.43e-04  1.97e+02  8.54e-03  2.88e+02
     20000| 2.94e-02  1.07e-05  6.22e-04  1.97e+02  8.54e-03  2.91e+02
     20250| 1.93e-02  1.84e-06  1.47e-04  1.97e+02  8.54e-03  2.95e+02
     20500| 1.95e-02  2.90e-06  1.38e-04  1.97e+02  8.54e-03  2.99e+02
     20750| 1.93e-02  1.94e-06  1.39e-04  1.97e+02  8.54e-03  3.02e+02
     21000| 1.91e-02  1.89e-06  1.35e-04  1.97e+02  8.54e-03  3.06e+02
     21250| 1.89e-02  1.89e-06  1.36e-04  1.97e+02  8.54e-03  3.10e+02
     21500| 1.87e-02  1.87e-06  1.35e-04  1.97e+02  8.54e-03  3.13e+02
     21750| 1.85e-02  1.85e-06  1.33e-04  1.97e+02  8.54e-03  3.17e+02
     22000| 1.83e-02  1.83e-06  1.31e-04  1.97e+02  8.54e-03  3.21e+02
     22250| 1.81e-02  1.82e-06  1.31e-04  1.97e+02  8.54e-03  3.24e+02
     22500| 1.40e-01  7.84e-04  4.33e-02  1.97e+02  8.54e-03  3.28e+02
     22750| 1.78e-02  1.76e-06  1.26e-04  1.97e+02  8.54e-03  3.32e+02
     23000| 1.76e-02  1.75e-06  1.24e-04  1.97e+02  8.54e-03  3.36e+02
     23250| 1.74e-02  1.74e-06  1.23e-04  1.97e+02  8.54e-03  3.39e+02
     23500| 1.72e-02  1.73e-06  1.23e-04  1.97e+02  8.54e-03  3.43e+02
     23750| 1.71e-02  1.73e-06  1.21e-04  1.97e+02  8.54e-03  3.47e+02
     24000| 1.69e-02  1.70e-06  1.21e-04  1.97e+02  8.54e-03  3.50e+02
     24250| 1.67e-02  1.68e-06  1.20e-04  1.97e+02  8.54e-03  3.54e+02
     24500| 1.66e-02  1.67e-06  1.19e-04  1.97e+02  8.54e-03  3.58e+02
     24750| 1.64e-02  1.64e-06  1.16e-04  1.97e+02  8.54e-03  3.61e+02
     25000| 1.62e-02  1.62e-06  1.16e-04  1.97e+02  8.54e-03  3.65e+02
     25250| 2.66e+00  1.62e-02  3.91e-03  1.98e+02  8.54e-03  3.69e+02
     25500| 1.59e-02  1.61e-06  1.15e-04  1.97e+02  8.54e-03  3.72e+02
     25750| 1.58e-02  1.58e-06  1.13e-04  1.97e+02  8.54e-03  3.76e+02
     26000| 1.56e-02  1.57e-06  1.13e-04  1.97e+02  8.54e-03  3.80e+02
     26250| 1.55e-02  1.54e-06  1.10e-04  1.97e+02  8.54e-03  3.84e+02
     26500| 1.53e-02  1.54e-06  1.08e-04  1.97e+02  8.54e-03  3.87e+02
     26750| 1.52e-02  1.53e-06  1.07e-04  1.97e+02  8.54e-03  3.91e+02
     27000| 1.47e-02  1.49e-05  3.06e-04  1.97e+02  2.70e-02  3.95e+02
     27250| 1.43e-02  1.44e-05  2.90e-04  1.97e+02  2.70e-02  3.98e+02
     27500| 1.38e-02  1.40e-05  2.95e-04  1.97e+02  2.70e-02  4.02e+02
     27750| 1.34e-02  1.36e-05  2.94e-04  1.97e+02  2.70e-02  4.06e+02
     28000| 1.30e-02  1.32e-05  2.90e-04  1.97e+02  2.70e-02  4.09e+02
     28250| 1.26e-02  1.28e-05  2.82e-04  1.97e+02  2.70e-02  4.13e+02
     28500| 1.22e-02  1.25e-05  2.73e-04  1.97e+02  2.70e-02  4.17e+02
     28750| 7.89e-01  1.52e-02  2.64e-04  1.98e+02  2.70e-02  4.20e+02
     29000| 1.15e-02  1.18e-05  2.57e-04  1.97e+02  2.70e-02  4.24e+02
     29250| 1.12e-02  1.14e-05  2.49e-04  1.97e+02  2.70e-02  4.28e+02
     29500| 1.09e-02  1.11e-05  2.42e-04  1.97e+02  2.70e-02  4.31e+02
     29750| 1.05e-02  1.08e-05  2.34e-04  1.97e+02  2.70e-02  4.35e+02
     30000| 1.02e-02  1.05e-05  2.28e-04  1.97e+02  2.70e-02  4.39e+02
     30250| 9.93e-03  1.02e-05  2.20e-04  1.97e+02  2.70e-02  4.42e+02
     30500| 9.65e-03  9.92e-06  2.14e-04  1.97e+02  2.70e-02  4.46e+02
     30750| 9.37e-03  9.64e-06  2.07e-04  1.97e+02  2.70e-02  4.49e+02
     31000| 9.10e-03  9.36e-06  2.01e-04  1.97e+02  2.70e-02  4.53e+02
     31250| 8.84e-03  9.11e-06  1.95e-04  1.97e+02  2.70e-02  4.57e+02
     31500| 4.22e-01  8.14e-03  2.71e-04  1.98e+02  2.70e-02  4.60e+02
     31750| 8.33e-03  8.62e-06  1.84e-04  1.97e+02  2.70e-02  4.64e+02
     32000| 8.10e-03  8.36e-06  1.79e-04  1.97e+02  2.70e-02  4.68e+02
     32250| 7.87e-03  8.14e-06  1.73e-04  1.97e+02  2.70e-02  4.72e+02
     32500| 7.64e-03  7.92e-06  1.69e-04  1.97e+02  2.70e-02  4.75e+02
     32750| 7.42e-03  7.69e-06  1.64e-04  1.97e+02  2.70e-02  4.79e+02
     33000| 7.21e-03  7.48e-06  1.59e-04  1.97e+02  2.70e-02  4.82e+02
     33250| 7.01e-03  7.27e-06  1.55e-04  1.97e+02  2.70e-02  4.86e+02
     33500| 6.81e-03  7.07e-06  1.50e-04  1.97e+02  2.70e-02  4.90e+02
     33750| 6.62e-03  6.89e-06  1.46e-04  1.97e+02  2.70e-02  4.93e+02
     34000| 6.43e-03  6.69e-06  1.42e-04  1.97e+02  2.70e-02  4.97e+02
     34250| 2.70e-01  5.20e-03  6.19e-05  1.98e+02  2.70e-02  5.00e+02
     34500| 6.08e-03  6.33e-06  1.34e-04  1.97e+02  2.70e-02  5.04e+02
     34750| 5.91e-03  6.15e-06  1.30e-04  1.97e+02  2.70e-02  5.08e+02
     35000| 5.74e-03  5.98e-06  1.26e-04  1.97e+02  2.70e-02  5.11e+02
     35250| 5.58e-03  5.82e-06  1.23e-04  1.98e+02  2.70e-02  5.15e+02
     35500| 5.43e-03  5.66e-06  1.19e-04  1.98e+02  2.70e-02  5.19e+02
     35750| 5.28e-03  5.51e-06  1.16e-04  1.98e+02  2.70e-02  5.22e+02
     36000| 5.13e-03  5.36e-06  1.13e-04  1.98e+02  2.70e-02  5.26e+02
     36250| 4.99e-03  5.21e-06  1.10e-04  1.98e+02  2.70e-02  5.30e+02
     36500| 4.85e-03  5.07e-06  1.07e-04  1.98e+02  2.70e-02  5.33e+02
     36750| 4.72e-03  4.94e-06  1.04e-04  1.98e+02  2.70e-02  5.37e+02
     37000| 1.13e-01  2.17e-03  1.89e-04  1.98e+02  2.70e-02  5.40e+02
     37250| 4.46e-03  4.68e-06  9.73e-05  1.98e+02  2.70e-02  5.44e+02
     37500| 4.34e-03  4.54e-06  9.50e-05  1.98e+02  2.70e-02  5.48e+02
     37750| 4.22e-03  4.42e-06  9.26e-05  1.98e+02  2.70e-02  5.51e+02
     38000| 4.10e-03  4.30e-06  9.02e-05  1.98e+02  2.70e-02  5.55e+02
     38250| 3.99e-03  4.18e-06  8.78e-05  1.98e+02  2.70e-02  5.58e+02
     38500| 3.88e-03  4.07e-06  8.50e-05  1.98e+02  2.70e-02  5.62e+02
     38750| 3.78e-03  3.96e-06  8.23e-05  1.98e+02  2.70e-02  5.66e+02
     39000| 3.67e-03  3.86e-06  8.08e-05  1.98e+02  2.70e-02  5.70e+02
    ------------------------------------------------------------------
    status:  solved
    timings: total: 5.70e+02s = setup: 1.32e-01s + solve: 5.70e+02s
    	 lin-sys: 7.80e+01s, cones: 4.42e+02s, accel: 8.97e+00s
    ------------------------------------------------------------------
    objective = 197.538705
    ------------------------------------------------------------------
    -------------------------------------------------------------------------------
                                        Summary
    -------------------------------------------------------------------------------
    (CVXPY) Jan 23 06:06:09 AM: Problem status: optimal
    (CVXPY) Jan 23 06:06:09 AM: Optimal value: 1.975e+02
    (CVXPY) Jan 23 06:06:09 AM: Compilation took 1.915e+02 seconds
    (CVXPY) Jan 23 06:06:09 AM: Solver (including time spent in interface) took 5.698e+02 seconds
    The optimal value is 197.53866422999994
    A solution X is
    [[ 197.53866423    0.            0.         ...    0.
         0.            0.        ]
     [   0.          366.29342919 -167.47861172 ...    0.
         0.            0.        ]
     [   0.         -167.47861172   92.63853734 ...    0.
         0.            0.        ]
     ...
     [   0.            0.            0.         ...    0.99307456
         0.56950203    0.56950203]
     [   0.            0.            0.         ...    0.56950203
         0.99307456    0.56950203]
     [   0.            0.            0.         ...    0.56950203
         0.56950203    0.99307456]]

```python

```


```python
#!pip3.6 install myhdl
#!pip3.6 install myhdlpeek
```

#

## Python->Verilog->PYNQ FM GEN & Micrphone Signals Anylsis

```python
import numpy as np
import pandas as pd
from IPython.display import display, Math, Latex
from sympy import *
init_printing()
from tabulate import tabulate
import itertools

from myhdl import *
from myhdlpeek import Peeker

from random import randrange
import matplotlib.pyplot as plt
%matplotlib inline

```

# Acknowledgments
The orgianl Chebyshev Sinwave Genrator written in myHDL was done by ["HARDSOFTLUCID"](https://hardsoftlucid.wordpress.com/various-stuff/myhdl/)
(myHDL.old version [here](https://github.com/jandecaluwe/site-myhdl-retired/blob/master/_ori/pages/projects/continuous_wave_sinusgenerator.txt))

Author of myHDL [Jan Decaluwe](http://www.myhdl.org/users/jandecaluwe.html) and the author of the myHDL Peeker [XESS Corp.](https://github.com/xesscorp/myhdlpeek)

And to my Digital Signal Processing Advisor [Dr. Jesse Wilson](http://www.engr.colostate.edu/ece/facultystaff/facultypage.php?pass=146)

# Derivation of the Chebyshev Polynomial Approximation for Sin & Cos

## Chebyshev Polynomials

We Start with recalling that the double(n) angle trig identity for $n=2$ is
 $\cos$ are
$$\cos(2\theta)= \cos(\theta)^2 -\sin(\theta)^2 = 2\cos(\theta)^2 -1$$
and for $n=3$ is
$$\cos(3\theta)= cos(\theta)^3 -3\sin(\theta)^2 \cos(\theta)=4\cos(\theta)^3 -3\cos(\theta)$$

Now exploiting Chebyshev polynomials that come from the power series solution($y(x)=\sum_{n=0}^{\infty} a_n x^n$) of  Chebyshev differential equation:
$$(1-x^2)y" -xy'+p^2y=0$$

The Power series solution takes on the form of a Recurrence relation for the $a_n$ term in the Power series as
$$a_{n+2}=\dfrac{(n-p)(n+p)}{(n+1)(n+2)}a_n$$
for $x\in [-1, 1]$
that leads to the Chebyshev polynomial defined as
$$T_0(x)=1$$
$$T_1(x)=x$$
$$T_{n+1}(x)=2xT_n(x)-T_{n-1}(x)$$

### Plot of Chebyshev Polynomials

```python
x=np.linspace(-1.0, 1.0)
fig=plt.figure()
ax=plt.subplot(111)
for i in range(1,8+1):
    coeff=[0]*i
    coeff[-1]=i
    y=np.polynomial.Chebyshev(coeff)(x)
    ax.plot(x, y, label=f'$T_{i-1}(x)$')
bbox_to_anchor=ax.get_position()
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
ax.grid()
plt.title(r"Chebyshev Polynomials $T_0(x)-T_1(x), x\in[-1, 1]$" )
None
```

## Chebyshev Polynomial $\cos$ Representation

If now $T_n(x)=T_n(cos(\theta))=cos(n\theta)$ we have

$$T_0(\cos(\theta))=1$$
$$T_1(\cos(\theta))=\cos(\theta)$$
$$T_{n+1}(\cos(\theta))=2 \cos(\theta)T_n(\cos(\theta))-T_{n-1}(\cos(\theta))$$
$$\cos((n+1)\theta)=2\cos(\theta)\cos(n\theta)-\cos((n-1)\theta)$$

solving for $\cos(\theta)$ we get

```python
n, theta=symbols('n, theta')
LHS=cos(theta)
RHS=(cos((n+1)*theta)+cos((n-1)*theta))/(2*cos(n*theta))
Eq(LHS, RHS)
```

```python
f_1, f_2=symbols('f_1, f_2')
simplify((cos(2*pi*(n+1)*(f_1+f_2))+cos(2*pi*(n-1)*(f_1+f_2)))/(2*cos(2*pi*(n)*(f_1+f_2))))
```

### Plots of Chebyshev polynomial $\cos$ Approx.

```python
#numericalize symbolic
RHSN=lambdify((n, theta), RHS, dummify=False)

fig=plt.figure()
ax=plt.subplot(111)

thetaN=np.linspace(0, 2*np.pi)
for N in range(1, 8+1):
    y=RHSN(N, thetaN)
    ax.plot(thetaN, y, label=f'$C_{N-1} aprox$')
ax.plot(thetaN, np.cos(thetaN), label=r'$cos(\theta)$')
ax.grid()

ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.title(r"Plot of $\cos(\theta), \theta \in[0, 2\pi]$ & $N\in[0, 7]$ CP Approx.")
None
```

```python
thetaN=np.linspace(0, 2*np.pi)
for N in range(1, 8+1):
    y=np.cos(thetaN)-RHSN(N, thetaN)
    plt.plot(thetaN, y, label=f'$C_{N-1} error$')
plt.grid()
plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))

plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.title(r"Plot of error of $\cos(\theta), \theta \in[0, 2\pi]$ & $N\in[0, 7]$ CP Aprox")

None
```

## Algorithm Development

now letting $\cos(\theta)=\cos(2*\pi f_{\sin}/f_{clk})=K'(\theta)$ we have
$$K'((n+1)\theta)=2K'(\theta)K'(n\theta)-K'((n-1)\theta)$$

Then letting $2K'=K$ and splitting up the recursion relations we have
$$R_0=K'((n-1)\theta)$$
$$R_2=KR_1-R_0$$
where R now represents a register. We will also have to add a an overflow wrapper via a shift register

```python
def SinGenerator(SinFreq_parm, ClkFreq_parm, SinValue_out,
                clk, rst, ena):
    #contorl byte size and works with -1 to translate cos to sin
    INTERNALWIDTH=len(SinValue_out)-2

    #qunitited version of the 2x for cos(\theta)
    KONSTANT_FACTOR=int(np.cos(2*np.pi * SinFreq_parm /ClkFreq_parm)* 2**(INTERNALWIDTH))

    #prep the Needed regesters at sysnthis
    Reg_T0=Signal(intbv((2**(INTERNALWIDTH))-1,
                        min=SinValue_out.min, max=SinValue_out.max))
    Reg_T1=Signal(intbv(KONSTANT_FACTOR,
                        min=SinValue_out.min, max=SinValue_out.max))

    #define the polynomal logic
    @always(clk.posedge,rst.negedge)
    def logicCP():
        #clear and prep the regesters
        if rst== 0 :
            Reg_T0.next=(2**(INTERNALWIDTH))-1
            Reg_T1.next=KONSTANT_FACTOR

        #run a single recursion iterration of the polynomal
        else:
            if ena==1:
                # recursive Chebyshev  formulation for sinus waveform calculation
                Reg_T0.next=Reg_T1
                #>> shift is a overflow wrapper
                Reg_T1.next=((KONSTANT_FACTOR * Reg_T1)>>(INTERNALWIDTH-1)) - Reg_T0

    #pole the R1 for the value of the sin function
    @always_comb
    def comb_logic():
        SinValue_out.next=Reg_T1

    return instances()
```

# Test Bench for $\sin$ Generator

```python
SinFreq=0.75e6   # make a 1.45 mhz Sinus
clkFreq=10e6   # 10 mhz
clkPeriod=1.0/clkFreq

OUTPUT_BITWIDTH=30

Peeker.clear()

SinValue_out=Signal(intbv(0, min=-2**OUTPUT_BITWIDTH, max=2**OUTPUT_BITWIDTH))
Peeker(SinValue_out, 'SinVal')
SinValueTracker=[]

clk=Signal(bool(0)); Peeker(clk, 'clk')
ena=Signal(bool(0)); Peeker(ena, 'ena')
rst=Signal(bool(0)); Peeker(rst, 'rst')

DUT=SinGenerator(SinFreq_parm=SinFreq, ClkFreq_parm=clkFreq, SinValue_out=SinValue_out,
                clk=clk, rst=rst, ena=ena)

def SinGenerator_TB(TestClkCyc=200):

    #clock genrator
    @always(delay(int(clkPeriod*0.5*1e9)))  ## delay in nano seconds
    def clkGen():
        clk.next = not clk

    # accterla test procdure
    @instance
    def stimulus():
        while 1:
            rst.next=0
            ena.next=0
            #wait one clock cycle
            yield clk.posedge

            #test reset
            rst.next=1

            #wait one clock cycle
            yield clk.posedge

            #run the sin wave genrator
            ena.next=1
            #run the test for 200 clock cycles
            for i in range(TestClkCyc):
                #wait for next clock cycle
                yield clk.posedge
                SinValueTracker.append(int(SinValue_out))
            raise StopSimulation

    return instances()
```

!? Peeker is failing for some reason to capture all these values so haveing to improve

```python
N=200
sim = Simulation(DUT, SinGenerator_TB(TestClkCyc=N), *Peeker.instances()).run()
#Peeker.to_wavedrom(start_time=0, stop_time=20, tock=True)
```

# Post Processing of Test Bench

```python
SinGenOutDF=pd.DataFrame(columns=['SinValue'], data=SinValueTracker)
SinGenOutDF['Time[s]']=np.arange(0.0,clkPeriod*(len(SinGenOutDF)-0.5),clkPeriod)
SinGenOutDF['SinValueNorm']=SinGenOutDF['SinValue']/SinGenOutDF['SinValue'].max()
SinGenOutDF['f[Hz]']=np.arange(-clkFreq/2.0,clkFreq/2.0,clkFreq/(len(SinValueTracker)))

FFT=np.fft.fftshift(np.fft.fft(SinGenOutDF['SinValueNorm']))
SinGenOutDF['FFTMag']=np.abs(FFT)
SinGenOutDF['FFTPhase']=np.angle(FFT)
SinGenOutDF.head(5)
```

      SinValue
      Time[s]
      SinValueNorm
      f[Hz]
      FFTMag
      FFTPhase

      0
      478355485
      0.000000e+00
      0.891007
      -5000000.0
      1.676381e-08
      -5.921190e-15

      1
      315564804
      1.000000e-07
      0.587785
      -4950000.0
      1.169079e-08
      8.481712e-02

      2
      83985113
      2.000000e-07
      0.156434
      -4900000.0
      1.374530e-08
      -2.588747e-02

      3
      -165902237
      3.000000e-07
      -0.309017
      -4850000.0
      1.256693e-08
      8.504632e-03

      4
      -379625064
      4.000000e-07
      -0.707107
      -4800000.0
      1.237123e-08
      3.107669e-01

```python
CosDF=pd.DataFrame(columns=['Time[s]'], data=np.arange(0.0,clkPeriod*(len(SinGenOutDF)-0.5),clkPeriod))
CosDF['Sin']=np.cos(2*np.pi*SinFreq*SinDF['Time[s]'])
CosDF['SinS']=CosDF['Sin']*SinGenOutDF['SinValue'].max()
CosDF['f[Hz]']=np.arange(-clkFreq/2.0,clkFreq/2.0,clkFreq/(len(SinValueTracker)))
FFT=np.fft.fftshift(np.fft.fft(CosDF['Sin']))
CosDF['FFTMag']=np.abs(FFT)
CosDF['FFTPhase']=np.angle(FFT)
CosDF.head(5)
```

      Time[s]
      Sin
      SinS
      f[Hz]
      FFTMag
      FFTPhase

      0
      0.000000e+00
      1.000000
      5.368709e+08
      -5000000.0
      4.768857e-15
      -3.141593

      1
      1.000000e-07
      0.891007
      4.783555e+08
      -4950000.0
      3.754675e-14
      -1.502735

      2
      2.000000e-07
      0.587785
      3.155648e+08
      -4900000.0
      3.920159e-14
      0.642098

      3
      3.000000e-07
      0.156434
      8.398512e+07
      -4850000.0
      4.962420e-14
      -0.653919

      4
      4.000000e-07
      -0.309017
      -1.659022e+08
      -4800000.0
      9.565805e-14
      1.207279

```python
fig, [ax0, ax1]=plt.subplots(nrows=2, ncols=1, sharex=False)
plt.suptitle(f'Plots of Sin Generator output in time for {N} Cycles')

SinGenOutDF.plot(use_index=True ,y='SinValue', ax=ax0)
CosDF.plot(use_index=True, y='SinS', ax=ax0)
ax0.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
ax0.legend(loc='best')

SinGenOutDF.plot(x='Time[s]', y='SinValueNorm', ax=ax1)
CosDF.plot(x='Time[s]', y='Sin', ax=ax1)
ax1.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
ax1.legend(loc='best')

None
```

```python
fig, [ax0, ax1]=plt.subplots(nrows=2, ncols=1, sharex=True)
plt.suptitle(f'Plots of Sin Generator output in freq for {N} Cycles')

SinGenOutDF.plot(x='f[Hz]' ,y='FFTMag', logy=True, ax=ax0, label='GenFFTMag')
SinDF.plot(x='f[Hz]' ,y='FFTMag', logy=True, ax=ax0, label='SinFFTMag')

ax0.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
ax0.set_ylabel('Amp [dB]')
ax0.legend(loc='best')

SinGenOutDF.plot(x='f[Hz]', y='FFTPhase', ax=ax1, label='GenFFTPhase')
SinDF.plot(x='f[Hz]', y='FFTPhase', ax=ax1, label='SinFFTPhase')
ax1.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
ax1.set_xlabel('f[Hz]'); ax1.set_ylabel('Phase [rad]')

ax1.legend(loc='best')

None
```

# Modification for Frequncy Control

```python
def SinGeneratorFMOD(SinFreq_parm, ClkFreq_parm, KONSTANT_FACTOR_in,  SinValue_out,
                clk, rst):
    #contorl byte size and works with -1 to translate cos to sin
    INTERNALWIDTH=len(SinValue_out)-2

    #qunitited version of the 2x for cos(\theta)
    KONSTANT_FACTOR=int(np.cos(2*np.pi * SinFreq_parm /ClkFreq_parm)* 2**(INTERNALWIDTH))

    #prep the Needed regesters at sysnthis
    Reg_T0=Signal(intbv((2**(INTERNALWIDTH))-1,
                        min=SinValue_out.min, max=SinValue_out.max))
    Reg_T1=Signal(intbv(KONSTANT_FACTOR,
                        min=SinValue_out.min, max=SinValue_out.max))

    #define the polynomal logic
    @always(clk.posedge,rst.negedge)
    def logicCP():
        #clear and prep the regesters
        if rst== 0 :
            Reg_T0.next=(2**(INTERNALWIDTH))-1
            Reg_T1.next=KONSTANT_FACTOR

        #run a single recursion iterration of the polynomal
        else:
            # recursive Chebyshev  formulation for sinus waveform calculation
            Reg_T0.next=Reg_T1
            #>> shift is a overflow wrapper
            Reg_T1.next=((KONSTANT_FACTOR_in * Reg_T1)>>(INTERNALWIDTH-1)) - Reg_T0

    #pole the R1 for the value of the sin function
    @always_comb
    def comb_logic():
        SinValue_out.next=Reg_T1

    return instances()
```

```python
SinFreq=0.75e6   # make a 1.45 mhz Sinus
clkFreq=10e6   # 10 mhz
clkPeriod=1.0/clkFreq

OUTPUT_BITWIDTH=30

Peeker.clear()

SinValue_out=Signal(intbv(0, min=-2**OUTPUT_BITWIDTH, max=2**OUTPUT_BITWIDTH))
New_KONSTANT_FACTOR_in=lambda SinFreq: int(np.cos(2*np.pi * SinFreq /clkFreq)* 2**(len(SinValue_out)-2 ))

KONSTANT_FACTOR_in=Signal(intbv(New_KONSTANT_FACTOR_in(SinFreq), min=-2**OUTPUT_BITWIDTH, max=2**OUTPUT_BITWIDTH))

Peeker(SinValue_out, 'SinVal')
SinValueTracker=[]

clk=Signal(bool(0)); Peeker(clk, 'clk')
rst=Signal(bool(0)); Peeker(rst, 'rst')

DUT=SinGeneratorFMOD(SinFreq_parm=SinFreq, ClkFreq_parm=clkFreq, KONSTANT_FACTOR_in=KONSTANT_FACTOR_in,  SinValue_out=SinValue_out,
                clk=clk, rst=rst)

def SinGeneratorFMOD_TB(TestClkCyc=200):

    #clock genrator
    @always(delay(int(clkPeriod*0.5*1e9)))  ## delay in nano seconds
    def clkGen():
        clk.next = not clk

    # accterla test procdure
    @instance
    def stimulus():
        while 1:
            rst.next=0
            #wait one clock cycle
            yield clk.posedge

            #test reset
            rst.next=1

            #wait one clock cycle
            yield clk.posedge

            #run the sin wave genrator
            #run the test for 200 clock cycles
            for i in range(TestClkCyc//2):
                #wait for next clock cycle
                yield clk.posedge
                SinValueTracker.append(int(SinValue_out))

            KONSTANT_FACTOR_in.next=New_KONSTANT_FACTOR_in(2*SinFreq)
            for i in range(TestClkCyc//2):
                yield clk.posedge
                SinValueTracker.append(int(SinValue_out))
            raise StopSimulation

    return instances()
```

```python
N=400
sim = Simulation(DUT, SinGeneratorFMOD_TB(TestClkCyc=N), *Peeker.instances()).run()
#Peeker.to_wavedrom(start_time=0, stop_time=20, tock=True)
```

## Post Processing of FMOD Test Bench

```python
SinGenOutDF=pd.DataFrame(columns=['SinValue'], data=SinValueTracker)
SinGenOutDF['Time[s]']=np.arange(0.0,clkPeriod*(len(SinGenOutDF)-0.5),clkPeriod)
SinGenOutDF['SinValueNorm']=SinGenOutDF['SinValue']/SinGenOutDF['SinValue'].max()
SinGenOutDF['f[Hz]']=np.arange(-clkFreq/2.0,clkFreq/2.0,clkFreq/(len(SinValueTracker)))

FFT=np.fft.fftshift(np.fft.fft(SinGenOutDF['SinValueNorm']))
SinGenOutDF['FFTMag']=np.abs(FFT)
SinGenOutDF['FFTPhase']=np.angle(FFT)
#SinGenOutDF
```

```python
fig, [ax0, ax1]=plt.subplots(nrows=2, ncols=1, sharex=False)
plt.suptitle(f'Plots of Sin FMOD Generator output in time for {N} Cycles')

SinGenOutDF.plot(use_index=True ,y='SinValue', ax=ax0)
ax0.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
ax0.legend(loc='best')

SinGenOutDF.plot(x='Time[s]', y='SinValueNorm', ax=ax1)
ax1.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
ax1.legend(loc='best')

None
```

```python
fig, [ax0, ax1]=plt.subplots(nrows=2, ncols=1, sharex=True)
plt.suptitle(f'Plots of Sin FMOD Generator output in freq for {N} Cycles')

SinGenOutDF.plot(x='f[Hz]' ,y='FFTMag', logy=True, ax=ax0, label='GenFFTMag')

ax0.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
ax0.set_ylabel('Amp [dB]')
ax0.legend(loc='best')

SinGenOutDF.plot(x='f[Hz]', y='FFTPhase', ax=ax1, label='GenFFTPhase')
ax1.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
ax1.set_xlabel('f[Hz]'); ax1.set_ylabel('Phase [rad]')

ax1.legend(loc='best')

None
```

# RTL Synthisis

```python
SinFreq=0.75e6   # make a 1.45 mhz Sinus
clkFreq=10e6   # 10 mhz
clkPeriod=1.0/clkFreq

OUTPUT_BITWIDTH=30

Peeker.clear()

SinValue_out=Signal(intbv(0, min=-2**OUTPUT_BITWIDTH, max=2**OUTPUT_BITWIDTH))
KONSTANT_FACTOR_in=Signal(intbv(New_KONSTANT_FACTOR_in(SinFreq), min=-2**OUTPUT_BITWIDTH, max=2**OUTPUT_BITWIDTH))

clk=Signal(bool(0))
ena=Signal(bool(0))
rst=Signal(bool(0))

#toVerilog(SinGenerator, SinFreq, clkFreq, SinValue_out, clk, rst, ena)
toVerilog(SinGeneratorFMOD, SinFreq, clkFreq, KONSTANT_FACTOR_in, SinValue_out, clk, rst)

```

    [<myhdl._always_comb._AlwaysComb at 0x196cbcac2b0>,
     <myhdl._always._Always at 0x196cbcac4a8>]

```python
def VerilogTextReader(loc, printresult=True):
    with open(f'{loc}.v', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***Verilog modual from {loc}.v***\n\n', VerilogText)
    return VerilogText

def VHDLTextReader(loc, printresult=True):
    with open(f'{loc}.vhd', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***VHDL modual from {loc}.vhd***\n\n', VerilogText)
    return VerilogText
```

```python
_=VerilogTextReader('SinGeneratorFMOD', True)
```

    ***Verilog modual from SinGeneratorFMOD.v***

     // File: SinGeneratorFMOD.v
    // Generated by MyHDL 0.9.0
    // Date: Sat Oct  7 16:52:25 2017

    `timescale 1ns/10ps

    module SinGeneratorFMOD (
        KONSTANT_FACTOR_in,
        SinValue_out,
        clk,
        rst
    );

    input signed [30:0] KONSTANT_FACTOR_in;
    output signed [30:0] SinValue_out;
    wire signed [30:0] SinValue_out;
    input clk;
    input rst;

    reg signed [30:0] Reg_T1;
    reg signed [30:0] Reg_T0;

    assign SinValue_out = Reg_T1;

    always @(posedge clk, negedge rst) begin: SINGENERATORFMOD_LOGICCP
        if ((rst == 0)) begin
            Reg_T0 <= ((2 ** 29) - 1);
            Reg_T1 <= 478355485;
        end
        else begin
            Reg_T0 <= Reg_T1;
            Reg_T1 <= ($signed((KONSTANT_FACTOR_in * Reg_T1) >>> (29 - 1)) - Reg_T0);
        end
    end

    endmodule

The RTL Schematic from the verilog myHDL synthesis via vavado 2016.1 of the Sine Generator (NON FM) is shown below

The RTL Synthesis shows 65 cells, 34 I/O ports 161 Nets, 2 Register Sets, and 3 RTL Operations (multiply, right shift, subtraction). Where the last two statistics are exactly as predected from the myHDL (python) function **SinGenerator**

# Refrances

https://en.wikibooks.org/wiki/Trigonometry/For_Enthusiasts/Chebyshev_Polynomials

https://www.geophysik.uni-muenchen.de/~igel/Lectures/NMG/05_orthogonalfunctions.pdf

# Pulse Density Modulation
via https://www.koheron.com/blog/2016/09/27/pulse-density-modulation

```python
def pdm(x):
    n = len(x)
    y = np.zeros(n)
    error = np.zeros(n+1)
    for i in range(n):
        y[i] = 1 if x[i] >= error[i] else 0
        error[i+1] = y[i] - x[i] + error[i]
    return y, error[0:n]
```

```python
y, error=pdm(SinGenOutDF['SinValue'])
t=SinGenOutDF['Time[s]']
```

```python
fig, [ax1, ax2, ax3]=plt.subplots(nrows=3, ncols=1, sharex=True)
ax1.plot(t, SinGenOutDF['SinValue'], label='input signal')
ax1.legend(loc='best')
ax2.step(t, y, label='pdm signal',  linewidth=2.0)
ax2.legend(loc='best')

ax3.step(t, error, label='error')
ax3.legend(loc='best')

ax3.set_xlabel('Time (ns)')
None
```

## Kheron's Verilog code for PDM (not MyHDL)

// Pulse density Modulator verilog
`timescale 1 ns / 1 ps

module pdm #(parameter NBITS = 10)
(
  input wire                      clk,
  input wire [NBITS-1:0]          din,
  input wire                      rst,
  output reg                      dout,
  output reg [NBITS-1:0]          error
);

  localparam integer MAX = 2**NBITS - 1;
  reg [NBITS-1:0] din_reg;
  reg [NBITS-1:0] error_0;
  reg [NBITS-1:0] error_1;

  always @(posedge clk) begin
    din_reg <= din;
    error_1 <= error + MAX - din_reg;
    error_0 <= error - din_reg;
  end

  always @(posedge clk) begin
    if (rst == 1'b1) begin
      dout <= 0;
      error <= 0;
    end
    else if (din_reg >= error) begin
      dout <= 1;
      error <= error_1;
    end else begin
      dout <= 0;
      error <= error_0;
    end
  end

endmodule

## RTL of PDM
taken from https://www.koheron.com/blog/2016/09/27/pulse-density-modulation (I am haveing all sorts of computer issues)

# Base Overlay Modification (DID GET NOT WORKING)

# Controling Sin Freq and Watch PDM Error(DID NOT GET WORKING)

```python
#from pynq.overlays.mybase import MyBaseOverlay
import ipywidgets as widgets
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
clkFreq=10e6   # 10 mhz
BaseFreq=0.75e6   # make a 1.45 mhz Sinus

class Sin_mit_FM():#MyBaseOverlay):
    def __init__(self, bitfile_name, clkFreq=10e6, BaseFreq=0.75e6, Bitwidth=30, Test=True):
        #super().__init__(bitfile_name)

        self.clkFreq=clkFreq
        self.BaseFreq=BaseFreq
        self.Bitwidth=Bitwidth

        self.Test=Test

        self.New_KONSTANT_FACTOR_in(scale=1)

        self.PDMError=0

    def New_KONSTANT_FACTOR_in(self, scale):
        self.scale=scale
        self.Kvalue=int(np.cos(2*np.pi * self.BaseFreq* scale /self.clkFreq)* 2**(self.Bitwidth-2 ))
        if not self.Test:
            self.SendReadUpdateToPYNQ()

    def PlotCosTheory(self, scale):
        self.New_KONSTANT_FACTOR_in(scale)
        if not self.Test:
            self.SendReadUpdateToPYNQ()

        timespace=np.linspace(0, 1/self.BaseFreq, 100)
        plt.title('CosTheory')
        plt.plot(timespace, np.cos(2*np.pi*self.scale*self.BaseFreq*timespace),
                label=f'PDM Out Error is {self.PDMError}')
        plt.ticklabel_format(axis='x', style='sci', scilimits=(-2,2))
        plt.xlabel('time'); plt.ylabel('Amp')
        plt.legend(loc='best')

    def SendReadUpdateToPYNQ(self):
        #Could Not Get Working
        #self.mmioSinGen.write(0, self.Kvalue|0x80000000)
        #self.PDMError=self.mmioPDMError.read(0)
        pass

```

## What the overlay was supposed to do
The frequency would be scaled from the base frequency effectively creating a user controlled frequency modulator. So that the plot would show the ideal output for the current frequency scaling before the PDM and speaker output, where the PDM error is read in from the PDM module in the FPGA for reference of the sudo DAC error. Where then the speaker output is picked up by the onboard  microphone  that is processed by in High level PYNQ Python interaction.

```python
Test=Sin_mit_FM('mybase.bit', Test=True)
widgets.interact_manual (Test.PlotCosTheory, scale=(0.1, 2.0, 0.1))
None
```

    A Jupyter Widget

```python

```