FPGA SDR(27)メモリベースFIRフィルタ
2019/03/20 追記:メモリベースFIRフィルタを修正しました。
2019/03/06 追記:メモリベースFIRフィルタを修正しました。
以前作ったFIRフィルタやFIR間引きフィルタの特性を急峻にするためタップ数を増やすとLogic Elementsの使用量が急激に増加します。入力信号を保持するタップ数のレジスタをOn chip memoryにするとLogic Elementsを大幅に節約できました。IP Catalogにある評価版FIRフィルタと同等になりました。
古い入力信号を1つ捨てて新しい入力信号を1つ追加するため、IP CatalogのRAM: 2 PORTを使います。
遮断周波数0.0625 x サンプリング周波数のメモリベースFIR 1/8間引きフィルタ
`timescale 1ns/1ns module MyMEMFIR8 #( parameter RATE = 8, parameter DATA_WIDTH = 10 ) ( input wire clk, input wire reset_n, input wire signed [DATA_WIDTH-1:0] ast_sink_data, input wire ast_sink_valid, input wire [1:0] ast_sink_error, output reg signed [DATA_WIDTH-1:0] ast_source_data, output reg ast_source_valid, output wire [1:0] ast_source_error ); localparam NUM_TAPS = 191; localparam H_WIDTH = 16; localparam Y_WIDTH = H_WIDTH + DATA_WIDTH - 1; // RAM 16x256 localparam RAM_NUM_ADDRS = 256; integer i; reg signed [H_WIDTH-1:0] h[0:NUM_TAPS-1]; wire signed [DATA_WIDTH-1:0] x; reg signed [Y_WIDTH-1:0] y; wire [7:0] raddr; reg [7:0] waddr; reg [7:0] last_waddr; reg [8:0] cnt; reg [7:0] deci_cnt; // Normalized Frequency: 0.0625 initial begin h[0] = -3; h[1] = -6; h[2] = -8; h[3] = -9; h[4] = -9; h[5] = -7; h[6] = -4; h[7] = 0; h[8] = 4; h[9] = 9; h[10] = 12; h[11] = 14; h[12] = 13; h[13] = 11; h[14] = 6; h[15] = 0; h[16] = -7; h[17] = -14; h[18] = -20; h[19] = -23; h[20] = -23; h[21] = -19; h[22] = -11; h[23] = 0; h[24] = 12; h[25] = 24; h[26] = 33; h[27] = 39; h[28] = 38; h[29] = 31; h[30] = 18; h[31] = 0; h[32] = -20; h[33] = -39; h[34] = -54; h[35] = -62; h[36] = -60; h[37] = -49; h[38] = -28; h[39] = 0; h[40] = 31; h[41] = 60; h[42] = 83; h[43] = 95; h[44] = 92; h[45] = 74; h[46] = 42; h[47] = 0; h[48] = -47; h[49] = -90; h[50] = -124; h[51] = -141; h[52] = -136; h[53] = -109; h[54] = -62; h[55] = 0; h[56] = 68; h[57] = 132; h[58] = 181; h[59] = 206; h[60] = 200; h[61] = 160; h[62] = 91; h[63] = 0; h[64] = -100; h[65] = -195; h[66] = -267; h[67] = -304; h[68] = -296; h[69] = -238; h[70] = -136; h[71] = 0; h[72] = 152; h[73] = 296; h[74] = 410; h[75] = 471; h[76] = 463; h[77] = 377; h[78] = 218; h[79] = 0; h[80] = -251; h[81] = -501; h[82] = -710; h[83] = -838; h[84] = -850; h[85] = -719; h[86] = -435; h[87] = 0; h[88] = 563; h[89] = 1218; h[90] = 1915; h[91] = 2597; h[92] = 3205; h[93] = 3684; h[94] = 3990; h[95] = 4096; h[96] = 3990; h[97] = 3684; h[98] = 3205; h[99] = 2597; h[100] = 1915; h[101] = 1218; h[102] = 563; h[103] = 0; h[104] = -435; h[105] = -719; h[106] = -850; h[107] = -838; h[108] = -710; h[109] = -501; h[110] = -251; h[111] = 0; h[112] = 218; h[113] = 377; h[114] = 463; h[115] = 471; h[116] = 410; h[117] = 296; h[118] = 152; h[119] = 0; h[120] = -136; h[121] = -238; h[122] = -296; h[123] = -304; h[124] = -267; h[125] = -195; h[126] = -100; h[127] = 0; h[128] = 91; h[129] = 160; h[130] = 200; h[131] = 206; h[132] = 181; h[133] = 132; h[134] = 68; h[135] = 0; h[136] = -62; h[137] = -109; h[138] = -136; h[139] = -141; h[140] = -124; h[141] = -90; h[142] = -47; h[143] = 0; h[144] = 42; h[145] = 74; h[146] = 92; h[147] = 95; h[148] = 83; h[149] = 60; h[150] = 31; h[151] = 0; h[152] = -28; h[153] = -49; h[154] = -60; h[155] = -62; h[156] = -54; h[157] = -39; h[158] = -20; h[159] = 0; h[160] = 18; h[161] = 31; h[162] = 38; h[163] = 39; h[164] = 33; h[165] = 24; h[166] = 12; h[167] = 0; h[168] = -11; h[169] = -19; h[170] = -23; h[171] = -23; h[172] = -20; h[173] = -14; h[174] = -7; h[175] = 0; h[176] = 6; h[177] = 11; h[178] = 13; h[179] = 14; h[180] = 12; h[181] = 9; h[182] = 4; h[183] = 0; h[184] = -4; h[185] = -7; h[186] = -9; h[187] = -9; h[188] = -8; h[189] = -6; h[190] = -3; end assign ast_source_error = 2'b00; always @(posedge clk) begin if (~reset_n) begin waddr <= 0; cnt <= 0; deci_cnt <= 0; y <= 0; ast_source_data <= 0; ast_source_valid <= 1'b0; end else begin if (ast_sink_valid) begin if (waddr == RAM_NUM_ADDRS-1) begin waddr <= 0; end else begin waddr <= waddr + 1; end if (deci_cnt == RATE-1) begin deci_cnt <= 0; ast_source_data <= y[Y_WIDTH-1 -: DATA_WIDTH]; ast_source_valid <= 1'b1; last_waddr <= waddr; cnt <= 0; y <= 0; end else begin deci_cnt <= deci_cnt + 1; if (cnt < NUM_TAPS) begin cnt <= cnt + 1; end if (cnt < NUM_TAPS) begin y <= y + h[cnt] * x; end ast_source_valid <= 1'b0; end end else begin if (cnt < NUM_TAPS) begin cnt <= cnt + 1; end if (cnt < NUM_TAPS) begin y <= y + h[cnt] * x; end ast_source_valid <= 1'b0; end end end assign raddr = (RAM_NUM_ADDRS + last_waddr - (NUM_TAPS - 1) + cnt <= RAM_NUM_ADDRS-1) ? RAM_NUM_ADDRS + last_waddr - (NUM_TAPS - 1) + cnt : RAM_NUM_ADDRS + last_waddr - (NUM_TAPS - 1) + cnt - RAM_NUM_ADDRS; ram16x256 ram16x256_inst ( .clock (clk), .data (ast_sink_data), .rdaddress (raddr), .wraddress (waddr), .wren (ast_sink_valid), .q (x) ); endmodule
遮断周波数0.042 x サンプリング周波数のメモリベース FIR 1/8間引きフィルタ
`timescale 1ns/1ns module MyMEMLPF8 #( parameter RATE = 8, parameter DATA_WIDTH = 10 ) ( input wire clk, input wire reset_n, input wire signed [DATA_WIDTH-1:0] ast_sink_data, input wire ast_sink_valid, input wire [1:0] ast_sink_error, output reg signed [DATA_WIDTH-1:0] ast_source_data, output reg ast_source_valid, output wire [1:0] ast_source_error ); localparam NUM_TAPS = 199; localparam H_WIDTH = 16; localparam Y_WIDTH = H_WIDTH + DATA_WIDTH - 1; // RAM 16x256 localparam RAM_NUM_ADDRS = 256; integer i; reg signed [H_WIDTH-1:0] h[0:NUM_TAPS-1]; wire signed [DATA_WIDTH-1:0] x; reg signed [Y_WIDTH-1:0] y; wire [7:0] raddr; reg [7:0] waddr; reg [7:0] last_waddr; reg [8:0] cnt; reg [7:0] deci_cnt; // Normalized Frequency: 0.042 initial begin h[0] = 7; h[1] = 6; h[2] = 4; h[3] = 2; h[4] = -1; h[5] = -3; h[6] = -6; h[7] = -8; h[8] = -10; h[9] = -11; h[10] = -12; h[11] = -12; h[12] = -11; h[13] = -9; h[14] = -7; h[15] = -3; h[16] = 2; h[17] = 6; h[18] = 11; h[19] = 16; h[20] = 20; h[21] = 24; h[22] = 25; h[23] = 25; h[24] = 23; h[25] = 19; h[26] = 13; h[27] = 5; h[28] = -4; h[29] = -14; h[30] = -25; h[31] = -34; h[32] = -43; h[33] = -49; h[34] = -51; h[35] = -51; h[36] = -46; h[37] = -37; h[38] = -24; h[39] = -8; h[40] = 10; h[41] = 29; h[42] = 49; h[43] = 67; h[44] = 81; h[45] = 91; h[46] = 95; h[47] = 92; h[48] = 82; h[49] = 65; h[50] = 42; h[51] = 12; h[52] = -21; h[53] = -56; h[54] = -89; h[55] = -120; h[56] = -144; h[57] = -160; h[58] = -166; h[59] = -160; h[60] = -141; h[61] = -110; h[62] = -67; h[63] = -16; h[64] = 42; h[65] = 102; h[66] = 160; h[67] = 212; h[68] = 253; h[69] = 280; h[70] = 288; h[71] = 276; h[72] = 242; h[73] = 187; h[74] = 111; h[75] = 19; h[76] = -85; h[77] = -194; h[78] = -302; h[79] = -401; h[80] = -482; h[81] = -537; h[82] = -559; h[83] = -542; h[84] = -481; h[85] = -374; h[86] = -220; h[87] = -21; h[88] = 218; h[89] = 491; h[90] = 789; h[91] = 1102; h[92] = 1417; h[93] = 1724; h[94] = 2009; h[95] = 2261; h[96] = 2469; h[97] = 2624; h[98] = 2720; h[99] = 2752; h[100] = 2720; h[101] = 2624; h[102] = 2469; h[103] = 2261; h[104] = 2009; h[105] = 1724; h[106] = 1417; h[107] = 1102; h[108] = 789; h[109] = 491; h[110] = 218; h[111] = -21; h[112] = -220; h[113] = -374; h[114] = -481; h[115] = -542; h[116] = -559; h[117] = -537; h[118] = -482; h[119] = -401; h[120] = -302; h[121] = -194; h[122] = -85; h[123] = 19; h[124] = 111; h[125] = 187; h[126] = 242; h[127] = 276; h[128] = 288; h[129] = 280; h[130] = 253; h[131] = 212; h[132] = 160; h[133] = 102; h[134] = 42; h[135] = -16; h[136] = -67; h[137] = -110; h[138] = -141; h[139] = -160; h[140] = -166; h[141] = -160; h[142] = -144; h[143] = -120; h[144] = -89; h[145] = -56; h[146] = -21; h[147] = 12; h[148] = 42; h[149] = 65; h[150] = 82; h[151] = 92; h[152] = 95; h[153] = 91; h[154] = 81; h[155] = 67; h[156] = 49; h[157] = 29; h[158] = 10; h[159] = -8; h[160] = -24; h[161] = -37; h[162] = -46; h[163] = -51; h[164] = -51; h[165] = -49; h[166] = -43; h[167] = -34; h[168] = -25; h[169] = -14; h[170] = -4; h[171] = 5; h[172] = 13; h[173] = 19; h[174] = 23; h[175] = 25; h[176] = 25; h[177] = 24; h[178] = 20; h[179] = 16; h[180] = 11; h[181] = 6; h[182] = 2; h[183] = -3; h[184] = -7; h[185] = -9; h[186] = -11; h[187] = -12; h[188] = -12; h[189] = -11; h[190] = -10; h[191] = -8; h[192] = -6; h[193] = -3; h[194] = -1; h[195] = 2; h[196] = 4; h[197] = 6; h[198] = 7; end assign ast_source_error = 2'b00; always @(posedge clk) begin if (~reset_n) begin waddr <= 0; cnt <= 0; deci_cnt <= 0; y <= 0; ast_source_data <= 0; ast_source_valid <= 1'b0; end else begin if (ast_sink_valid) begin if (waddr == RAM_NUM_ADDRS-1) begin waddr <= 0; end else begin waddr <= waddr + 1; end if (deci_cnt == RATE-1) begin deci_cnt <= 0; ast_source_data <= y[Y_WIDTH-1 -: DATA_WIDTH]; ast_source_valid <= 1'b1; last_waddr <= waddr; cnt <= 0; y <= 0; end else begin deci_cnt <= deci_cnt + 1; if (cnt < NUM_TAPS) begin cnt <= cnt + 1; end if (cnt < NUM_TAPS) begin y <= y + h[cnt] * x; end ast_source_valid <= 1'b0; end end else begin if (cnt < NUM_TAPS) begin cnt <= cnt + 1; end if (cnt < NUM_TAPS) begin y <= y + h[cnt] * x; end ast_source_valid <= 1'b0; end end end assign raddr = (RAM_NUM_ADDRS + last_waddr - (NUM_TAPS - 1) + cnt <= RAM_NUM_ADDRS-1) ? RAM_NUM_ADDRS + last_waddr - (NUM_TAPS - 1) + cnt : RAM_NUM_ADDRS + last_waddr - (NUM_TAPS - 1) + cnt - RAM_NUM_ADDRS; ram16x256 ram16x256_inst ( .clock (clk), .data (ast_sink_data), .rdaddress (raddr), .wraddress (waddr), .wren (ast_sink_valid), .q (x) ); endmodule