Matlabでバターワースフィルターを設計し、オンラインVerilog HDLコードジェネレーターの整数としてフィルター[ab]係数を取得


15

Matlabを使用して、非常にシンプルなローパスバタワースフィルターを設計しました。次のコードスニペットは、私が行ったことを示しています。

fs = 2.1e6;
flow = 44 * 1000;
fNorm =  flow / (fs / 2);
[b,a] = butter(10, fNorm, 'low');

[b、a]にはフィルター係数が格納されます。オンラインHDLコードジェネレーターを使用してVerilogでコードを生成できるように、整数として[b、a]を取得したいと思います。

Matlab [b、a]の値はオンラインコードジェネレーターで使用するには小さすぎるようです(サーバー側のPerlスクリプトは係数を使用したコードの生成を拒否します)。[b、 a]適切な入力として使用できる形式。

Matlabで取得するa係数は次のとおりです。

1.0000
-9.1585
37.7780
-92.4225
148.5066
-163.7596
125.5009
-66.0030
22.7969
-4.6694
0.4307

Matlabで取得するb係数は次のとおりです。

1.0167e-012
1.0167e-011
4.5752e-011
1.2201e-010
2.1351e-010
2.5621e-010
2.1351e-010
1.2201e-010
4.5752e-011
1.0167e-011
1.0167e-012

オンラインジェネレーターを使用して、12ビットのビット幅とIまたはIIフィルター形式のフィルターを設計します。上記のリンクにある「フラクショナルビット」の意味がわかりません。

