Polyphonyって何だろう(6)使用例:FIRフィルター
Python で書いた関数を Verilog HDL に変換する高位合成コンパイラである Polyphony を使ってみたいと思います。固定小数点の掛け算もできるようになったので、FIRフィルターを記述して、pythonなので、グラフ表示で機能確認をしてみたいと思います。
FIRフィルターの係数
FIRフィルターの係数は
Parks-McClellan法の設計仕様(BPF,BEF)
このサイトを利用させてもらいました。
設計仕様を入力して右下の[設計する]をクリックすると
次の様に、係数と特性が表示されます。
この係数をコピーして使わせていただきました。
FIRローパスフィルターコード (FIRfilter.py) と簡単な説明
係数は32bit固定小数点として扱う事にします。19 タップとしているので、32x19=608bit 必要となります。
Polyphonyの標準設定として 512bit を超えると RAM を使用するような設定になっていて、読み出しに delay が入るようになっているので、それを回避するために env.py を修正します。
internal_ram_threashold_size = 1024
入力と係数の固定小数点掛け算には、前回作成した fix32.py から fix32_mul を import して使用します。
FIR係数の浮動小数点変数を32bit固定小数点に直すための関数 x_fix32 も fix32.py から import して使用したいところですが、@pure が無視されてしまうようで、polyphony コンパイル時にエラーが出てしまいます。そのため、コピーして使用することにしました。
python デバッグ時に、出力結果の 32bit固定小数点を通常の浮動小数点に戻す為の関数 fix32_x もコピーして使用します。
シミュレーション用の入力データは、2つのサイン波を足し合わせて、ベース周波数にノイズが乗っている波形を作成しています。その波形から、FIRローパスフィルターでノイズを除去する事を想定しています。
# -*- coding: utf-8 -*- # FIRfilter.py import math import polyphony from polyphony import pure, unroll, pipelined from polyphony import testbench from polyphony.typing import bit32,List from fix32 import fix32_mul TAPS = 19 FPPBIT = 23 TESTSIZE = 200 @pure def x_fix32(x,fn): y = int(x * (2**fn)) & 0xFFFFFFFF # print(x,':',format(y,'032b')) return(y) @pure def fix32_x(x,fn): x = x & 0xFFFFFFFF s = x >> 31 y = x & 0x7FFFFFFF if s != 0: y = -((2**32) - x) r = y / (2**fn) # print(format(x,'032b'),':',r) return(r) @pure def calcoeff(fp): coeff = [0] * TAPS coeff[0] =6.612020219528149e-04 coeff[1] =1.831283662723811e-14 coeff[2] =-5.277493642752464e-03 coeff[3] =2.734654608024070e-15 coeff[4] =2.263745261146082e-02 coeff[5] =-3.303789990121387e-14 coeff[6] =-7.405318429979151e-02 coeff[7] =6.039613253960852e-14 coeff[8] =3.060336228515318e-01 coeff[9] =4.999999999999285e-01 coeff[10] =3.060336228515318e-01 coeff[11] =6.039613253960852e-14 coeff[12] =-7.405318429979151e-02 coeff[13] =-3.303789990121387e-14 coeff[14] =2.263745261146082e-02 coeff[15] =2.734654608024070e-15 coeff[16] =-5.277493642752464e-03 coeff[17] =1.831283662723811e-14 coeff[18] =6.612020219528149e-04 for i in range(19): coeff[i] = x_fix32(coeff[i], fp) # print(fix32_x(coeff[i], fp)) return(coeff) @pure def caltestdata(fp): testdata = [0] * TESTSIZE for i in range(TESTSIZE): x = 7 * math.sin(0.01*3.14*i)+2*math.sin(0.8*3.14*i) testdata[i] = x_fix32(x, fp) # print(testdata) return(testdata) COEFF = calcoeff(FPPBIT) TESTDATA = caltestdata(FPPBIT) def FIRfilter(input:bit32, coeff:List, previous:List)->bit32: for j in unroll(range(TAPS-1)): jj = TAPS-1 -j previous[jj] = previous[jj-1] previous[0] = input temp:bit32 = 0 for j in pipelined(range(TAPS)): temp += fix32_mul(previous[TAPS-1-j], coeff[j], FPPBIT) return(temp) @testbench def FIRfilter_test(): previous = [0] * TAPS # data = [] #python # result = [] #python for i in range(TESTSIZE): r = FIRfilter(TESTDATA[i], COEFF, previous) & 0xFFFFFFFF print(r) # print(format(TESTDATA[i],'10d'),':',format(r,'10d')) #python # print(fix32_x(TESTDATA[i],FPPBIT),fix32_x(r,FPPBIT)) #python # print(format(TESTDATA[i],'032b'),':',format(r,'032b')) #python # data.append(fix32_x(TESTDATA[i],FPPBIT)) #python # result.append(fix32_x(r,FPPBIT)) #python # import matplotlib.pyplot as plt #python # plt.plot(data) #python # plt.plot(result) #python if __name__ == '__main__': FIRfilter_test()
実行結果
#python と書かれた行をアンコメントしてからpythonで実行すると、テストデータとFIRフィルターによって処理されたデータのグラフが表示され、FIRフィルターの効果が確認できます。
4276652763 4286795431 : 4276652763 -0.974162220954895 -2.1832624673843384 11111111100000110100111010100111 : 11111110111010001000101011011011
polyphony でコンパイルする時には #python が付いた行をコメントアウトする必要があります。
こんな風に何かマークを付けた行をコンパイル時に読み飛ばしてくれる機能がpolyphonyにあると 非常に便利なのですが、今後に期待したいところです。
testbench の print(r) はシミュレーション時に必要なので、コメントアウトしないようにします。これが無いと、シミュレーション結果が保存されません。
polyphony でのコンパイルから 、シミュレーション、gtkwave での結果表示までは、
https://feynman.hatenablog.com/entry/2018/12/22/115738#簡単実行ユーティリティー
を使用してください。
Verilogシミュレーション結果の .vcd ファイルを読み込んで、pythonシミュレーションと比較するようなスクリプトを書けば、python から Verilog への変換がうまくいているかどうかをもっと確実に確認できると思います。
実行環境:Win10 python3.7.1 polyphony0.3.4 iverilog0.9.7