\title{myHDL Sawtooth Wave Generator based on the Phase Accumulation method} \author{Steven K Armour} \maketitle
This is a simple SawTooth wave generator based on the phase accumulation method inspired by George Pantazopoulos implementation SawWaveGen in http://old.myhdl.org/doku.php/projects:dsx1000
In [1]:
from myhdl import *
import pandas as pd
from myhdlpeek import Peeker
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sympy import *
init_printing()
In [2]:
#helper functions to read in the .v and .vhd generated files into 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
In [ ]:
BitWidth=16
#the max in excluded in intbv
MaxV=int(2**(BitWidth-1)); MinV=-int(2**(BitWidth-1))
a=intbv(0)[BitWidth:]; a=a.signed()
len(a), a.min, MinV, a.max, MaxV
In [5]:
t, T=symbols('t, T', real=True)
y=Function('y')(t)
In [6]:
yEq=Eq(y, (t/T)-floor(t/T)); yEq
Out[6]:
In [7]:
ft, fc, W=symbols('f_t, f_c, W')
PhaseMax=(ft*2**W)//fc; PhaseMax
Out[7]:
In [8]:
Targets={ft:440, W:BitWidth}; Targets[fc]=100e3
Targets
Out[8]:
In [9]:
PM=PhaseMax.subs(Targets)
f'PhaseMax={PM}'
Out[9]:
In [10]:
yN=lambdify((t, T), yEq.rhs, dummify=False)
TN=1/100e3; TN
tN=np.linspace(0, .1, PM//4)
In [11]:
fig, axBot=plt.subplots(ncols=1, nrows=1)
axTop=axBot.twiny()
axBot.plot(tN, yN(tN, TN))
axBot.set_xlabel('Time [s]')
axTop.plot(yN(tN, TN))
axTop.set_xlabel('n');
In [12]:
@block
def SawToothGen(y, clk, rst, Freq, ClkFreq):
"""
Inputs:
clk (bool): system clock
rst (bool): reset signal
Ouputs:
y(2's): SawWave Ouput
Parmeters:
Freq(float): Target Freq
ClkFreq(float): System Clock Freq
"""
#Registor to store the phase; aka a counter
Phase=Signal(intbv(0)[BitWidth:])
# Make phase (Counter) limit
PhaseCeil=int((Freq*2**BitWidth)//ClkFreq)
@always(clk.posedge)
def logic():
if rst:
Phase.next=0
y.next=0
else:
if Phase==PhaseCeil-1:
y.next=0
Phase.next=0
else:
y.next=y+1
Phase.next=Phase+1
return instances()
In [13]:
Peeker.clear()
y=Signal(intbv(0)[BitWidth:]); Peeker(y, 'y')
#Phase=Signal(modbv(0, max=5)); Peeker(Phase, 'P')
clk, rst=[Signal(bool(0)) for _ in range(2)]
Peeker(clk, 'clk'); Peeker(rst, 'rst')
DUT=SawToothGen(y, clk, rst, 440, 100e3)
def SawToothGen_TB():
@always(delay(1)) ## delay in nano seconds
def clkGen():
clk.next = not clk
@instance
def Stimules():
for i in range(8*PM):
yield clk.posedge
for i in range(4):
if i <2:
rst.next=True
else:
rst.next=False
yield clk.posedge
raise StopSimulation
return instances()
sim=Simulation(DUT, SawToothGen_TB(), *Peeker.instances()).run()
#Peeker.to_wavedrom()
In [14]:
Simdata=Peeker.to_dataframe()
Simdata=Simdata[Simdata.clk!=0]
Simdata.reset_index(drop=True, inplace=True)
Simdata
Out[14]:
In [15]:
Simdata.plot(y='y')
Out[15]:
In [16]:
y=Simdata[Simdata.rst!=1]['y']
fy=np.fft.fftshift(np.fft.fft(y, len(y)))
fs=np.fft.fftfreq(len(y))
n=np.where(fs>=0)
plt.plot(fs[n], np.abs(fy[n]))
plt.twinx()
plt.plot(fs[n], np.angle(fy[n], deg=True), color='g', alpha=.3)
Out[16]:
In [17]:
f=fs.max()*100e3; f
Out[17]:
In [18]:
DUT.convert()
VerilogTextReader('SawTooth');
In [ ]: