デジタルIIRフィルターのVerilog実装

Habrを歓迎します。 少し前まで、このトピックに関する記事Verilogはすでにここに掲載されています RAM上 のデジタルフィルターと有限インパルス応答を持つデジタルフィルターの構築 。 ささやかな貢献をして、VerilogでのデジタルIIRフィルターの実装を紹介したいと思います。



このトピックに関係する人々は以下のすべてを知っているという事実にもかかわらず、私は、初心者のために、まだ広範囲の読者にほとんど理論を与えたくない。

IIRフィルター (IIRフィルター)-無限インパルス応答(無限インパルス応答)を持つフィルター。 FIRフィルター (有限インパルス応答を持つフィルター )のこのタイプのフィルターの特徴は、フィルター出力の値が入力データだけでなく、以前の反復でフィルターが受信した出力データにも依存する場合のフィードバックの存在です。 IIRフィルターの構造は、次のように表すことができます。



IIRフィルター構造

アナログフィルターの係数を計算する方法については説明しません。このトピックは、アナログフィルターやデジタルフィルターなど、多数の出版物に記載されています。 G. Lemまたはフィルターの合成の 計算と実装 Herrero J. Willoner G.これを行うプログラムも多数あります。 アナログフィルターをデジタルに変換するプロセスのみを簡単に説明します。

任意のフィルターは、アナログ伝達関数を使用して表すことができます。 たとえば、2次IIRフィルターの場合、次のようになります。

アナログ伝達関数

正規化された複素変数をこの式に代入する

正規化された複素変数

伝達関数A(z)を取得します。これはデジタルフィルターに実装できます。

デジタル伝達関数

2次フィルターの係数は、次の式によって決定されます。



どこで

-クロック周波数

-フィルターカットオフ周波数

d 0 ... 2および0 ... 2がアナログフィルターの係数であり、事前に計算されていることが前提となります。

これらの簡単な計算を使用して、アナログフィルターの対応する係数を知ることで、任意の次数のフィルターのデジタル伝達関数の係数を計算できます。 (しかし、私はかつて4次まで十分であり、そのために困難はありません。多くの長い式を書いて、単純な乗算の式で単純化します。しかし、私は遠い学年を思い出しました)。 たとえば、調整可能な特性を持つフィルターを実装するタスクに直面したため、すべての係数はPCで計算され、32ビット数の形式でFPGAに転送され、その後浮動小数点形式に変換されました。

したがって、デジタル伝達関数の係数を使用して、IIRフィルターの差分方程式にそれらを代入します。

IIRフィルター差分方程式

これに基づいて、Verilogで実装を記述することはもはや難しくありません。



