2012-03-23 11:41:30 -04:00
|
|
|
# Copyright (C) 2012 Vermeer Manufacturing Co.
|
|
|
|
# License: GPLv3 with additional permissions (see README).
|
|
|
|
|
2012-03-08 14:49:36 -05:00
|
|
|
from math import cos, pi
|
2012-03-10 13:38:39 -05:00
|
|
|
from scipy import signal
|
2012-06-07 17:20:59 -04:00
|
|
|
import matplotlib.pyplot as plt
|
2012-03-08 14:49:36 -05:00
|
|
|
|
|
|
|
from migen.fhdl.structure import *
|
|
|
|
from migen.fhdl import verilog
|
|
|
|
from migen.corelogic.misc import optree
|
|
|
|
from migen.fhdl import autofragment
|
2012-06-12 11:08:56 -04:00
|
|
|
from migen.sim.generic import Simulator, PureSimulable
|
2012-03-08 14:49:36 -05:00
|
|
|
from migen.sim.icarus import Runner
|
|
|
|
|
2012-03-10 13:38:39 -05:00
|
|
|
# A synthesizable FIR filter.
|
2012-03-08 14:49:36 -05:00
|
|
|
class FIR:
|
|
|
|
def __init__(self, coef, wsize=16):
|
|
|
|
self.coef = coef
|
|
|
|
self.wsize = wsize
|
|
|
|
self.i = Signal(BV(self.wsize, True))
|
|
|
|
self.o = Signal(BV(self.wsize, True))
|
|
|
|
|
|
|
|
def get_fragment(self):
|
|
|
|
muls = []
|
|
|
|
sync = []
|
|
|
|
src = self.i
|
|
|
|
for c in self.coef:
|
|
|
|
sreg = Signal(BV(self.wsize, True))
|
|
|
|
sync.append(sreg.eq(src))
|
|
|
|
src = sreg
|
|
|
|
c_fp = int(c*2**(self.wsize - 1))
|
|
|
|
c_e = Constant(c_fp, BV(bits_for(c_fp), True))
|
|
|
|
muls.append(c_e*sreg)
|
|
|
|
sum_full = Signal(BV(2*self.wsize-1, True))
|
|
|
|
sync.append(sum_full.eq(optree("+", muls)))
|
|
|
|
comb = [self.o.eq(sum_full[self.wsize-1:])]
|
|
|
|
return Fragment(comb, sync)
|
|
|
|
|
2012-03-10 13:38:39 -05:00
|
|
|
# A test bench for our FIR filter.
|
|
|
|
# Generates a sine wave at the input and records the output.
|
2012-06-12 11:08:56 -04:00
|
|
|
class TB(PureSimulable):
|
2012-03-08 14:49:36 -05:00
|
|
|
def __init__(self, fir, frequency):
|
|
|
|
self.fir = fir
|
|
|
|
self.frequency = frequency
|
|
|
|
self.inputs = []
|
|
|
|
self.outputs = []
|
|
|
|
|
|
|
|
def do_simulation(self, s):
|
|
|
|
f = 2**(self.fir.wsize - 1)
|
|
|
|
v = 0.1*cos(2*pi*self.frequency*s.cycle_counter)
|
|
|
|
s.wr(self.fir.i, int(f*v))
|
|
|
|
self.inputs.append(v)
|
|
|
|
self.outputs.append(s.rd(self.fir.o)/f)
|
|
|
|
|
|
|
|
def main():
|
2012-03-10 13:38:39 -05:00
|
|
|
# Compute filter coefficients with SciPy.
|
2012-03-08 14:49:36 -05:00
|
|
|
coef = signal.remez(80, [0, 0.1, 0.1, 0.5], [1, 0])
|
|
|
|
fir = FIR(coef)
|
2012-06-07 17:20:59 -04:00
|
|
|
|
|
|
|
# Simulate for different frequencies and concatenate
|
|
|
|
# the results.
|
|
|
|
in_signals = []
|
|
|
|
out_signals = []
|
|
|
|
for frequency in [0.05, 0.07, 0.1, 0.15, 0.2]:
|
|
|
|
tb = TB(fir, frequency)
|
|
|
|
fragment = autofragment.from_local()
|
|
|
|
sim = Simulator(fragment, Runner())
|
|
|
|
sim.run(100)
|
2012-08-04 18:16:11 -04:00
|
|
|
del sim
|
2012-06-07 17:20:59 -04:00
|
|
|
in_signals += tb.inputs
|
|
|
|
out_signals += tb.outputs
|
|
|
|
|
|
|
|
# Plot data from the input and output waveforms.
|
|
|
|
plt.plot(in_signals)
|
|
|
|
plt.plot(out_signals)
|
|
|
|
plt.show()
|
2012-06-08 08:00:49 -04:00
|
|
|
|
|
|
|
# Print the Verilog source for the filter.
|
|
|
|
print(verilog.convert(fir.get_fragment(),
|
|
|
|
ios={fir.i, fir.o}))
|
2012-03-08 14:49:36 -05:00
|
|
|
|
|
|
|
main()
|