上記の[b、a]係数で、20に設定された小数ビットと12のビット幅でコードジェネレーター(http://www.spiral.net/hardware/filter.html)を実行すると、次の実行エラーが表示されます。 :

Integer A constants: 1048576 -9603383 39613104 -96912015 155720456 -171714386 131597231 -69209161 23904282 -4896220 451621
Integer B constants: 0 0 0 0 0 0 0 0 0 0 0

Error: constants wider than 26 bits are not allowed, offending constant = -69209161, effective bitwidth = 7 mantissa + 20 fractional = 27 total.

An error has occurred - please revise the input parameters. 

このエラーが発生しないようにデザインを変更するにはどうすればよいですか?

更新: Matlabを使用して6次バタワースフィルターを生成すると、次の係数が得られます。

のために:

1.0000
-5.4914
12.5848
-15.4051
10.6225
-3.9118
0.6010 

bの場合:

0.0064e-005
0.0382e-005
0.0954e-005
0.1272e-005
0.0954e-005
0.0382e-005
0.0064e-005

オンラインコードジェネレーター(http://www.spiral.net/hardware/filter.html)を実行すると、次のエラーが表示されます(小数ビットが8、ビット幅が20)。

./iirGen.pl -A 256  '-1405' '3221' '-3943' '2719' '-1001' '153' -B  '0' '0' '0' '0' '0' '0' '0' -moduleName acm_filter -fractionalBits 8 -bitWidth 20 -inData inData  -inReg   -outReg  -outData outData -clk clk -reset reset -reset_edge negedge -filterForm 1  -debug  -outFile ../outputs/filter_1330617505.v 2>&1 
At least 1 non-zero-valued constant is required.  Please check the inputs and try again.

おそらく、b係数が小さすぎるのでしょうか、それともコードジェネレーター(http://www.spiral.net/hardware/filter.html)が[b、a]を別の形式にしたいのでしょうか?

更新:

おそらく、[b、a]係数を小数ビットの数でスケーリングして、係数を整数として取得する必要があります。

a .* 2^12
b .* 2^12

ただし、b係数は非常に小さいと考えています。ここで何が間違っていますか?

おそらく、別のタイプのフィルター(またはフィルター設計法)の方が適しているでしょうか?誰か提案をしてもらえますか?

更新: 以下のコメントでJason RとChristopher Feltonが示唆したように、SOSフィルターの方が適しています。SOSフィルターを取得するためのMatlabコードをいくつか作成しました。

fs = 2.1e6;
flow = 44 * 1000;      
fNorm =  flow / (fs / 2);
[A,B,C,D] = butter(10, fNorm, 'low');
[sos,g] = ss2sos(A,B,C,D);

私が得るSOSマトリックスは次のとおりです。

1.0000    3.4724    3.1253    1.0000   -1.7551    0.7705
1.0000    2.5057    1.9919    1.0000   -1.7751    0.7906
1.0000    1.6873    1.0267    1.0000   -1.8143    0.8301
1.0000    1.2550    0.5137    1.0000   -1.8712    0.8875
1.0000    1.0795    0.3046    1.0000   -1.9428    0.9598

Verilogコード生成ツール(http://www.spiral.net/hardware/filter.html)を使用してこのSOSフィルターを実装することは可能ですか、それとも単にVerilogを手動で記述する必要がありますか?良い参考資料はありますか?

この状況でFIRフィルターを使用する方が良いのではないかと思います。

さらに:整数IIを使用して、係数を分数として表現することにより、再帰IIRフィルターを実装できます。(詳細については、スミスの優れたDSP信号処理の本を参照してください:http : //www.dspguide.com/ch19/5.htm

次のMatlabプログラムは、Matlab rat()関数を使用してバターワースフィルター係数を小数部に変換します。次に、コメントで述べたように、2次セクションを使用して数値的にフィルターを実装できます(http://en.wikipedia.org/wiki/Digital_biquad_filter)。

% variables
% variables
fs = 2.1e6;                     % sampling frequency           
flow = 44 * 1000;               % lowpass filter


% pre-calculations
fNorm =  flow / (fs / 2);       % normalized freq for lowpass filter

% uncomment this to look at the coefficients in fvtool
% compute [b,a] coefficients
% [b,a] = butter(7, fNorm, 'low');
% fvtool(b,a)  

% compute SOS coefficients (7th order filter)
[z,p,k] = butter(7, fNorm, 'low');

% NOTE that we might have to scale things to make sure
% that everything works out well (see zp2sos help for 'up' and 'inf' options)
sos = zp2sos(z,p,k, 'up', 'inf'); 
[n,d] = rat(sos); 
sos_check = n ./ d;  % this should be the same as SOS matrix

% by here, n is the numerator and d is the denominator coefficients
% as an example, write the the coefficients into a C code header file
% for prototyping the implementation

 % write the numerator and denominator matices into a file
[rownum, colnum] = size(n);  % d should be the same
sections = rownum;           % the number of sections is the same as the number of rows
fid = fopen('IIR_coeff.h', 'w');

fprintf(fid, '#ifndef IIR_COEFF_H\n');
fprintf(fid, '#define IIR_COEFF_H\n\n\n');
for i = 1:rownum
   for j = 1:colnum

       if(j <= 3)  % b coefficients
            bn = ['b' num2str(j-1) num2str(i) 'n' ' = ' num2str(n(i,j))];
            bd = ['b' num2str(j-1) num2str(i) 'd' ' = ' num2str(d(i,j))];
            fprintf(fid, 'const int32_t %s;\n', bn);
            fprintf(fid, 'const int32_t %s;\n', bd);

       end
       if(j >= 5)  % a coefficients
            if(j == 5) 
                colstr = '1'; 
            end
            if(j == 6) 
                colstr = '2'; 
            end
            an = ['a' colstr num2str(i) 'n' ' = ' num2str(n(i,j))];
            ad = ['a' colstr num2str(i) 'd' ' = ' num2str(d(i,j))];
            fprintf(fid, 'const int32_t %s;\n', an);
            fprintf(fid, 'const int32_t %s;\n', ad);
       end
   end
end

% write the end of the file
fprintf(fid, '\n\n\n#endif');
fclose(fid);

4
このような高次IIRフィルターは、通常2次セクションを使用して実装されます。複数の2次ステージをカスケードすることで、目的のフィルターを取得します(希望する順序が奇数の場合は1つの1次ステージを使用)。通常、高次フィルタを直接実装するよりも堅牢な実装です。
ジェイソンR

3
@JasonRが提案することをしないと、非常に大きな単語サイズになります。このようなフィルターは、基本的なIIR構造で実装された場合、単精度浮動小数点で失敗する可能性があります。SOSが必要です。
クリストファーフェルトン

@JasonR:これを提案してくれてありがとう。上記の回答で更新しました。
ニコラスキナー

@ChristopherFelton:これを強化するのを手伝ってくれてありがとう。
ニコラスキナー

はい、新しいSOSマトリックスを使用すると、サイトから3つのフィルターを作成できます。または、ここで私のコードを使用できます。ウェブサイトと同じように機能します。SOSマトリックスを除くスクリプトを喜んで更新します。
クリストファーフェルトン

回答:


5

説明したように、セクションの合計を使用することをお勧めします。つまり、高次フィルターをカスケード2次フィルターに分割します。更新された質問にはSOSマトリックスが含まれています。このコードを使用し、Pythonオブジェクトを使用して個々のセクションを生成できます。

MATLABで

save SOS

Pythonで

import shutil
import numpy
from scipy.io import loadmat
from siir import SIIR

matfile = loadmat('SOS.mat')  
SOS = matfile['SOS']
b = numpy.zeros((3,3))
a = numpy.zeros((3,3))
section = [None for ii in range(3)]
for ii in xrange(3):
    b[ii] = SOS[ii,0:3]
    a[ii] = SOS[ii,3:6]

    section[ii] = SIIR(b=b[ii], a=a[ii], W=(24,0))
    section[ii].Convert()  # Create the Verilog for the section
    shutil.copyfile('siir_hdl.v', 'iir_sos_section%d.v'%(ii))

固定小数点の詳細については、こちらをご覧ください


洞察に満ちたすべてのリンク、およびPythonコードをありがとう。あなたの答え(およびここに投稿された他の答え)が他の多くの人にとって良い参考になることを願っています。ここですべての回答を承認済みとしてマークできることを望みます。
ニコラスキナー

1
問題がある場合はお知らせください。うまくいかない場合はコードを更新/修正します。SOSマトリックスを直接受け入れるように変更します(比較的近いうちに、doh)。
クリストファーフェルトン

1
私はあなたの例から自分のバージョンを実装しようとしました。私のシステムでは、「numpy import zerosから」を使用して、loatmatをloadmat()に変更する必要がありました。Matlab(mathworks.com/help/toolbox/signal/ref/ss2sos.html)によって提供されるSOSマトリックスは、予想と同じ形式ですか?"[II]、B = SOS [0:3、II]"インタプリタがラインに到達したとき: "非ハッシュタイプはTypeError:"私はSOS行列にアクセスしようとすると、次のエラーを受け取り
ニコラスKinar

1
それはSOS.matファイルの形式に依存します。単純に>>> print(matfile)を実行すると、読み込まれた.matファイルのキーが表示されます。scipy.io.loadmatは常に辞書(BOMK)としてロードされます。
クリストファーフェルトン

1
はい、それは正しいです。0の出力は1への入力などです。単語の幅について少し考える必要があります。デフォルトでは、24ビットの小数を使用する2(整数0、整数23、符号1)です。もともとは小さい単語幅を使用したかったと思います。
クリストファーフェルトン

10

「端数ビット」は、数値の端数部分を表すために専用にしたバスのビット数です(3.75の0.75など)。

あなたが4ビット幅のデジタルバスを持っているとしたら、何の数字を1001表していますか?正の整数(2 ^ 3 + 2 ^ 0 = 8 + 1 = 9)として扱う場合、「9」を意味する場合があります。または、2の補数表記で-7を意味する場合があります:(-2 ^ 3 + 2 ^ 0 = -8 + 1 = -7)。

いくつかの小数を含む数字、つまり「実際の」数字についてはどうですか?実数は、ハードウェアでは「固定小数点」または「浮動小数点」として表すことができます。これらのフィルタージェネレーターは固定小数点を使用しているようです。

4ビットバス(1001)に戻ります。バイナリポイントを導入して、を取得し1.001ます。つまり、ポイントのRHSのビットを使用して整数を構築し、LHSのビットを使用して小数を構築していたということです。に設定されたデジタルバスによって表される数値1.001は1.125(1* 2 ^ 0 + 0* 2 ^ -1 + 0* 2 ^ -2 + 1* 2 ^ -3 = 1 + 0.125 = 1.125)です。この場合、バス内の4ビットのうち3ビットを使用して、数値の小数部分を表します。または、3つの小数ビットがあります。

したがって、上記のような実数のリストがある場合は、それらを表す小数ビットの数を決定する必要があります。トレードオフは次のとおりです。小数ビットを使用するほど、必要な数をより正確に表現できますが、回路を大きくする必要があります。さらに、使用する小数ビットが少ないほど、フィルターの実際の周波数応答は、最初に設計したものからさらに逸脱します!

さらに悪いことに、無限インパルス応答(IIR)フィルターの構築を検討しています。十分な小数および整数ビットがない場合、これらは実際に不安定になる可能性があります!


この洞察に富んだ答えを提供してくれてありがとう。上記の小さなb係数を使用してコードジェネレーターを実行しようとしましたが、まだエラーが発生します。ジェネレーターを適切に実行するためにできることを提案してもらえますか?上記の回答を更新して、自分が行ったことを示します。

10

だからマーティはビットの質問をよく世話してくれました。フィルター自体については、スケーリングが不十分な係数について、matlabから警告または苦情を受け取る可能性が高いと思いますか?matcipではなくscipyからフィルターをプロットすると、非常によく似ています。

応答

通過帯域で100 dB低下しています!そのため、より小さな次数のフィルターが必要であることを確認したい場合があります。これはとにかく実装に役立ちます。6次のフィルターに到達すると、悪い係数に関する苦情がなくなります。注文を減らして、まだ要件を満たしているかどうかを確認してください。


これを提案してくれてありがとう!6次フィルターも同様に機能すると思います。matlabのfvtoolを使用すると、応答がアプリケーションに適していると思います。上記の回答を更新しました。ただし、Verilog HDLコードジェネレーター(spiral.net/hardware/filter.html)にはまだ問題があります。おそらく、別の形式の[b、a]が必要です。さらに、SciPyを使用する場合は+1。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.