モジュールテキスト
 module LP_FILTER ( mhz_clk,RESET, D0,D1,D2,C0,C1, X,Y, COUNT ); // low pass filter INPUT32 OUTPUT32 /* y(i) = D2 * x(i) + D1 * x(i-1) + D0 * x(i-2) + C1 * y(i-1) + C0 * y(i-2) A(z) = (D0+D1*z+D2*z*z)/(C0+C1*z+z*z) <==> A(P) = (d0+d1*P+d2*P*P)/(c0+c1*P+c2*P*P) A(P) = 1/(1+1.4*P+P*P) LPF D0 = ( d0 - d1*l + d2*l*l)/(c0 + c1*l + c2*l*l) D1 = (2*d0 - 2*d2*l*l)/(c0 + c1*l + c2*l*l) D2 = ( d0 + d1*l + d2*l*l)/(c0 + c1*l + c2*l*l) C0 = -( c0 - c1*l + c2*l*l)/(c0 + c1*l + c2*l*l) C1 = -(2*c0 - 2*c2*l*l)/(c0 + c1*l + c2*l*l) l = ctg ( 3.14 * f_filt / f_samp ) */ input mhz_clk; input RESET; input [17:0] X; input [31:0] D0; input [31:0] D1; input [31:0] D2; input [31:0] C0; input [31:0] C1; output [17:0] Y; output [5:0] COUNT; // adc-filter counter reg [5:0] COUNT; always @( posedge mhz_clk,negedge RESET ) if (~RESET) COUNT[5:0] = 0; //49 count else if (COUNT[5:0] == 6'h31) COUNT[5:0] = 0; else COUNT[5:0] = COUNT[5:0] + 6'b1; // input - COUNT[4:0] = 24:49 // output - COUNT[4:0] = 6 reg [31:0] c0_y2; reg [31:0] c1_y1; reg [31:0] d0_x2; reg [31:0] d1_x1; reg [31:0] d2_x0; reg [31:0] y0; reg [31:0] y1; reg [31:0] y2; reg [31:0] x0; reg [31:0] x1; reg [31:0] x2; // y(i) = D2 * x(i) + D1 * x(i-1) + D0 * x(i-2) + C1 * y(i-1) + C0 * y(i-2) reg [31:0] mul_a; reg [31:0] mul_b; always @(*) if ( ( COUNT[5:0] >= 0 ) & ( COUNT[5:0] <= 4 ) | ( COUNT[5:0] == 49 ) ) mul_a[31:0] = x0[31:0]; else if ( ( COUNT[5:0] >= 5 ) & ( COUNT[5:0] <= 10 ) ) mul_a[31:0] = x1[31:0]; else if ( ( COUNT[5:0] >= 11 ) & ( COUNT[5:0] <= 16 ) ) mul_a[31:0] = x2[31:0]; else if ( ( COUNT[5:0] >= 17 ) & ( COUNT[5:0] <= 22 ) ) mul_a[31:0] = y1[31:0]; else mul_a[31:0] = y2[31:0]; always @(*) if ( ( COUNT[5:0] >= 0 ) & ( COUNT[5:0] <= 4 ) | ( COUNT[5:0] == 49 ) ) mul_b[31:0] = D2[31:0]; else if ( ( COUNT[5:0] >= 5 ) & ( COUNT[5:0] <= 10 ) ) mul_b[31:0] = D1[31:0]; else if ( ( COUNT[5:0] >= 11 ) & ( COUNT[5:0] <= 16 ) ) mul_b[31:0] = D0[31:0]; else if ( ( COUNT[5:0] >= 17 ) & ( COUNT[5:0] <= 22 ) ) mul_b[31:0] = C1[31:0]; else mul_b[31:0] = C0[31:0]; wire [31:0] mul_out; mul_float32 ( 1, mhz_clk, mul_a[31:0], mul_b[31:0], mul_out[31:0] ); reg [31:0] outmul; always @(*) outmul[31:0]=mul_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) d2_x0[31:0] = 32'h0; else if ( COUNT[5:0] == 4 ) d2_x0[31:0] = mul_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) d1_x1[31:0] = 32'h0; else if ( COUNT[5:0] == 10 ) d1_x1[31:0] = mul_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) d0_x2[31:0] = 32'h0; else if ( COUNT[5:0] == 16 ) d0_x2[31:0] = mul_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) c1_y1[31:0] = 32'h0; else if ( COUNT[5:0] == 22 ) c1_y1[31:0] = mul_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) c0_y2[31:0] = 32'h0; else if ( COUNT[5:0] == 28 ) c0_y2[31:0] = mul_out[31:0]; // y(i) = D2 * x(i) + D1 * x(i-1) + D0 * x(i-2) + C1 * y(i-1) + C0 * y(i-2) reg [31:0] sum_a; reg [31:0] sum_b; always @(*) if ( ( COUNT[5:0] >= 0 ) & ( COUNT[5:0] <= 18 ) | ( COUNT[5:0] == 49 ) ) sum_a[31:0] = d2_x0[31:0]; else if ( ( COUNT[5:0] >= 19 ) & ( COUNT[5:0] <= 26 ) ) sum_a[31:0] = d0_x2[31:0]; else if ( ( COUNT[5:0] >= 27 ) & ( COUNT[5:0] <= 34 ) ) sum_a[31:0] = c1_y1[31:0]; else sum_a[31:0] = c0_y2[31:0]; always @(*) if ( ( COUNT[5:0] >= 0 ) & ( COUNT[5:0] <= 18 ) | ( COUNT[5:0] == 49 ) ) sum_b[31:0] = d1_x1[31:0]; else sum_b[31:0] = y0[31:0]; wire [31:0] sum_out; sum_float32 ( 1, mhz_clk, sum_a[31:0], sum_b[31:0], sum_out[31:0] ); reg [31:0] outsum; always @(*) outsum[31:0]=sum_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) y0[31:0] = 32'h0; else if ( ( COUNT[5:0] == 18 ) | ( COUNT[5:0] == 26 ) | ( COUNT[5:0] == 34 ) | ( COUNT[5:0] == 42 ) ) y0[31:0] = sum_out[31:0]; reg [17:0] int_to_float_in; always @(*) begin int_to_float_in[17:0] = X[17:0];end wire [31:0] int_to_float_out; int18_to_float32 ( 1, mhz_clk, int_to_float_in[17:0], int_to_float_out[31:0] ); always @( posedge mhz_clk,negedge RESET ) if (~RESET) x0[31:0] = 32'h0; else if ( COUNT[5:0] == 49 ) x0[31:0] = int_to_float_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) x1[31:0] = 32'h0; else if ( COUNT[5:0] == 49 ) x1[31:0] = x0[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) x2[31:0] = 32'h0; else if ( COUNT[5:0] == 49 ) x2[31:0] = x1[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) y1[31:0] = 32'h0; else if ( COUNT[5:0] == 49 ) y1[31:0] = sum_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) y2[31:0] = 32'h0; else if ( COUNT[5:0] == 49 ) y2[31:0] = y1[31:0]; wire [17:0] float_to_int_out; wire nan; wire overflow; wire underflow; float32_to_int18 ( 1, mhz_clk, y0[31:0], nan, overflow, float_to_int_out[17:0], underflow ); reg [17:0] Y; always @( posedge mhz_clk ) if ( COUNT[4:0] == 6 ) Y[17:0] = float_to_int_out[17:0]; endmodule
      
      









