FPGA SDR(18)自作CICフィルタ(可変間引き率版)
IP CatalogのCICフィルタも自作CICフィルタも入力rateの値で間引き率を動的に変更できます。ただし平均の分母が常に最高間引き率固定なので、最高間引き率より小さい間引き率のときは出力データが小さくなってしまいます。段数が多いとべき乗で小さくなってしまいます。
AM/FMラジオの間引き率は、AM 1/1024、FM 1/64にしているので、1段のフィルタでもFMのときのCICフィルタの出力はAMのときの1/16になります。2段、3段にすると小さくなりすぎて復調できません。
そこで、間引き率で出力レベルが変化しないCICフィルタを作ってみました。
`timescale 1ns/1ns module MyCIC #( parameter NUM_STAGES = 3, parameter MAX_RATE_WIDTH = 12, parameter IN_WIDTH = 19, parameter OUT_WIDTH = 19 ) ( input wire clk, input wire reset_n, input wire [MAX_RATE_WIDTH:0] rate, input wire signed [IN_WIDTH-1:0] in_data, output wire in_ready, input wire in_valid, input wire [1:0] in_error, output reg signed [OUT_WIDTH-1:0] out_data, input wire out_ready, output reg out_valid, output wire [1:0] out_error ); localparam WIDTH = MAX_RATE_WIDTH * NUM_STAGES + IN_WIDTH; integer i; reg signed [WIDTH-1:0] integ [0:NUM_STAGES]; reg signed [WIDTH-1:0] diff [0:NUM_STAGES]; reg signed [WIDTH-1:0] diff_d [0:NUM_STAGES]; reg [MAX_RATE_WIDTH:0] count; reg [3:0] rate_width; reg next_out_valid; assign in_ready = 1'b1; assign out_error = 2'b00; always @(posedge clk) begin if (~reset_n) begin for (i = 1; i <= NUM_STAGES; i = i + 1) begin integ[i] <= 0; end diff[1] <= 0; end else begin integ[1] <= in_data + integ[1]; for (i = 2; i <= NUM_STAGES; i = i + 1) begin integ[i] <= integ[i-1] + integ[i]; end diff[1] <= integ[NUM_STAGES-1] + integ[NUM_STAGES]; end end always @(posedge clk) begin if (~reset_n) begin count <= 0; next_out_valid <= 1'b1; rate_width <= 0; end else begin if (count == rate - 1) begin count <= 0; next_out_valid <= 1'b1; if (count >= 16384) rate_width <= 15; else if (count >= 8192) rate_width <= 14; else if (count >= 4096) rate_width <= 13; else if (count >= 2048) rate_width <= 12; else if (count >= 1024) rate_width <= 11; else if (count >= 512) rate_width <= 10; else if (count >= 256) rate_width <= 9; else if (count >= 128) rate_width <= 8; else if (count >= 64) rate_width <= 7; else if (count >= 32) rate_width <= 6; else if (count >= 16) rate_width <= 5; else if (count >= 8) rate_width <= 4; else if (count >= 4) rate_width <= 3; else if (count >= 2) rate_width <= 2; else if (count >= 1) rate_width <= 1; else rate_width <= 0; end else begin count <= count + 1; next_out_valid <= 1'b0; end end end always @(posedge clk) begin out_valid <= next_out_valid; if (~reset_n) begin for (i = 1; i <= NUM_STAGES; i = i + 1) begin diff_d[i] <= 0; end for (i = 2; i <= NUM_STAGES; i = i + 1) begin diff[i] <= 0; end out_data <= 0; end else begin if (next_out_valid) begin for (i = 1; i <= NUM_STAGES; i = i + 1) begin diff_d[i] <= diff[i]; end for (i = 2; i <= NUM_STAGES; i = i + 1) begin diff[i] <= diff[i-1] - diff_d[i-1]; end out_data <= (diff[NUM_STAGES] - diff_d[NUM_STAGES]) >>> (rate_width * NUM_STAGES + IN_WIDTH - OUT_WIDTH); end end end endmodule