module LP_FILTER ( mhz_clk,RESET, D0,D1,D2,C0,C1, X,Y, COUNT ); // low pass filter INPUT32 OUTPUT32 /* y(i) = D2 * x(i) + D1 * x(i-1) + D0 * x(i-2) + C1 * y(i-1) + C0 * y(i-2) A(z) = (D0+D1*z+D2*z*z)/(C0+C1*z+z*z) <==> A(P) = (d0+d1*P+d2*P*P)/(c0+c1*P+c2*P*P) A(P) = 1/(1+1.4*P+P*P) LPF D0 = ( d0 - d1*l + d2*l*l)/(c0 + c1*l + c2*l*l) D1 = (2*d0 - 2*d2*l*l)/(c0 + c1*l + c2*l*l) D2 = ( d0 + d1*l + d2*l*l)/(c0 + c1*l + c2*l*l) C0 = -( c0 - c1*l + c2*l*l)/(c0 + c1*l + c2*l*l) C1 = -(2*c0 - 2*c2*l*l)/(c0 + c1*l + c2*l*l) l = ctg ( 3.14 * f_filt / f_samp ) */ input mhz_clk; input RESET; input [17:0] X; input [31:0] D0; input [31:0] D1; input [31:0] D2; input [31:0] C0; input [31:0] C1; output [17:0] Y; output [5:0] COUNT; // adc-filter counter reg [5:0] COUNT; always @( posedge mhz_clk,negedge RESET ) if (~RESET) COUNT[5:0] = 0; //49 count else if (COUNT[5:0] == 6'h31) COUNT[5:0] = 0; else COUNT[5:0] = COUNT[5:0] + 6'b1; // input - COUNT[4:0] = 24:49 // output - COUNT[4:0] = 6 reg [31:0] c0_y2; reg [31:0] c1_y1; reg [31:0] d0_x2; reg [31:0] d1_x1; reg [31:0] d2_x0; reg [31:0] y0; reg [31:0] y1; reg [31:0] y2; reg [31:0] x0; reg [31:0] x1; reg [31:0] x2; // y(i) = D2 * x(i) + D1 * x(i-1) + D0 * x(i-2) + C1 * y(i-1) + C0 * y(i-2) reg [31:0] mul_a; reg [31:0] mul_b; always @(*) if ( ( COUNT[5:0] >= 0 ) & ( COUNT[5:0] <= 4 ) | ( COUNT[5:0] == 49 ) ) mul_a[31:0] = x0[31:0]; else if ( ( COUNT[5:0] >= 5 ) & ( COUNT[5:0] <= 10 ) ) mul_a[31:0] = x1[31:0]; else if ( ( COUNT[5:0] >= 11 ) & ( COUNT[5:0] <= 16 ) ) mul_a[31:0] = x2[31:0]; else if ( ( COUNT[5:0] >= 17 ) & ( COUNT[5:0] <= 22 ) ) mul_a[31:0] = y1[31:0]; else mul_a[31:0] = y2[31:0]; always @(*) if ( ( COUNT[5:0] >= 0 ) & ( COUNT[5:0] <= 4 ) | ( COUNT[5:0] == 49 ) ) mul_b[31:0] = D2[31:0]; else if ( ( COUNT[5:0] >= 5 ) & ( COUNT[5:0] <= 10 ) ) mul_b[31:0] = D1[31:0]; else if ( ( COUNT[5:0] >= 11 ) & ( COUNT[5:0] <= 16 ) ) mul_b[31:0] = D0[31:0]; else if ( ( COUNT[5:0] >= 17 ) & ( COUNT[5:0] <= 22 ) ) mul_b[31:0] = C1[31:0]; else mul_b[31:0] = C0[31:0]; wire [31:0] mul_out; mul_float32 ( 1, mhz_clk, mul_a[31:0], mul_b[31:0], mul_out[31:0] ); reg [31:0] outmul; always @(*) outmul[31:0]=mul_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) d2_x0[31:0] = 32'h0; else if ( COUNT[5:0] == 4 ) d2_x0[31:0] = mul_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) d1_x1[31:0] = 32'h0; else if ( COUNT[5:0] == 10 ) d1_x1[31:0] = mul_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) d0_x2[31:0] = 32'h0; else if ( COUNT[5:0] == 16 ) d0_x2[31:0] = mul_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) c1_y1[31:0] = 32'h0; else if ( COUNT[5:0] == 22 ) c1_y1[31:0] = mul_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) c0_y2[31:0] = 32'h0; else if ( COUNT[5:0] == 28 ) c0_y2[31:0] = mul_out[31:0]; // y(i) = D2 * x(i) + D1 * x(i-1) + D0 * x(i-2) + C1 * y(i-1) + C0 * y(i-2) reg [31:0] sum_a; reg [31:0] sum_b; always @(*) if ( ( COUNT[5:0] >= 0 ) & ( COUNT[5:0] <= 18 ) | ( COUNT[5:0] == 49 ) ) sum_a[31:0] = d2_x0[31:0]; else if ( ( COUNT[5:0] >= 19 ) & ( COUNT[5:0] <= 26 ) ) sum_a[31:0] = d0_x2[31:0]; else if ( ( COUNT[5:0] >= 27 ) & ( COUNT[5:0] <= 34 ) ) sum_a[31:0] = c1_y1[31:0]; else sum_a[31:0] = c0_y2[31:0]; always @(*) if ( ( COUNT[5:0] >= 0 ) & ( COUNT[5:0] <= 18 ) | ( COUNT[5:0] == 49 ) ) sum_b[31:0] = d1_x1[31:0]; else sum_b[31:0] = y0[31:0]; wire [31:0] sum_out; sum_float32 ( 1, mhz_clk, sum_a[31:0], sum_b[31:0], sum_out[31:0] ); reg [31:0] outsum; always @(*) outsum[31:0]=sum_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) y0[31:0] = 32'h0; else if ( ( COUNT[5:0] == 18 ) | ( COUNT[5:0] == 26 ) | ( COUNT[5:0] == 34 ) | ( COUNT[5:0] == 42 ) ) y0[31:0] = sum_out[31:0]; reg [17:0] int_to_float_in; always @(*) begin int_to_float_in[17:0] = X[17:0];end wire [31:0] int_to_float_out; int18_to_float32 ( 1, mhz_clk, int_to_float_in[17:0], int_to_float_out[31:0] ); always @( posedge mhz_clk,negedge RESET ) if (~RESET) x0[31:0] = 32'h0; else if ( COUNT[5:0] == 49 ) x0[31:0] = int_to_float_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) x1[31:0] = 32'h0; else if ( COUNT[5:0] == 49 ) x1[31:0] = x0[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) x2[31:0] = 32'h0; else if ( COUNT[5:0] == 49 ) x2[31:0] = x1[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) y1[31:0] = 32'h0; else if ( COUNT[5:0] == 49 ) y1[31:0] = sum_out[31:0]; always @( posedge mhz_clk,negedge RESET ) if (~RESET) y2[31:0] = 32'h0; else if ( COUNT[5:0] == 49 ) y2[31:0] = y1[31:0]; wire [17:0] float_to_int_out; wire nan; wire overflow; wire underflow; float32_to_int18 ( 1, mhz_clk, y0[31:0], nan, overflow, float_to_int_out[17:0], underflow ); reg [17:0] Y; always @( posedge mhz_clk ) if ( COUNT[4:0] == 6 ) Y[17:0] = float_to_int_out[17:0]; endmodule













このプログラムは完全なモジュールであり、既存のプロジェクトに組み込む準備ができています。 入力データは、18ビット整数の形式でそこに転送されます。 (おそらく、このようなビットは誰かにとって奇妙に思えるかもしれませんが、開発されたボードはAD7643 18ビットADCを使用していることをすぐに説明します) 次に、32ビット浮動小数点形式に変換されます。 これは、標準のAlterメガファンクションint18_to_float32を使用して行われます。 加算と乗算はそれぞれ標準関数sum_float32mul_float32によっても実装されます。 必要な計算を実行した後、結果はfloat32_to_int18関数によって18ビット整数に変換されます。 事前に計算された係数を使用して、このモジュールをローパス、ハイパス、またはバンドパスフィルターに変えることができます。

Quartus II 9.1のプロジェクトアーカイブ

すでに本文で言及されているウィキペディアの書籍とデータに加えて、トピックを作成するときに、 半導体回路リファレンスガイドが使用されました。 Titze W.、Schenk K. 、およびデジタルフィルターの構造とその特性

声明の混乱のいくつかをおpoびします。 文学的な才能は私の特徴ではありませんでした。ご清聴ありがとうございました。



All Articles