Posted by May 23, 2005
"Paul Solomon" <psolomon@tpg.com.au> writes:

> Hi Brian, > > Wow, that is great, reading that verilog code has helped heaps and it > cleared up where I was going wrong > with my CIC filter.. I just needed to add a few signed keywords and handle > the signed extension with the > $signed cast operator. > > Thank you very much.. > > Is there any chance you could do the same and post the code for a FIR filter > as well as I am having a similar > problem now trying to implement the compensating FIR filter that should come > next.. > > the filter is designed as follows... > > cfir = firceqrip(20, 0.16, [5.7565e-4 0.000001], 'passedge','invsinc', [1
I would be happy to do this as another gesture of good will; I will even go one step further and suggest FIR-transposed as generally being a better structure for hardware implementation. For both we exploit the symmetric coefficients. Just ask for a trial of Filter Design and Filter Design HDL Coder toolboxes and you can do this yourself in under ten seconds! I will show both and my script: cfir = firceqrip(20, 0.16, [5.7565e-4 0.000001], 'passedge','invsinc', [1 4]) Hcfir = dfilt.dfsymfir(cfir); Hcfir.arithmetic = 'fixed'; Hcfir.coeffWordLength = 20 Hcfir.InputWordLength = 32; Hcfir.InputFracLength = 0; Hcfir.filterInternals = 'specifyPrecision'; Hcfir.RoundMode = 'floor'; Hcfir.outputWordLength = 32; generatehdl(Hcfir,'targetlanguage','verilog') Hcfirt = dfilt.dffirt(cfir); Hcfirt.arithmetic = 'fixed'; Hcfirt.coeffWordLength = 20 Hcfirt.InputWordLength = 32; Hcfirt.InputFracLength = 0; Hcfirt.filterInternals = 'specifyPrecision'; Hcfirt.RoundMode = 'floor'; Hcfirt.outputWordLength = 32; generatehdl(Hcfirt,'targetlanguage','verilog') Note that I changed the rounding mode to floor and tried to set the input, coefficient, and output widths as you said but I let the coefficient binary points and internal arithmetic be automatically scaled so only the output is quantized. Recall too that input and output registers are the default but that can be changed. By changing an option, we can also remove all the multipliers, using a shift-and-add technique known as Canonic Signed-Digit or CSD recoding or even a factored version of CSD. We can also cascade your CIC and your compensating FIR into one filter object and generate Verilog for the two filters and the cascade wrapper in one simple command. Here are the Verilog files for both Symmetric-FIR and FIR-Transposed: // ------------------------------------------------------------- // // Module: Hcfir // // Generated by MATLAB(R) 7.1 and the Filter Design HDL Coder 1.3. // // Generated on: 2005-05-23 12:22:10 // // ------------------------------------------------------------- // ------------------------------------------------------------- // HDL Code Generation Options: // // TargetLanguage: Verilog // Name: Hcfir // // Filter Settings: // // Discrete-Time FIR Filter (real) // ------------------------------- // Filter Structure : Direct-Form Symmetric FIR // Filter Length : 21 // Stable : Yes // Linear Phase : Yes (Type 1) // Arithmetic : fixed // Numerator : s20,19 -> [-1 1) // Input : s32,0 -> [-2.147484e+009 2.147484e+009) // Filter Internals : Specify Precision // Output : s32,19 -> [-4096 4096) // Tap Sum : s33,0 -> [-4.294967e+009 4.294967e+009) // Product : s52,19 -> [-4.294967e+009 4.294967e+009) // Accumulator : s52,19 -> [-4.294967e+009 4.294967e+009) // Round Mode : floor // Overflow Mode : wrap // ------------------------------------------------------------- `timescale 1 ns / 1 ns module Hcfir ( clk, clk_enable, reset, filter_in, filter_out ); input clk; input clk_enable; input reset; input signed [31:0] filter_in; //sfix32 output signed [31:0] filter_out; //sfix32_En19 // Local Functions // Type Definitions // Constants parameter signed [19:0] coeff1 = 20'b11111111111011000100; //sfix20_En19 parameter signed [19:0] coeff2 = 20'b11111111101010011100; //sfix20_En19 parameter signed [19:0] coeff3 = 20'b11111111110010100011; //sfix20_En19 parameter signed [19:0] coeff4 = 20'b00000001100100011011; //sfix20_En19 parameter signed [19:0] coeff5 = 20'b00000011101011000110; //sfix20_En19 parameter signed [19:0] coeff6 = 20'b00000000000011100000; //sfix20_En19 parameter signed [19:0] coeff7 = 20'b11110100111011001001; //sfix20_En19 parameter signed [19:0] coeff8 = 20'b11110000101111001100; //sfix20_En19 parameter signed [19:0] coeff9 = 20'b00000110011011010001; //sfix20_En19 parameter signed [19:0] coeff10 = 20'b00101101111111101001; //sfix20_En19 parameter signed [19:0] coeff11 = 20'b01000010100100000111; //sfix20_En19 // Signals reg signed [31:0] delay_pipeline [0:20] ; // sfix32 wire signed [32:0] tapsum1; // sfix33 wire signed [31:0] add_signext; // sfix32 wire signed [31:0] add_signext_1; // sfix32 wire signed [32:0] tapsum_mcand; // sfix33 wire signed [32:0] tapsum2; // sfix33 wire signed [31:0] add_signext_2; // sfix32 wire signed [31:0] add_signext_3; // sfix32 wire signed [32:0] tapsum_mcand_1; // sfix33 wire signed [32:0] tapsum3; // sfix33 wire signed [31:0] add_signext_4; // sfix32 wire signed [31:0] add_signext_5; // sfix32 wire signed [32:0] tapsum_mcand_2; // sfix33 wire signed [32:0] tapsum4; // sfix33 wire signed [31:0] add_signext_6; // sfix32 wire signed [31:0] add_signext_7; // sfix32 wire signed [32:0] tapsum_mcand_3; // sfix33 wire signed [32:0] tapsum5; // sfix33 wire signed [31:0] add_signext_8; // sfix32 wire signed [31:0] add_signext_9; // sfix32 wire signed [32:0] tapsum_mcand_4; // sfix33 wire signed [32:0] tapsum6; // sfix33 wire signed [31:0] add_signext_10; // sfix32 wire signed [31:0] add_signext_11; // sfix32 wire signed [32:0] tapsum_mcand_5; // sfix33 wire signed [32:0] tapsum7; // sfix33 wire signed [31:0] add_signext_12; // sfix32 wire signed [31:0] add_signext_13; // sfix32 wire signed [32:0] tapsum_mcand_6; // sfix33 wire signed [32:0] tapsum8; // sfix33 wire signed [31:0] add_signext_14; // sfix32 wire signed [31:0] add_signext_15; // sfix32 wire signed [32:0] tapsum_mcand_7; // sfix33 wire signed [32:0] tapsum9; // sfix33 wire signed [31:0] add_signext_16; // sfix32 wire signed [31:0] add_signext_17; // sfix32 wire signed [32:0] tapsum_mcand_8; // sfix33 wire signed [32:0] tapsum10; // sfix33 wire signed [31:0] add_signext_18; // sfix32 wire signed [31:0] add_signext_19; // sfix32 wire signed [32:0] tapsum_mcand_9; // sfix33 wire signed [51:0] product11; // sfix52_En19 wire signed [51:0] product10; // sfix52_En19 wire signed [52:0] mul_temp; // sfix53_En19 wire signed [51:0] product9; // sfix52_En19 wire signed [52:0] mul_temp_1; // sfix53_En19 wire signed [51:0] product8; // sfix52_En19 wire signed [52:0] mul_temp_2; // sfix53_En19 wire signed [51:0] product7; // sfix52_En19 wire signed [52:0] mul_temp_3; // sfix53_En19 wire signed [51:0] product6; // sfix52_En19 wire signed [52:0] mul_temp_4; // sfix53_En19 wire signed [51:0] product5; // sfix52_En19 wire signed [52:0] mul_temp_5; // sfix53_En19 wire signed [51:0] product4; // sfix52_En19 wire signed [52:0] mul_temp_6; // sfix53_En19 wire signed [51:0] product3; // sfix52_En19 wire signed [52:0] mul_temp_7; // sfix53_En19 wire signed [51:0] product2; // sfix52_En19 wire signed [52:0] mul_temp_8; // sfix53_En19 wire signed [51:0] product1; // sfix52_En19 wire signed [52:0] mul_temp_9; // sfix53_En19 wire signed [51:0] sum1; // sfix52_En19 wire signed [51:0] add_signext_20; // sfix52_En19 wire signed [51:0] add_signext_21; // sfix52_En19 wire signed [52:0] add_temp; // sfix53_En19 wire signed [51:0] sum2; // sfix52_En19 wire signed [51:0] add_signext_22; // sfix52_En19 wire signed [51:0] add_signext_23; // sfix52_En19 wire signed [52:0] add_temp_1; // sfix53_En19 wire signed [51:0] sum3; // sfix52_En19 wire signed [51:0] add_signext_24; // sfix52_En19 wire signed [51:0] add_signext_25; // sfix52_En19 wire signed [52:0] add_temp_2; // sfix53_En19 wire signed [51:0] sum4; // sfix52_En19 wire signed [51:0] add_signext_26; // sfix52_En19 wire signed [51:0] add_signext_27; // sfix52_En19 wire signed [52:0] add_temp_3; // sfix53_En19 wire signed [51:0] sum5; // sfix52_En19 wire signed [51:0] add_signext_28; // sfix52_En19 wire signed [51:0] add_signext_29; // sfix52_En19 wire signed [52:0] add_temp_4; // sfix53_En19 wire signed [51:0] sum6; // sfix52_En19 wire signed [51:0] add_signext_30; // sfix52_En19 wire signed [51:0] add_signext_31; // sfix52_En19 wire signed [52:0] add_temp_5; // sfix53_En19 wire signed [51:0] sum7; // sfix52_En19 wire signed [51:0] add_signext_32; // sfix52_En19 wire signed [51:0] add_signext_33; // sfix52_En19 wire signed [52:0] add_temp_6; // sfix53_En19 wire signed [51:0] sum8; // sfix52_En19 wire signed [51:0] add_signext_34; // sfix52_En19 wire signed [51:0] add_signext_35; // sfix52_En19 wire signed [52:0] add_temp_7; // sfix53_En19 wire signed [51:0] sum9; // sfix52_En19 wire signed [51:0] add_signext_36; // sfix52_En19 wire signed [51:0] add_signext_37; // sfix52_En19 wire signed [52:0] add_temp_8; // sfix53_En19 wire signed [51:0] sum10; // sfix52_En19 wire signed [51:0] add_signext_38; // sfix52_En19 wire signed [51:0] add_signext_39; // sfix52_En19 wire signed [52:0] add_temp_9; // sfix53_En19 wire signed [31:0] output_typeconvert; // sfix32_En19 reg signed [31:0] output_register; // sfix32_En19 // Block Statements always @( posedge clk or posedge reset) begin: Delay_Pipeline_process if (reset == 1'b1) begin delay_pipeline[0] <= 0; delay_pipeline[1] <= 0; delay_pipeline[2] <= 0; delay_pipeline[3] <= 0; delay_pipeline[4] <= 0; delay_pipeline[5] <= 0; delay_pipeline[6] <= 0; delay_pipeline[7] <= 0; delay_pipeline[8] <= 0; delay_pipeline[9] <= 0; delay_pipeline[10] <= 0; delay_pipeline[11] <= 0; delay_pipeline[12] <= 0; delay_pipeline[13] <= 0; delay_pipeline[14] <= 0; delay_pipeline[15] <= 0; delay_pipeline[16] <= 0; delay_pipeline[17] <= 0; delay_pipeline[18] <= 0; delay_pipeline[19] <= 0; delay_pipeline[20] <= 0; end else begin if (clk_enable == 1'b1) begin delay_pipeline[0] <= filter_in; delay_pipeline[1] <= delay_pipeline[0]; delay_pipeline[2] <= delay_pipeline[1]; delay_pipeline[3] <= delay_pipeline[2]; delay_pipeline[4] <= delay_pipeline[3]; delay_pipeline[5] <= delay_pipeline[4]; delay_pipeline[6] <= delay_pipeline[5]; delay_pipeline[7] <= delay_pipeline[6]; delay_pipeline[8] <= delay_pipeline[7]; delay_pipeline[9] <= delay_pipeline[8]; delay_pipeline[10] <= delay_pipeline[9]; delay_pipeline[11] <= delay_pipeline[10]; delay_pipeline[12] <= delay_pipeline[11]; delay_pipeline[13] <= delay_pipeline[12]; delay_pipeline[14] <= delay_pipeline[13]; delay_pipeline[15] <= delay_pipeline[14]; delay_pipeline[16] <= delay_pipeline[15]; delay_pipeline[17] <= delay_pipeline[16]; delay_pipeline[18] <= delay_pipeline[17]; delay_pipeline[19] <= delay_pipeline[18]; delay_pipeline[20] <= delay_pipeline[19]; end end end // Delay_Pipeline_process assign add_signext = delay_pipeline[0]; assign add_signext_1 = delay_pipeline[20]; assign tapsum1 = add_signext + add_signext_1; assign tapsum_mcand = tapsum1; assign add_signext_2 = delay_pipeline[1]; assign add_signext_3 = delay_pipeline[19]; assign tapsum2 = add_signext_2 + add_signext_3; assign tapsum_mcand_1 = tapsum2; assign add_signext_4 = delay_pipeline[2]; assign add_signext_5 = delay_pipeline[18]; assign tapsum3 = add_signext_4 + add_signext_5; assign tapsum_mcand_2 = tapsum3; assign add_signext_6 = delay_pipeline[3]; assign add_signext_7 = delay_pipeline[17]; assign tapsum4 = add_signext_6 + add_signext_7; assign tapsum_mcand_3 = tapsum4; assign add_signext_8 = delay_pipeline[4]; assign add_signext_9 = delay_pipeline[16]; assign tapsum5 = add_signext_8 + add_signext_9; assign tapsum_mcand_4 = tapsum5; assign add_signext_10 = delay_pipeline[5]; assign add_signext_11 = delay_pipeline[15]; assign tapsum6 = add_signext_10 + add_signext_11; assign tapsum_mcand_5 = tapsum6; assign add_signext_12 = delay_pipeline[6]; assign add_signext_13 = delay_pipeline[14]; assign tapsum7 = add_signext_12 + add_signext_13; assign tapsum_mcand_6 = tapsum7; assign add_signext_14 = delay_pipeline[7]; assign add_signext_15 = delay_pipeline[13]; assign tapsum8 = add_signext_14 + add_signext_15; assign tapsum_mcand_7 = tapsum8; assign add_signext_16 = delay_pipeline[8]; assign add_signext_17 = delay_pipeline[12]; assign tapsum9 = add_signext_16 + add_signext_17; assign tapsum_mcand_8 = tapsum9; assign add_signext_18 = delay_pipeline[9]; assign add_signext_19 = delay_pipeline[11]; assign tapsum10 = add_signext_18 + add_signext_19; assign tapsum_mcand_9 = tapsum10; assign product11 = delay_pipeline[10] * coeff11; assign mul_temp = tapsum_mcand_9 * coeff10; assign product10 = mul_temp[51:0]; assign mul_temp_1 = tapsum_mcand_8 * coeff9; assign product9 = mul_temp_1[51:0]; assign mul_temp_2 = tapsum_mcand_7 * coeff8; assign product8 = mul_temp_2[51:0]; assign mul_temp_3 = tapsum_mcand_6 * coeff7; assign product7 = mul_temp_3[51:0]; assign mul_temp_4 = tapsum_mcand_5 * coeff6; assign product6 = mul_temp_4[51:0]; assign mul_temp_5 = tapsum_mcand_4 * coeff5; assign product5 = mul_temp_5[51:0]; assign mul_temp_6 = tapsum_mcand_3 * coeff4; assign product4 = mul_temp_6[51:0]; assign mul_temp_7 = tapsum_mcand_2 * coeff3; assign product3 = mul_temp_7[51:0]; assign mul_temp_8 = tapsum_mcand_1 * coeff2; assign product2 = mul_temp_8[51:0]; assign mul_temp_9 = tapsum_mcand * coeff1; assign product1 = mul_temp_9[51:0]; assign add_signext_20 = product1; assign add_signext_21 = product2; assign add_temp = add_signext_20 + add_signext_21; assign sum1 = add_temp[51:0]; assign add_signext_22 = sum1; assign add_signext_23 = product3; assign add_temp_1 = add_signext_22 + add_signext_23; assign sum2 = add_temp_1[51:0]; assign add_signext_24 = sum2; assign add_signext_25 = product4; assign add_temp_2 = add_signext_24 + add_signext_25; assign sum3 = add_temp_2[51:0]; assign add_signext_26 = sum3; assign add_signext_27 = product5; assign add_temp_3 = add_signext_26 + add_signext_27; assign sum4 = add_temp_3[51:0]; assign add_signext_28 = sum4; assign add_signext_29 = product6; assign add_temp_4 = add_signext_28 + add_signext_29; assign sum5 = add_temp_4[51:0]; assign add_signext_30 = sum5; assign add_signext_31 = product7; assign add_temp_5 = add_signext_30 + add_signext_31; assign sum6 = add_temp_5[51:0]; assign add_signext_32 = sum6; assign add_signext_33 = product8; assign add_temp_6 = add_signext_32 + add_signext_33; assign sum7 = add_temp_6[51:0]; assign add_signext_34 = sum7; assign add_signext_35 = product9; assign add_temp_7 = add_signext_34 + add_signext_35; assign sum8 = add_temp_7[51:0]; assign add_signext_36 = sum8; assign add_signext_37 = product10; assign add_temp_8 = add_signext_36 + add_signext_37; assign sum9 = add_temp_8[51:0]; assign add_signext_38 = sum9; assign add_signext_39 = product11; assign add_temp_9 = add_signext_38 + add_signext_39; assign sum10 = add_temp_9[51:0]; assign output_typeconvert = sum10[31:0]; always @ (posedge clk or posedge reset) begin: Output_Register_process if (reset == 1'b1) begin output_register <= 0; end else begin if (clk_enable == 1'b1) begin output_register <= output_typeconvert; end end end // Output_Register_process // Assignment Statements assign filter_out = output_register; endmodule // Hcfir ==================================================================== // ------------------------------------------------------------- // // Module: Hcfirt // // Generated by MATLAB(R) 7.1 and the Filter Design HDL Coder 1.3. // // Generated on: 2005-05-23 12:22:11 // // ------------------------------------------------------------- // ------------------------------------------------------------- // HDL Code Generation Options: // // TargetLanguage: Verilog // Name: Hcfirt // // Filter Settings: // // Discrete-Time FIR Filter (real) // ------------------------------- // Filter Structure : Direct-Form FIR Transposed // Filter Length : 21 // Stable : Yes // Linear Phase : Yes (Type 1) // Arithmetic : fixed // Numerator : s20,19 -> [-1 1) // Input : s32,0 -> [-2.147484e+009 2.147484e+009) // Filter Internals : Specify Precision // Output : s32,19 -> [-4096 4096) // States : s52,19 -> [-4.294967e+009 4.294967e+009) // Product : s51,19 -> [-2.147484e+009 2.147484e+009) // Accumulator : s52,19 -> [-4.294967e+009 4.294967e+009) // Round Mode : floor // Overflow Mode : wrap // ------------------------------------------------------------- `timescale 1 ns / 1 ns module Hcfirt ( clk, clk_enable, reset, filter_in, filter_out ); input clk; input clk_enable; input reset; input signed [31:0] filter_in; //sfix32 output signed [31:0] filter_out; //sfix32_En19 // Local Functions // Type Definitions // Constants parameter signed [19:0] coeff1 = 20'b11111111111011000100; //sfix20_En19 parameter signed [19:0] coeff2 = 20'b11111111101010011100; //sfix20_En19 parameter signed [19:0] coeff3 = 20'b11111111110010100011; //sfix20_En19 parameter signed [19:0] coeff4 = 20'b00000001100100011011; //sfix20_En19 parameter signed [19:0] coeff5 = 20'b00000011101011000110; //sfix20_En19 parameter signed [19:0] coeff6 = 20'b00000000000011100000; //sfix20_En19 parameter signed [19:0] coeff7 = 20'b11110100111011001001; //sfix20_En19 parameter signed [19:0] coeff8 = 20'b11110000101111001100; //sfix20_En19 parameter signed [19:0] coeff9 = 20'b00000110011011010001; //sfix20_En19 parameter signed [19:0] coeff10 = 20'b00101101111111101001; //sfix20_En19 parameter signed [19:0] coeff11 = 20'b01000010100100000111; //sfix20_En19 parameter signed [19:0] coeff12 = 20'b00101101111111101001; //sfix20_En19 parameter signed [19:0] coeff13 = 20'b00000110011011010001; //sfix20_En19 parameter signed [19:0] coeff14 = 20'b11110000101111001100; //sfix20_En19 parameter signed [19:0] coeff15 = 20'b11110100111011001001; //sfix20_En19 parameter signed [19:0] coeff16 = 20'b00000000000011100000; //sfix20_En19 parameter signed [19:0] coeff17 = 20'b00000011101011000110; //sfix20_En19 parameter signed [19:0] coeff18 = 20'b00000001100100011011; //sfix20_En19 parameter signed [19:0] coeff19 = 20'b11111111110010100011; //sfix20_En19 parameter signed [19:0] coeff20 = 20'b11111111101010011100; //sfix20_En19 parameter signed [19:0] coeff21 = 20'b11111111111011000100; //sfix20_En19 // Signals reg signed [31:0] inputreg; // sfix32 reg signed [51:0] delay_pipeline [0:19] ; // sfix52_En19 wire signed [51:0] sumvector [0:19] ; // sfix52_En19 wire signed [50:0] product11; // sfix51_En19 wire signed [51:0] mul_temp; // sfix52_En19 wire signed [50:0] product12; // sfix51_En19 wire signed [51:0] mul_temp_1; // sfix52_En19 wire signed [50:0] product13; // sfix51_En19 wire signed [51:0] mul_temp_2; // sfix52_En19 wire signed [50:0] product14; // sfix51_En19 wire signed [51:0] mul_temp_3; // sfix52_En19 wire signed [50:0] product15; // sfix51_En19 wire signed [51:0] mul_temp_4; // sfix52_En19 wire signed [50:0] product16; // sfix51_En19 wire signed [51:0] mul_temp_5; // sfix52_En19 wire signed [50:0] product17; // sfix51_En19 wire signed [51:0] mul_temp_6; // sfix52_En19 wire signed [50:0] product18; // sfix51_En19 wire signed [51:0] mul_temp_7; // sfix52_En19 wire signed [50:0] product19; // sfix51_En19 wire signed [51:0] mul_temp_8; // sfix52_En19 wire signed [50:0] product20; // sfix51_En19 wire signed [51:0] mul_temp_9; // sfix52_En19 wire signed [50:0] product21; // sfix51_En19 wire signed [51:0] mul_temp_10; // sfix52_En19 wire signed [51:0] finalsum; // sfix52_En19 wire signed [51:0] add_signext; // sfix52_En19 wire signed [51:0] add_signext_1; // sfix52_En19 wire signed [52:0] add_temp; // sfix53_En19 wire signed [51:0] add_signext_2; // sfix52_En19 wire signed [51:0] add_signext_3; // sfix52_En19 wire signed [52:0] add_temp_1; // sfix53_En19 wire signed [51:0] add_signext_4; // sfix52_En19 wire signed [51:0] add_signext_5; // sfix52_En19 wire signed [52:0] add_temp_2; // sfix53_En19 wire signed [51:0] add_signext_6; // sfix52_En19 wire signed [51:0] add_signext_7; // sfix52_En19 wire signed [52:0] add_temp_3; // sfix53_En19 wire signed [51:0] add_signext_8; // sfix52_En19 wire signed [51:0] add_signext_9; // sfix52_En19 wire signed [52:0] add_temp_4; // sfix53_En19 wire signed [51:0] add_signext_10; // sfix52_En19 wire signed [51:0] add_signext_11; // sfix52_En19 wire signed [52:0] add_temp_5; // sfix53_En19 wire signed [51:0] add_signext_12; // sfix52_En19 wire signed [51:0] add_signext_13; // sfix52_En19 wire signed [52:0] add_temp_6; // sfix53_En19 wire signed [51:0] add_signext_14; // sfix52_En19 wire signed [51:0] add_signext_15; // sfix52_En19 wire signed [52:0] add_temp_7; // sfix53_En19 wire signed [51:0] add_signext_16; // sfix52_En19 wire signed [51:0] add_signext_17; // sfix52_En19 wire signed [52:0] add_temp_8; // sfix53_En19 wire signed [51:0] add_signext_18; // sfix52_En19 wire signed [51:0] add_signext_19; // sfix52_En19 wire signed [52:0] add_temp_9; // sfix53_En19 wire signed [51:0] add_signext_20; // sfix52_En19 wire signed [51:0] add_signext_21; // sfix52_En19 wire signed [52:0] add_temp_10; // sfix53_En19 wire signed [51:0] add_signext_22; // sfix52_En19 wire signed [51:0] add_signext_23; // sfix52_En19 wire signed [52:0] add_temp_11; // sfix53_En19 wire signed [51:0] add_signext_24; // sfix52_En19 wire signed [51:0] add_signext_25; // sfix52_En19 wire signed [52:0] add_temp_12; // sfix53_En19 wire signed [51:0] add_signext_26; // sfix52_En19 wire signed [51:0] add_signext_27; // sfix52_En19 wire signed [52:0] add_temp_13; // sfix53_En19 wire signed [51:0] add_signext_28; // sfix52_En19 wire signed [51:0] add_signext_29; // sfix52_En19 wire signed [52:0] add_temp_14; // sfix53_En19 wire signed [51:0] add_signext_30; // sfix52_En19 wire signed [51:0] add_signext_31; // sfix52_En19 wire signed [52:0] add_temp_15; // sfix53_En19 wire signed [51:0] add_signext_32; // sfix52_En19 wire signed [51:0] add_signext_33; // sfix52_En19 wire signed [52:0] add_temp_16; // sfix53_En19 wire signed [51:0] add_signext_34; // sfix52_En19 wire signed [51:0] add_signext_35; // sfix52_En19 wire signed [52:0] add_temp_17; // sfix53_En19 wire signed [51:0] add_signext_36; // sfix52_En19 wire signed [51:0] add_signext_37; // sfix52_En19 wire signed [52:0] add_temp_18; // sfix53_En19 wire signed [51:0] add_signext_38; // sfix52_En19 wire signed [51:0] add_signext_39; // sfix52_En19 wire signed [52:0] add_temp_19; // sfix53_En19 wire signed [31:0] output_typeconvert; // sfix32_En19 reg signed [31:0] output_register; // sfix32_En19 // Block Statements always @ (posedge clk or posedge reset) begin: input_reg_process if (reset == 1'b1) begin inputreg <= 0; end else begin if (clk_enable == 1'b1) begin inputreg <= filter_in; end end end // input_reg_process always @ (posedge clk or posedge reset) begin: Delay_Pipeline_process if (reset == 1'b1) begin delay_pipeline[0] <= 0; delay_pipeline[1] <= 0; delay_pipeline[2] <= 0; delay_pipeline[3] <= 0; delay_pipeline[4] <= 0; delay_pipeline[5] <= 0; delay_pipeline[6] <= 0; delay_pipeline[7] <= 0; delay_pipeline[8] <= 0; delay_pipeline[9] <= 0; delay_pipeline[10] <= 0; delay_pipeline[11] <= 0; delay_pipeline[12] <= 0; delay_pipeline[13] <= 0; delay_pipeline[14] <= 0; delay_pipeline[15] <= 0; delay_pipeline[16] <= 0; delay_pipeline[17] <= 0; delay_pipeline[18] <= 0; delay_pipeline[19] <= 0; end else begin if (clk_enable == 1'b1) begin delay_pipeline[0] <= sumvector[0]; delay_pipeline[1] <= sumvector[1]; delay_pipeline[2] <= sumvector[2]; delay_pipeline[3] <= sumvector[3]; delay_pipeline[4] <= sumvector[4]; delay_pipeline[5] <= sumvector[5]; delay_pipeline[6] <= sumvector[6]; delay_pipeline[7] <= sumvector[7]; delay_pipeline[8] <= sumvector[8]; delay_pipeline[9] <= sumvector[9]; delay_pipeline[10] <= sumvector[10]; delay_pipeline[11] <= sumvector[11]; delay_pipeline[12] <= sumvector[12]; delay_pipeline[13] <= sumvector[13]; delay_pipeline[14] <= sumvector[14]; delay_pipeline[15] <= sumvector[15]; delay_pipeline[16] <= sumvector[16]; delay_pipeline[17] <= sumvector[17]; delay_pipeline[18] <= sumvector[18]; delay_pipeline[19] <= sumvector[19]; end end end // Delay_Pipeline_process assign mul_temp = inputreg * coeff11; assign product11 = mul_temp[50:0]; assign mul_temp_1 = inputreg * coeff12; assign product12 = mul_temp_1[50:0]; assign mul_temp_2 = inputreg * coeff13; assign product13 = mul_temp_2[50:0]; assign mul_temp_3 = inputreg * coeff14; assign product14 = mul_temp_3[50:0]; assign mul_temp_4 = inputreg * coeff15; assign product15 = mul_temp_4[50:0]; assign mul_temp_5 = inputreg * coeff16; assign product16 = mul_temp_5[50:0]; assign mul_temp_6 = inputreg * coeff17; assign product17 = mul_temp_6[50:0]; assign mul_temp_7 = inputreg * coeff18; assign product18 = mul_temp_7[50:0]; assign mul_temp_8 = inputreg * coeff19; assign product19 = mul_temp_8[50:0]; assign mul_temp_9 = inputreg * coeff20; assign product20 = mul_temp_9[50:0]; assign mul_temp_10 = inputreg * coeff21; assign product21 = mul_temp_10[50:0]; assign add_signext = $signed({{1{product21[50]}}, product21}); assign add_signext_1 = delay_pipeline[0]; assign add_temp = add_signext + add_signext_1; assign finalsum = add_temp[51:0]; assign add_signext_2 = $signed({{1{product20[50]}}, product20}); assign add_signext_3 = delay_pipeline[1]; assign add_temp_1 = add_signext_2 + add_signext_3; assign sumvector[0] = add_temp_1[51:0]; assign add_signext_4 = $signed({{1{product19[50]}}, product19}); assign add_signext_5 = delay_pipeline[2]; assign add_temp_2 = add_signext_4 + add_signext_5; assign sumvector[1] = add_temp_2[51:0]; assign add_signext_6 = $signed({{1{product18[50]}}, product18}); assign add_signext_7 = delay_pipeline[3]; assign add_temp_3 = add_signext_6 + add_signext_7; assign sumvector[2] = add_temp_3[51:0]; assign add_signext_8 = $signed({{1{product17[50]}}, product17}); assign add_signext_9 = delay_pipeline[4]; assign add_temp_4 = add_signext_8 + add_signext_9; assign sumvector[3] = add_temp_4[51:0]; assign add_signext_10 = $signed({{1{product16[50]}}, product16}); assign add_signext_11 = delay_pipeline[5]; assign add_temp_5 = add_signext_10 + add_signext_11; assign sumvector[4] = add_temp_5[51:0]; assign add_signext_12 = $signed({{1{product15[50]}}, product15}); assign add_signext_13 = delay_pipeline[6]; assign add_temp_6 = add_signext_12 + add_signext_13; assign sumvector[5] = add_temp_6[51:0]; assign add_signext_14 = $signed({{1{product14[50]}}, product14}); assign add_signext_15 = delay_pipeline[7]; assign add_temp_7 = add_signext_14 + add_signext_15; assign sumvector[6] = add_temp_7[51:0]; assign add_signext_16 = $signed({{1{product13[50]}}, product13}); assign add_signext_17 = delay_pipeline[8]; assign add_temp_8 = add_signext_16 + add_signext_17; assign sumvector[7] = add_temp_8[51:0]; assign add_signext_18 = $signed({{1{product12[50]}}, product12}); assign add_signext_19 = delay_pipeline[9]; assign add_temp_9 = add_signext_18 + add_signext_19; assign sumvector[8] = add_temp_9[51:0]; assign add_signext_20 = $signed({{1{product11[50]}}, product11}); assign add_signext_21 = delay_pipeline[10]; assign add_temp_10 = add_signext_20 + add_signext_21; assign sumvector[9] = add_temp_10[51:0]; assign add_signext_22 = $signed({{1{product12[50]}}, product12}); assign add_signext_23 = delay_pipeline[11]; assign add_temp_11 = add_signext_22 + add_signext_23; assign sumvector[10] = add_temp_11[51:0]; assign add_signext_24 = $signed({{1{product13[50]}}, product13}); assign add_signext_25 = delay_pipeline[12]; assign add_temp_12 = add_signext_24 + add_signext_25; assign sumvector[11] = add_temp_12[51:0]; assign add_signext_26 = $signed({{1{product14[50]}}, product14}); assign add_signext_27 = delay_pipeline[13]; assign add_temp_13 = add_signext_26 + add_signext_27; assign sumvector[12] = add_temp_13[51:0]; assign add_signext_28 = $signed({{1{product15[50]}}, product15}); assign add_signext_29 = delay_pipeline[14]; assign add_temp_14 = add_signext_28 + add_signext_29; assign sumvector[13] = add_temp_14[51:0]; assign add_signext_30 = $signed({{1{product16[50]}}, product16}); assign add_signext_31 = delay_pipeline[15]; assign add_temp_15 = add_signext_30 + add_signext_31; assign sumvector[14] = add_temp_15[51:0]; assign add_signext_32 = $signed({{1{product17[50]}}, product17}); assign add_signext_33 = delay_pipeline[16]; assign add_temp_16 = add_signext_32 + add_signext_33; assign sumvector[15] = add_temp_16[51:0]; assign add_signext_34 = $signed({{1{product18[50]}}, product18}); assign add_signext_35 = delay_pipeline[17]; assign add_temp_17 = add_signext_34 + add_signext_35; assign sumvector[16] = add_temp_17[51:0]; assign add_signext_36 = $signed({{1{product19[50]}}, product19}); assign add_signext_37 = delay_pipeline[18]; assign add_temp_18 = add_signext_36 + add_signext_37; assign sumvector[17] = add_temp_18[51:0]; assign add_signext_38 = $signed({{1{product20[50]}}, product20}); assign add_signext_39 = delay_pipeline[19]; assign add_temp_19 = add_signext_38 + add_signext_39; assign sumvector[18] = add_temp_19[51:0]; assign sumvector[19] = $signed({{1{product21[50]}}, product21}); assign output_typeconvert = finalsum[31:0]; always @ (posedge clk or posedge reset) begin: output_register_process if (reset == 1'b1) begin output_register <= 0; end else begin if (clk_enable == 1'b1) begin output_register <= output_typeconvert; end end end // output_register_process // Assignment Statements assign filter_out = output_register; endmodule // Hcfirt
Posted by Rick Lyons May 22, 2005
On Wed, 18 May 2005 15:41:06 -0400, "Steve Conahan"
<Steve.Conahan@mathworks.com> wrote:

>"Rick Lyons" <R.Lyons@_BOGUS_ieee.org> wrote in message >news:428b4b55.1377594562@news.sf.sbcglobal.net... >> On Tue, 17 May 2005 17:23:41 -0400, "Steve Conahan" >> <Steve.Conahan@mathworks.com> wrote: >> >> (snipped) >>> >>>Hi Paul, >>> >>>There is a demo that is in the Filter Design Toolbox for MATLAB (Release >>>14, >>>Service Pack 2) that may help you. The demo file is named >>>ddcfilterchaindemo.m (see complete code below). It illustrates how to >>>design a similar DDC system for GSM. It looks like a very similar example >>>for what you are interested in doing (at least it could get you started). >>> >>>Also there is a similar "GSM Digital Downconverter" Simulink demo that >>>ships >>>with the Signal Processing Blockset product. >>> >>>Cheers, >>>Steve Conahan >>>Signal Processing and Communications Development >>>The MathWorks, Inc. >>> >>>P.S. Here is the complete M code for the demo: >>> >> >> (MATLAB code snipped) >> >> Hello Steve, >> >> I was tickled that you posted that code. >> >> However, trying to run it failed because >> I don't have a "called" routine titled >> "mfilt.cicdecim". >> >> Any chance you could provide that >> "mfilt.cicdecim" code? >> >> Thanks, >> [-Rick-] >> I'm just being greedy. :-) >> > >Hi Rick, > >Our Filter Design Toolbox MFILT multirate filter object code is not open >source. ;-) > >However, as a friendly gesture, I have included below some >close/equivalent/similar MATLAB fixed-point M code that can be used to do >CIC decimation filtering. This code may explain some of the lower-level >fixed-point arithmetic that you are interested in simulating. > >(Note that the code below uses fixed-point arithmetic in MATLAB, and hence >requires the Fixed-Point Toolbox but it does not use Filter Design Toolbox >MFILT objects). > >Cheers, >Steve
Hi Steve, Thanks VERY MUCH for sharing! [-Rick-]
Posted by Paul Solomon May 21, 2005
Hi Brian,

Wow, that is great, reading that verilog code has helped heaps and it 
cleared up where I was going wrong
with my CIC filter.. I just needed to add a few signed keywords and handle 
the signed extension with the
$signed cast operator.

Thank you very much..

Is there any chance you could do the same and post the code for a FIR filter 
as well as I am having a similar
problem now trying to implement the compensating FIR filter that should come 
next..

the filter is designed as follows...

cfir = firceqrip(20, 0.16, [5.7565e-4 0.000001], 'passedge','invsinc', [1 
4])

cfir =

  Columns 1 through 8

   -0.0006   -0.0026   -0.0016    0.0123    0.0287 
 0.0004   -0.0865   -0.1192

  Columns 9 through 16

    0.0502    0.3593    0.5200    0.3593    0.0502   -0.1192   -0.0865 
0.0004

  Columns 17 through 21

    0.0287    0.0123   -0.0016   -0.0026   -0.0006

I was planning on using ~20 bits to represent the co-effecients and have a 
32bit in - 32 bit out filter for now.

If you can easily run this in matlab and post the FIR code I would greatly 
appreciate it!

Regards,

Paul Solomon


<brian.ogilvie@mathworks.com> wrote in message 
news:u64xdhjht.fsf@mathworks.com...
> "Paul Solomon" <psolomon@tpg.com.au> writes: > >> Hi Guys, >> >> Ok, I managed to get the simulation done that I was happy with in Matlab >> and >> designed a conpensating >> FIR filter and it all looks good in matlab.. I have not started moving >> this >> stuff to verilog for the FPGA >> and I have had a bit of trouble (probably as my verilog is rusty more >> than >> anything else) >> ... >> The CIC filter I am trying to implement here is a 4 stage M = 1, filter >> with >> a decimation rate of 64. > > Hi Paul, > > If you get a trial of Filter Design Toolbox and Filter Design HDL > Coder, you could just do the following in MATLAB: > > Hx = mfilt.cicdecim(64,1,4) > Hx.inputWordLength = 30; > Hx.inputFracLength = 0; > Hx.outputWordLength = 32; > generatehdl(Hx,'targetlanguage','verilog'); > > > Notes: Adding input and output registers is the default for > generatehdl, but these registers are optional. CIC bit widths were > chosen automatically and are shown in the comments in the Verilog > file below; the binary points are notational and do not change the > algorithm until the quantizer at the output of the filter where > based on your 32-bit output, one bit is truncated (it can optionally > be rounded in various ways). The single clock mode shown below is > the default, but a two-clock interface can be generated as well. > You can add your inverse sinc FIR filter and cascade it with the CIC > and generate Verilog for both. You can also automatically generate > a Verilog testbench to verify that the generated Verilog filter is > working correcly. > > I hope this helps! > > Here is the Verilog: > > // ------------------------------------------------------------- > // > // Module: Hx > // > // Generated by MATLAB(R) 7.1 and the Filter Design HDL Coder 1.3. > // > // Generated on: 2005-05-20 13:34:06 > // > // ------------------------------------------------------------- > > // ------------------------------------------------------------- > // HDL Code Generation Options: > // > // TargetLanguage: Verilog > // Name: Hx > // CastBeforeSum: On > // > // Filter Settings: > // > // Discrete-Time FIR Multirate Filter (real) > // ----------------------------------------- > // Filter Structure : Cascaded Integrator-Comb Decimator > // Decimation Factor : 64 > // Differential Delay : 1 > // Number of Sections : 4 > // Stable : Yes > // Linear Phase : Yes (Type 1) > // > // Input : s30,0 > // Output : s32,-21 > // Filter Internals : Minimum Word Lengths > // Integrator Section 1 : s53,0 > // Integrator Section 2 : s48,-5 > // Integrator Section 3 : s43,-10 > // Integrator Section 4 : s38,-15 > // Comb Section 1 : s36,-17 > // Comb Section 2 : s35,-18 > // Comb Section 3 : s34,-19 > // Comb Section 4 : s33,-20 > // ------------------------------------------------------------- > > `timescale 1 ns / 1 ns > > module Hx > ( > clk, > clk_enable, > reset, > filter_in, > filter_out, > ce_out > ); > > input clk; > input clk_enable; > input reset; > input signed [29:0] filter_in; //sfix30 > output signed [31:0] filter_out; //sfix32_E21 > output ce_out; > > //////////////////////////////////////////////////////////////// > //Module Architecture: Hx > //////////////////////////////////////////////////////////////// > // Local Functions > // Type Definitions > // Constants > // Signals > reg [5:0] cur_count; // ufix6 > wire current_count; // boolean > reg ce_out_reg; // boolean > // > reg signed [29:0] input_register; // sfix30 > // -- Section 1 Signals > wire signed [29:0] section_in1; // sfix30 > wire signed [52:0] section_cast1; // sfix53 > wire signed [52:0] sum1; // sfix53 > reg signed [52:0] section_out1; // sfix53 > wire signed [52:0] add_cast; // sfix53 > wire signed [52:0] add_cast_1; // sfix53 > wire signed [53:0] add_temp; // sfix54 > // -- Section 2 Signals > wire signed [52:0] section_in2; // sfix53 > wire signed [47:0] section_cast2; // sfix48_E5 > wire signed [47:0] sum2; // sfix48_E5 > reg signed [47:0] section_out2; // sfix48_E5 > wire signed [47:0] add_cast_2; // sfix48_E5 > wire signed [47:0] add_cast_3; // sfix48_E5 > wire signed [48:0] add_temp_1; // sfix49_E5 > // -- Section 3 Signals > wire signed [47:0] section_in3; // sfix48_E5 > wire signed [42:0] section_cast3; // sfix43_E10 > wire signed [42:0] sum3; // sfix43_E10 > reg signed [42:0] section_out3; // sfix43_E10 > wire signed [42:0] add_cast_4; // sfix43_E10 > wire signed [42:0] add_cast_5; // sfix43_E10 > wire signed [43:0] add_temp_2; // sfix44_E10 > // -- Section 4 Signals > wire signed [42:0] section_in4; // sfix43_E10 > wire signed [37:0] section_cast4; // sfix38_E15 > wire signed [37:0] sum4; // sfix38_E15 > reg signed [37:0] section_out4; // sfix38_E15 > wire signed [37:0] add_cast_6; // sfix38_E15 > wire signed [37:0] add_cast_7; // sfix38_E15 > wire signed [38:0] add_temp_3; // sfix39_E15 > // -- Section 5 Signals > wire signed [37:0] section_in5; // sfix38_E15 > wire signed [35:0] section_cast5; // sfix36_E17 > reg signed [35:0] diff1; // sfix36_E17 > wire signed [35:0] section_out5; // sfix36_E17 > wire signed [35:0] sub_cast; // sfix36_E17 > wire signed [35:0] sub_cast_1; // sfix36_E17 > wire signed [36:0] sub_temp; // sfix37_E17 > // -- Section 6 Signals > wire signed [35:0] section_in6; // sfix36_E17 > wire signed [34:0] section_cast6; // sfix35_E18 > reg signed [34:0] diff2; // sfix35_E18 > wire signed [34:0] section_out6; // sfix35_E18 > wire signed [34:0] sub_cast_2; // sfix35_E18 > wire signed [34:0] sub_cast_3; // sfix35_E18 > wire signed [35:0] sub_temp_1; // sfix36_E18 > // -- Section 7 Signals > wire signed [34:0] section_in7; // sfix35_E18 > wire signed [33:0] section_cast7; // sfix34_E19 > reg signed [33:0] diff3; // sfix34_E19 > wire signed [33:0] section_out7; // sfix34_E19 > wire signed [33:0] sub_cast_4; // sfix34_E19 > wire signed [33:0] sub_cast_5; // sfix34_E19 > wire signed [34:0] sub_temp_2; // sfix35_E19 > // -- Section 8 Signals > wire signed [33:0] section_in8; // sfix34_E19 > wire signed [32:0] section_cast8; // sfix33_E20 > reg signed [32:0] diff4; // sfix33_E20 > wire signed [32:0] section_out8; // sfix33_E20 > wire signed [32:0] sub_cast_6; // sfix33_E20 > wire signed [32:0] sub_cast_7; // sfix33_E20 > wire signed [33:0] sub_temp_3; // sfix34_E20 > wire signed [31:0] output_typeconvert; // sfix32_E21 > // > reg signed [31:0] output_register; // sfix32_E21 > > // Block Statements > // ------------------ CE Output Generation ------------------ > > always @ (posedge clk or posedge reset) > begin: ce_output > if (reset == 1'b1) begin > cur_count <= 0; > end > else begin > if (clk_enable == 1'b1) begin > if (cur_count == 63) begin > cur_count <= 0; > end > else begin > cur_count <= cur_count + 1; > end > end > end > end // ce_output > > assign current_count = (cur_count == 1 && clk_enable == 1'b1)? 1 : 0; > > // ------------------ CE Output Register ------------------ > > always @ (posedge clk or posedge reset) > begin: ce_output_register > if (reset == 1'b1) begin > ce_out_reg <= 1'b0; > end > else begin > ce_out_reg <= current_count; > end > end // ce_output_register > > // ------------------ Input Register ------------------ > > always @ (posedge clk or posedge reset) > begin: input_reg_process > if (reset == 1'b1) begin > input_register <= 0; > end > else begin > if (clk_enable == 1'b1) begin > input_register <= filter_in; > end > end > end // input_reg_process > > // ------------------ Section # 1 : Integrator ------------------ > > assign section_in1 = input_register; > > assign section_cast1 = $signed({{23{section_in1[29]}}, section_in1}); > > assign add_cast = section_cast1; > assign add_cast_1 = section_out1; > assign add_temp = add_cast + add_cast_1; > assign sum1 = add_temp[52:0]; > > always @ (posedge clk or posedge reset) > begin: integrator_delay_section1 > if (reset == 1'b1) begin > section_out1 <= 0; > end > else begin > if (clk_enable == 1'b1) begin > section_out1 <= sum1; > end > end > end // integrator_delay_section1 > > // ------------------ Section # 2 : Integrator ------------------ > > assign section_in2 = section_out1; > > assign section_cast2 = section_in2[52:5]; > > assign add_cast_2 = section_cast2; > assign add_cast_3 = section_out2; > assign add_temp_1 = add_cast_2 + add_cast_3; > assign sum2 = add_temp_1[47:0]; > > always @ (posedge clk or posedge reset) > begin: integrator_delay_section2 > if (reset == 1'b1) begin > section_out2 <= 0; > end > else begin > if (clk_enable == 1'b1) begin > section_out2 <= sum2; > end > end > end // integrator_delay_section2 > > // ------------------ Section # 3 : Integrator ------------------ > > assign section_in3 = section_out2; > > assign section_cast3 = section_in3[47:5]; > > assign add_cast_4 = section_cast3; > assign add_cast_5 = section_out3; > assign add_temp_2 = add_cast_4 + add_cast_5; > assign sum3 = add_temp_2[42:0]; > > always @ (posedge clk or posedge reset) > begin: integrator_delay_section3 > if (reset == 1'b1) begin > section_out3 <= 0; > end > else begin > if (clk_enable == 1'b1) begin > section_out3 <= sum3; > end > end > end // integrator_delay_section3 > > // ------------------ Section # 4 : Integrator ------------------ > > assign section_in4 = section_out3; > > assign section_cast4 = section_in4[42:5]; > > assign add_cast_6 = section_cast4; > assign add_cast_7 = section_out4; > assign add_temp_3 = add_cast_6 + add_cast_7; > assign sum4 = add_temp_3[37:0]; > > always @ (posedge clk or posedge reset) > begin: integrator_delay_section4 > if (reset == 1'b1) begin > section_out4 <= 0; > end > else begin > if (clk_enable == 1'b1) begin > section_out4 <= sum4; > end > end > end // integrator_delay_section4 > > // ------------------ Section # 5 : Comb ------------------ > > assign section_in5 = section_out4; > > assign section_cast5 = section_in5[37:2]; > > assign sub_cast = section_cast5; > assign sub_cast_1 = diff1; > assign sub_temp = sub_cast - sub_cast_1; > assign section_out5 = sub_temp[35:0]; > > always @ (posedge clk or posedge reset) > begin: comb_delay_section5 > if (reset == 1'b1) begin > diff1 <= 0; > end > else begin > if (current_count == 1'b1) begin > diff1 <= section_cast5; > end > end > end // comb_delay_section5 > > // ------------------ Section # 6 : Comb ------------------ > > assign section_in6 = section_out5; > > assign section_cast6 = section_in6[35:1]; > > assign sub_cast_2 = section_cast6; > assign sub_cast_3 = diff2; > assign sub_temp_1 = sub_cast_2 - sub_cast_3; > assign section_out6 = sub_temp_1[34:0]; > > always @ (posedge clk or posedge reset) > begin: comb_delay_section6 > if (reset == 1'b1) begin > diff2 <= 0; > end > else begin > if (current_count == 1'b1) begin > diff2 <= section_cast6; > end > end > end // comb_delay_section6 > > // ------------------ Section # 7 : Comb ------------------ > > assign section_in7 = section_out6; > > assign section_cast7 = section_in7[34:1]; > > assign sub_cast_4 = section_cast7; > assign sub_cast_5 = diff3; > assign sub_temp_2 = sub_cast_4 - sub_cast_5; > assign section_out7 = sub_temp_2[33:0]; > > always @ (posedge clk or posedge reset) > begin: comb_delay_section7 > if (reset == 1'b1) begin > diff3 <= 0; > end > else begin > if (current_count == 1'b1) begin > diff3 <= section_cast7; > end > end > end // comb_delay_section7 > > // ------------------ Section # 8 : Comb ------------------ > > assign section_in8 = section_out7; > > assign section_cast8 = section_in8[33:1]; > > assign sub_cast_6 = section_cast8; > assign sub_cast_7 = diff4; > assign sub_temp_3 = sub_cast_6 - sub_cast_7; > assign section_out8 = sub_temp_3[32:0]; > > always @ (posedge clk or posedge reset) > begin: comb_delay_section8 > if (reset == 1'b1) begin > diff4 <= 0; > end > else begin > if (current_count == 1'b1) begin > diff4 <= section_cast8; > end > end > end // comb_delay_section8 > > assign output_typeconvert = section_out8[32:1]; > > // ------------------ Output Register ------------------ > > always @ (posedge clk or posedge reset) > begin: output_reg_process > if (reset == 1'b1) begin > output_register <= 0; > end > else begin > if (current_count == 1'b1) begin > output_register <= output_typeconvert; > end > end > end // output_reg_process > > // Assignment Statements > assign ce_out = ce_out_reg; > assign filter_out = output_register; > endmodule // Hx > >
Posted by May 20, 2005
"Paul Solomon" <psolomon@tpg.com.au> writes:

> Hi Guys, > > Ok, I managed to get the simulation done that I was happy with in Matlab and > designed a conpensating > FIR filter and it all looks good in matlab.. I have not started moving this > stuff to verilog for the FPGA > and I have had a bit of trouble (probably as my verilog is rusty more than > anything else) > ... > The CIC filter I am trying to implement here is a 4 stage M = 1, filter with > a decimation rate of 64.
Hi Paul, If you get a trial of Filter Design Toolbox and Filter Design HDL Coder, you could just do the following in MATLAB: Hx = mfilt.cicdecim(64,1,4) Hx.inputWordLength = 30; Hx.inputFracLength = 0; Hx.outputWordLength = 32; generatehdl(Hx,'targetlanguage','verilog'); Notes: Adding input and output registers is the default for generatehdl, but these registers are optional. CIC bit widths were chosen automatically and are shown in the comments in the Verilog file below; the binary points are notational and do not change the algorithm until the quantizer at the output of the filter where based on your 32-bit output, one bit is truncated (it can optionally be rounded in various ways). The single clock mode shown below is the default, but a two-clock interface can be generated as well. You can add your inverse sinc FIR filter and cascade it with the CIC and generate Verilog for both. You can also automatically generate a Verilog testbench to verify that the generated Verilog filter is working correcly. I hope this helps! Here is the Verilog: // ------------------------------------------------------------- // // Module: Hx // // Generated by MATLAB(R) 7.1 and the Filter Design HDL Coder 1.3. // // Generated on: 2005-05-20 13:34:06 // // ------------------------------------------------------------- // ------------------------------------------------------------- // HDL Code Generation Options: // // TargetLanguage: Verilog // Name: Hx // CastBeforeSum: On // // Filter Settings: // // Discrete-Time FIR Multirate Filter (real) // ----------------------------------------- // Filter Structure : Cascaded Integrator-Comb Decimator // Decimation Factor : 64 // Differential Delay : 1 // Number of Sections : 4 // Stable : Yes // Linear Phase : Yes (Type 1) // // Input : s30,0 // Output : s32,-21 // Filter Internals : Minimum Word Lengths // Integrator Section 1 : s53,0 // Integrator Section 2 : s48,-5 // Integrator Section 3 : s43,-10 // Integrator Section 4 : s38,-15 // Comb Section 1 : s36,-17 // Comb Section 2 : s35,-18 // Comb Section 3 : s34,-19 // Comb Section 4 : s33,-20 // ------------------------------------------------------------- `timescale 1 ns / 1 ns module Hx ( clk, clk_enable, reset, filter_in, filter_out, ce_out ); input clk; input clk_enable; input reset; input signed [29:0] filter_in; //sfix30 output signed [31:0] filter_out; //sfix32_E21 output ce_out; //////////////////////////////////////////////////////////////// //Module Architecture: Hx //////////////////////////////////////////////////////////////// // Local Functions // Type Definitions // Constants // Signals reg [5:0] cur_count; // ufix6 wire current_count; // boolean reg ce_out_reg; // boolean // reg signed [29:0] input_register; // sfix30 // -- Section 1 Signals wire signed [29:0] section_in1; // sfix30 wire signed [52:0] section_cast1; // sfix53 wire signed [52:0] sum1; // sfix53 reg signed [52:0] section_out1; // sfix53 wire signed [52:0] add_cast; // sfix53 wire signed [52:0] add_cast_1; // sfix53 wire signed [53:0] add_temp; // sfix54 // -- Section 2 Signals wire signed [52:0] section_in2; // sfix53 wire signed [47:0] section_cast2; // sfix48_E5 wire signed [47:0] sum2; // sfix48_E5 reg signed [47:0] section_out2; // sfix48_E5 wire signed [47:0] add_cast_2; // sfix48_E5 wire signed [47:0] add_cast_3; // sfix48_E5 wire signed [48:0] add_temp_1; // sfix49_E5 // -- Section 3 Signals wire signed [47:0] section_in3; // sfix48_E5 wire signed [42:0] section_cast3; // sfix43_E10 wire signed [42:0] sum3; // sfix43_E10 reg signed [42:0] section_out3; // sfix43_E10 wire signed [42:0] add_cast_4; // sfix43_E10 wire signed [42:0] add_cast_5; // sfix43_E10 wire signed [43:0] add_temp_2; // sfix44_E10 // -- Section 4 Signals wire signed [42:0] section_in4; // sfix43_E10 wire signed [37:0] section_cast4; // sfix38_E15 wire signed [37:0] sum4; // sfix38_E15 reg signed [37:0] section_out4; // sfix38_E15 wire signed [37:0] add_cast_6; // sfix38_E15 wire signed [37:0] add_cast_7; // sfix38_E15 wire signed [38:0] add_temp_3; // sfix39_E15 // -- Section 5 Signals wire signed [37:0] section_in5; // sfix38_E15 wire signed [35:0] section_cast5; // sfix36_E17 reg signed [35:0] diff1; // sfix36_E17 wire signed [35:0] section_out5; // sfix36_E17 wire signed [35:0] sub_cast; // sfix36_E17 wire signed [35:0] sub_cast_1; // sfix36_E17 wire signed [36:0] sub_temp; // sfix37_E17 // -- Section 6 Signals wire signed [35:0] section_in6; // sfix36_E17 wire signed [34:0] section_cast6; // sfix35_E18 reg signed [34:0] diff2; // sfix35_E18 wire signed [34:0] section_out6; // sfix35_E18 wire signed [34:0] sub_cast_2; // sfix35_E18 wire signed [34:0] sub_cast_3; // sfix35_E18 wire signed [35:0] sub_temp_1; // sfix36_E18 // -- Section 7 Signals wire signed [34:0] section_in7; // sfix35_E18 wire signed [33:0] section_cast7; // sfix34_E19 reg signed [33:0] diff3; // sfix34_E19 wire signed [33:0] section_out7; // sfix34_E19 wire signed [33:0] sub_cast_4; // sfix34_E19 wire signed [33:0] sub_cast_5; // sfix34_E19 wire signed [34:0] sub_temp_2; // sfix35_E19 // -- Section 8 Signals wire signed [33:0] section_in8; // sfix34_E19 wire signed [32:0] section_cast8; // sfix33_E20 reg signed [32:0] diff4; // sfix33_E20 wire signed [32:0] section_out8; // sfix33_E20 wire signed [32:0] sub_cast_6; // sfix33_E20 wire signed [32:0] sub_cast_7; // sfix33_E20 wire signed [33:0] sub_temp_3; // sfix34_E20 wire signed [31:0] output_typeconvert; // sfix32_E21 // reg signed [31:0] output_register; // sfix32_E21 // Block Statements // ------------------ CE Output Generation ------------------ always @ (posedge clk or posedge reset) begin: ce_output if (reset == 1'b1) begin cur_count <= 0; end else begin if (clk_enable == 1'b1) begin if (cur_count == 63) begin cur_count <= 0; end else begin cur_count <= cur_count + 1; end end end end // ce_output assign current_count = (cur_count == 1 && clk_enable == 1'b1)? 1 : 0; // ------------------ CE Output Register ------------------ always @ (posedge clk or posedge reset) begin: ce_output_register if (reset == 1'b1) begin ce_out_reg <= 1'b0; end else begin ce_out_reg <= current_count; end end // ce_output_register // ------------------ Input Register ------------------ always @ (posedge clk or posedge reset) begin: input_reg_process if (reset == 1'b1) begin input_register <= 0; end else begin if (clk_enable == 1'b1) begin input_register <= filter_in; end end end // input_reg_process // ------------------ Section # 1 : Integrator ------------------ assign section_in1 = input_register; assign section_cast1 = $signed({{23{section_in1[29]}}, section_in1}); assign add_cast = section_cast1; assign add_cast_1 = section_out1; assign add_temp = add_cast + add_cast_1; assign sum1 = add_temp[52:0]; always @ (posedge clk or posedge reset) begin: integrator_delay_section1 if (reset == 1'b1) begin section_out1 <= 0; end else begin if (clk_enable == 1'b1) begin section_out1 <= sum1; end end end // integrator_delay_section1 // ------------------ Section # 2 : Integrator ------------------ assign section_in2 = section_out1; assign section_cast2 = section_in2[52:5]; assign add_cast_2 = section_cast2; assign add_cast_3 = section_out2; assign add_temp_1 = add_cast_2 + add_cast_3; assign sum2 = add_temp_1[47:0]; always @ (posedge clk or posedge reset) begin: integrator_delay_section2 if (reset == 1'b1) begin section_out2 <= 0; end else begin if (clk_enable == 1'b1) begin section_out2 <= sum2; end end end // integrator_delay_section2 // ------------------ Section # 3 : Integrator ------------------ assign section_in3 = section_out2; assign section_cast3 = section_in3[47:5]; assign add_cast_4 = section_cast3; assign add_cast_5 = section_out3; assign add_temp_2 = add_cast_4 + add_cast_5; assign sum3 = add_temp_2[42:0]; always @ (posedge clk or posedge reset) begin: integrator_delay_section3 if (reset == 1'b1) begin section_out3 <= 0; end else begin if (clk_enable == 1'b1) begin section_out3 <= sum3; end end end // integrator_delay_section3 // ------------------ Section # 4 : Integrator ------------------ assign section_in4 = section_out3; assign section_cast4 = section_in4[42:5]; assign add_cast_6 = section_cast4; assign add_cast_7 = section_out4; assign add_temp_3 = add_cast_6 + add_cast_7; assign sum4 = add_temp_3[37:0]; always @ (posedge clk or posedge reset) begin: integrator_delay_section4 if (reset == 1'b1) begin section_out4 <= 0; end else begin if (clk_enable == 1'b1) begin section_out4 <= sum4; end end end // integrator_delay_section4 // ------------------ Section # 5 : Comb ------------------ assign section_in5 = section_out4; assign section_cast5 = section_in5[37:2]; assign sub_cast = section_cast5; assign sub_cast_1 = diff1; assign sub_temp = sub_cast - sub_cast_1; assign section_out5 = sub_temp[35:0]; always @ (posedge clk or posedge reset) begin: comb_delay_section5 if (reset == 1'b1) begin diff1 <= 0; end else begin if (current_count == 1'b1) begin diff1 <= section_cast5; end end end // comb_delay_section5 // ------------------ Section # 6 : Comb ------------------ assign section_in6 = section_out5; assign section_cast6 = section_in6[35:1]; assign sub_cast_2 = section_cast6; assign sub_cast_3 = diff2; assign sub_temp_1 = sub_cast_2 - sub_cast_3; assign section_out6 = sub_temp_1[34:0]; always @ (posedge clk or posedge reset) begin: comb_delay_section6 if (reset == 1'b1) begin diff2 <= 0; end else begin if (current_count == 1'b1) begin diff2 <= section_cast6; end end end // comb_delay_section6 // ------------------ Section # 7 : Comb ------------------ assign section_in7 = section_out6; assign section_cast7 = section_in7[34:1]; assign sub_cast_4 = section_cast7; assign sub_cast_5 = diff3; assign sub_temp_2 = sub_cast_4 - sub_cast_5; assign section_out7 = sub_temp_2[33:0]; always @ (posedge clk or posedge reset) begin: comb_delay_section7 if (reset == 1'b1) begin diff3 <= 0; end else begin if (current_count == 1'b1) begin diff3 <= section_cast7; end end end // comb_delay_section7 // ------------------ Section # 8 : Comb ------------------ assign section_in8 = section_out7; assign section_cast8 = section_in8[33:1]; assign sub_cast_6 = section_cast8; assign sub_cast_7 = diff4; assign sub_temp_3 = sub_cast_6 - sub_cast_7; assign section_out8 = sub_temp_3[32:0]; always @ (posedge clk or posedge reset) begin: comb_delay_section8 if (reset == 1'b1) begin diff4 <= 0; end else begin if (current_count == 1'b1) begin diff4 <= section_cast8; end end end // comb_delay_section8 assign output_typeconvert = section_out8[32:1]; // ------------------ Output Register ------------------ always @ (posedge clk or posedge reset) begin: output_reg_process if (reset == 1'b1) begin output_register <= 0; end else begin if (current_count == 1'b1) begin output_register <= output_typeconvert; end end end // output_reg_process // Assignment Statements assign ce_out = ce_out_reg; assign filter_out = output_register; endmodule // Hx
Posted by Bhaskar Thiagarajan May 19, 2005
"Paul Solomon" <psolomon@tpg.com.au> wrote in message
news:428c9536@dnews.tpgi.com.au...
> Hi Guys, > > Ok, I managed to get the simulation done that I was happy with in Matlab
and
> designed a conpensating > FIR filter and it all looks good in matlab.. I have not started moving
this
> stuff to verilog for the FPGA > and I have had a bit of trouble (probably as my verilog is rusty more than > anything else) > > I wil post my verilog code here in case there are and verilog guru's > watching that may see what is wrong
Cross-posting to comp.arch.fpga might get you more responses/help. Our resident expert on this (Ray) is off writing a book and acting busy in general...perhaps there are others.
> instantly otherwise I will just keep plugging at it tonnorow. I have a > feelig that it may be a signed integer issue > i.e. something to do with casting from a 32 bit to a 54 bit not filling in > the trailing ones in the case of the negative input. > > Anyhow, when I run this on the hardware I just get an awful lot of noise
in
> the spectrum instead of a nice signal > which is what I have before filtering.
Have you tried simplifying your design (say fewer filters with fewer stages for debugging) and tapping off your signal at various points to see where things go bad?
> The CIC filter I am trying to implement here is a 4 stage M = 1, filter
with
> a decimation rate of 64. > > A 21 tap FIR filter seems to nicely clean up the passband if I put it > afterwards. > > I do have one big question weighing in my mind though, and that is how do > you deal with the bit widths that > are constantly growing. i.e., I only have 12 bit ADC input, however after > the multiply with the NCO I am up to 30 bits
Why? While it is nice to maintain all the precision if you can, the SNR of your input signal is only going to be so much. Filtering and decimation is going to lower your noise floor but I don't see 30 bits needed (that's approx 180dB of dynamic range!)
> then after the CIC I grow to 54 bits.. And after FIR it gets worse etc...
The CIC accumulator needs to be large for it to work right but the output can be rounded to your output precision.
> At the moment I have just taken the 14 MSB's to feed to my DAC (which is
how
> I am testing the output to see if it is ok) > However, I am not sure that this is the best method of doing this..
> Any Ideas on how to keep the bit widths down to a manageable size? > > Regards > > Paul Solomon > > module cic_filter(clk, in, clk_out, out); > > input clk; > > input [29:0] in; > > output clk_out; > > output [31:0] out; > > reg state; // 0 = hold, 1 = sample > > reg [5:0] count; > > > reg [31:0] x; > > > reg [53:0] int1; > > reg [53:0] int2; > > reg [53:0] int3; > > reg [53:0] int4; > > reg [53:0] int_out; > > reg [53:0] comb1; > > reg [53:0] comb2; > > reg [53:0] comb3; > > reg [53:0] comb4; > > reg [53:0] combd1; > > reg [53:0] combd2; > > reg [53:0] combd3; > > reg [53:0] combd4; > > reg clk2; > > > always @(negedge clk) begin > > if (~state) begin > > if (count < 63) begin > > state <= 1'b0; > > end else begin > > state <= 1'b1; > > end > > end else begin > > state <= 1'b0; > > end > > end > > > always @(posedge clk) begin > > x <= in; > > int1 <= int1 + x; > > int2 <= int2 + int1; > > int3 <= int3 + int2; > > int4 <= int4 + int3; > > if (state) begin > > count <= 6'b0; > > int_out <= int4; > > end else begin > > count <= count + 1; > > end > > > if ((count > 16) && (count < 32)) begin > > clk2 <= 1'b1; > > end else begin > > clk2 <= 1'b0; > > end > > end > > always @(posedge clk2) begin > > combd1 <= int_out; > > comb1 <= int_out - combd1; > > combd2 <= comb1; > > comb2 <= comb1 - combd2; > > combd3 <= comb2; > > comb3 <= comb2 - combd3; > > combd4 <= comb3; > > comb4 <= comb3 - combd4; > > end > > assign clk_out = clk2; > > assign out = comb4[53:22]; > > endmodule > > > "Bhaskar Thiagarajan" <bhaskart@deja.com> wrote in message > news:428b7038$0$79458$14726298@news.sunsite.dk... > > "Paul Solomon" <psolomon@tpg.com.au> wrote in message > > news:428add1a@dnews.tpgi.com.au... > >> Hi Bhaskar, > >> > >> thanks for this info, it has helped alot, and that article nicely > > explained > >> the finer details of > >> CIC that I was confused about. > >> > >> I am trying to do the design in matlab and am currently stalled as I do > > not > >> have the fixed point toolbox > >> that the filter design toolbox wants to do CIC filters.. I think that I > > have > >> now made a correct FIR correction > >> filter but it would be nice to be able to cascade this with a CIC
filter
> >> inmatlab and see the cumulative response. > > > > While a CIC filter is typically modeled (and implemented) in fixed
point,
> > I > > don't think you absolutely need the fixed point toolbox to do what you > > want. > > Either you can implement the fixed precision manually in your matlab
code
> > or > > go ahead and use double precision arithmetic to model it for now. What
is
> > of > > importance here is that you model the frequency response of the CIC > > correctly (since that is what you are trying to study)..esp to see if
your
> > FIR correction is doing it's job. The frequency response of the CIC is > > quite > > well defined (see references). So you should be able to stick that your > > current simulation and see what happens. (Yes, I know that it would > > certainly be a lot more convenient to take a canned solution from > > Mathworks > > and get this to happen but I can guarantee that you'll learn more this
way
> > and save a bunch of cash) > > > > Cheers > > Bhaskar > > > > Note - A CIC implementation takes advantage of fixed precision
arithmetic
> > to > > work right - so I suggest you *model* your CIC rather than implement it
in
> > matlab for your simulation. > > > > > >> So I think it will be a few days before I can report back sucsess, > >> however > > I > >> think I am on the right track now > >> thanks to your assistance. > >> > >> regards, > >> > >> Paul Solomon > >> > >> > >> "Bhaskar Thiagarajan" <bhaskart@deja.com> wrote in message > >> news:428a1b87$0$79456$14726298@news.sunsite.dk... > >> > "Tim Wescott" <tim@seemywebsite.com> wrote in message > >> > news:118jvijkhj28t22@corp.supernews.com... > >> >> Paul Solomon wrote: > >> >> > >> >> > Hi All, > >> >> > > >> >> > I am working on a project in which we are attempting to demod > > multiple > >> >> > (analog) FM radio stations in a FPGA. > >> >> > I have been trying to work out how to design the CIC / FIR filter > > pair > >> > in > >> >> > the DDC section of this design. > >> >> > >> >> This paragraph has put me into abbreviation overload. FM, FPGA and > >> >> FIR > >> >> all make sense to me -- what do CIC and DDC mean in this context? > >> > > >> > CIC - Cascaded Integrated Comb > >> > DDC - Digital Down Converter > >> > > >> > > >> >> > I have a input sampling rate of 80MSPS, which undersamples a clean > >> > spectrum > >> >> > of 88 - 108MHz i.e. the FM band. > >> >> > this should give me the FM band at 8 - 28MHz with an alias at 52 - > >> > 72MHz. > >> >> > > >> >> > I then take this input and mix with a NCO generated carrier at say > >> > 20.5MHz > >> >> > to try to pull out one of the stations. > >> >> > The output of the mixer needs to then be filtered to approx 200kHz > >> > bandwidth > >> >> > and decimated to maybe 800kSPS? > >> >> > >> >> Is it quadrature demodulation? If so 200kHz is strictly correct
only
> > if > >> >> you mean -100kHz to 100kHz. You could go out more than that if you > >> >> wanted to, but why? > >> >> > > >> >> > this is the part I am unsure of how to do.. I believe that I will > > need > >> >> > a > >> > CIC > >> >> > followed by a FIR however > >> >> > I am not sure the relevant paramaters of the CIC and how to set > >> >> > them, > >> >> > i.e. (decimation Rate) R = 128, but (stages)N = ?? and
(differential
> >> > delay)M > >> >> > = ??. > >> >> > >> >> Apparantly a CIC is some sort of a polyphase filter with decimation? > > If > >> >> so, why do you need a FIR filter at all? In fact if you were clever > > you > >> >> should be able to follow the quadrature demodulation with a > >> >> single-step > >> >> lowpass/decimation filter to get a nicely conditioned baseband
signal
> >> >> that you would then have to work on to extract the FM signal. > >> > > >> > A CIC is a box-car filter that (just google for lotsa references and > > very > >> > detailed explanations - Rick just had one of his artciles on this
very
> >> > topic > >> > in EE times I think) doesn't use any multipliers, supports large > >> > decimation > >> > ratios, works well in fixed point arithmentic. So these are excellent > >> > candiates for 'coarse' decimation blocks that need to be implemented
in
> >> > FPGAs. Since they are box-car to begin with, their frequency response > >> > is > >> > pretty bad - so they are typically followed by a FIR filter that does > > any > >> > 'fine' decimation that may be needed as well as correct for the > > amplitude > >> > droop in the pass-band caused by the CICs. > >> > > >> > Given Paul's system requirements, I would think that a single FIR > >> > (non-CIC) > >> > to get him from 80 Msps to 800ksps in one step wouldn't be easy. So
he
> > is > >> > correct in considering CICs in his design. > >> > > >> > Here is Rick's article for reference - Paul would be wise to read it > >> > before > >> > moving forward. > >> > http://www.embedded.com/showArticle.jhtml?articleID=160400592 > >> > > >> > Paul - it seems you are shooting for a decimation of about 100. I'd > >> > suggest > >> > a CIC decimation of say 64 and the rest can be handled by your final > > FIR. > >> > Rick's article discusses the trade-offs related to stages and > > differential > >> > delay choices for these filters. If you still aren't sure of what you > >> > need, > >> > ask again (with some background on what you don't get). > >> > > >> > Since the CIC filters' frequency response is known exactly, you can > >> > then > >> > create an 'inverse' of this response in the frequency domain and then > >> > perform an IFFT to get filter coeffs for your FIR filter that can > > correct > >> > for the CIC. > >> > Note that you probably want a combination FIR - one that will correct > > the > >> > CIC as well as provide filtering to remove images and good stop band > >> > attenuation for the spectrum of interest. So you'd need to combine
the
> >> > 2 > >> > responses together to get your filter coeffs. > >> > > >> > Cheers > >> > Bhaskar > >> > > >> >> > > >> >> > I have read Hogenauer and still feel none the wiser.. > >> >> > > >> >> > also once the filter parameters are decided, how do you design the > >> > following > >> >> > FIR filter to straighten up the passband?? > >> >> > > >> >> > Anyhow, Hopefully someone out there will be able to help. > >> >> > > >> >> > Cheers, > >> >> > > >> >> > Paul Solomon > >> >> > > >> >> > > >> >> > >> >> > >> >> -- > >> >> ------------------------------------------- > >> >> Tim Wescott > >> >> Wescott Design Services > >> >> http://www.wescottdesign.com > >> > > >> > > >> > >> > > > > > >
Posted by Tim Wescott May 19, 2005
Please bottom post.

Paul Solomon wrote:

> Hi Guys, > > Ok, I managed to get the simulation done that I was happy with in Matlab and > designed a conpensating > FIR filter and it all looks good in matlab.. I have not started moving this > stuff to verilog for the FPGA > and I have had a bit of trouble (probably as my verilog is rusty more than > anything else) > > I wil post my verilog code here in case there are and verilog guru's > watching that may see what is wrong > instantly otherwise I will just keep plugging at it tonnorow. I have a > feelig that it may be a signed integer issue > i.e. something to do with casting from a 32 bit to a 54 bit not filling in > the trailing ones in the case of the negative input. > > Anyhow, when I run this on the hardware I just get an awful lot of noise in > the spectrum instead of a nice signal > which is what I have before filtering. > > The CIC filter I am trying to implement here is a 4 stage M = 1, filter with > a decimation rate of 64. > > A 21 tap FIR filter seems to nicely clean up the passband if I put it > afterwards. > > I do have one big question weighing in my mind though, and that is how do > you deal with the bit widths that > are constantly growing. i.e., I only have 12 bit ADC input, however after > the multiply with the NCO I am up to 30 bits > then after the CIC I grow to 54 bits.. And after FIR it gets worse etc... > At the moment I have just taken the 14 MSB's to feed to my DAC (which is how > I am testing the output to see if it is ok) > However, I am not sure that this is the best method of doing this.. > > Any Ideas on how to keep the bit widths down to a manageable size? > > Regards > > Paul Solomon > > module cic_filter(clk, in, clk_out, out); > > input clk; > > input [29:0] in; > > output clk_out; > > output [31:0] out; > > reg state; // 0 = hold, 1 = sample > > reg [5:0] count; > > > reg [31:0] x; > > > reg [53:0] int1; > > reg [53:0] int2; > > reg [53:0] int3; > > reg [53:0] int4; > > reg [53:0] int_out; > > reg [53:0] comb1; > > reg [53:0] comb2; > > reg [53:0] comb3; > > reg [53:0] comb4; > > reg [53:0] combd1; > > reg [53:0] combd2; > > reg [53:0] combd3; > > reg [53:0] combd4; > > reg clk2; > > > always @(negedge clk) begin > > if (~state) begin > > if (count < 63) begin > > state <= 1'b0; > > end else begin > > state <= 1'b1; > > end > > end else begin > > state <= 1'b0; > > end > > end > > > always @(posedge clk) begin > > x <= in; > > int1 <= int1 + x; > > int2 <= int2 + int1; > > int3 <= int3 + int2; > > int4 <= int4 + int3; > > if (state) begin > > count <= 6'b0; > > int_out <= int4; > > end else begin > > count <= count + 1; > > end > > > if ((count > 16) && (count < 32)) begin > > clk2 <= 1'b1; > > end else begin > > clk2 <= 1'b0; > > end > > end > > always @(posedge clk2) begin > > combd1 <= int_out; > > comb1 <= int_out - combd1; > > combd2 <= comb1; > > comb2 <= comb1 - combd2; > > combd3 <= comb2; > > comb3 <= comb2 - combd3; > > combd4 <= comb3; > > comb4 <= comb3 - combd4; > > end > > assign clk_out = clk2; > > assign out = comb4[53:22]; > > endmodule >
Bit Widths: To keep bit widths to a manageable size you need to asses the number of "good" bits and keep those, while throwing away the dross. The number of bits can be a flexible quantity, depending on what you're trying to do. To really do it up right you draw up a block diagram of your system with noise injected anywhere you are planning to quantize. Then you find the transfer function from each quantization point to the output, and you find your sensitivity to noise vs. frequency at the output and ask "if the quantization noise were at the worst possible frequency it could be, would my output noise be higher than I could stand?". If the answer is yes, then you're quantizing too much. Various rules of thumb descend from this. If you're just keeping 14 bits, and you're doing it all with FIR filters, and you're not hacking bits off the top then you can probably just carry 16-20 bit intermediate values and be OK. This figure can vary however; I could certainly concieve of a control system with a 12-bit input that would require a 32-bit integrator and last-bit-dithering on the output to maintain DC accuracy. Verilog code: I don't see anything glaring, so I'll comment on your style instead. All the proffesional Verilog people I know would beat me up for clocking with clk2: they would want me to just gate the assignments instead. You _do_ have spaces and tabs availible, please indent for readability! If it were my code or I were adopting it I'd simulate it with a stimulus that exactly matches one that I could run through the Matlab simulation, and I'd compare the signals clock-by-clock with the Matlab results. This will, at least, tell you where your verilog code starts to diverge from your Matlab code. ------------------------------------------- Tim Wescott Wescott Design Services http://www.wescottdesign.com
Posted by Paul Solomon May 19, 2005
Hi Guys,

Ok, I managed to get the simulation done that I was happy with in Matlab and 
designed a conpensating
FIR filter and it all looks good in matlab.. I have not started moving this 
stuff to verilog for the FPGA
and I have had a bit of trouble (probably as my verilog is rusty more than 
anything else)

I wil post my verilog code here in case there are and verilog guru's 
watching that may see what is wrong
instantly otherwise I will just keep plugging at it tonnorow. I have a 
feelig that it may be a signed integer issue
i.e. something to do with casting from a 32 bit to a 54 bit not filling in 
the trailing ones in the case of the negative input.

Anyhow, when I run this on the hardware I just get an awful lot of noise in 
the spectrum instead of a nice signal
which is what I have before filtering.

The CIC filter I am trying to implement here is a 4 stage M = 1, filter with 
a decimation rate of 64.

A 21 tap FIR filter seems to nicely clean up the passband if I put it 
afterwards.

I do have one big question weighing in my mind though, and that is how do 
you deal with the bit widths that
are constantly growing. i.e., I only have 12 bit ADC input, however after 
the multiply with the NCO I am up to 30 bits
then after the CIC I grow to 54 bits.. And after FIR it gets worse etc...
At the moment I have just taken the 14 MSB's to feed to my DAC (which is how 
I am testing the output to see if it is ok)
However, I am not sure that this is the best method of doing this..

Any Ideas on how to keep the bit widths down to a manageable size?

Regards

Paul Solomon

module cic_filter(clk, in, clk_out, out);

input clk;

input [29:0] in;

output clk_out;

output [31:0] out;

reg state; // 0 = hold, 1 = sample

reg [5:0] count;


reg [31:0] x;


reg [53:0] int1;

reg [53:0] int2;

reg [53:0] int3;

reg [53:0] int4;

reg [53:0] int_out;

reg [53:0] comb1;

reg [53:0] comb2;

reg [53:0] comb3;

reg [53:0] comb4;

reg [53:0] combd1;

reg [53:0] combd2;

reg [53:0] combd3;

reg [53:0] combd4;

reg clk2;


always @(negedge clk) begin

if (~state) begin

if (count < 63) begin

state <= 1'b0;

end else begin

state <= 1'b1;

end

end else begin

state <= 1'b0;

end

end


always @(posedge clk) begin

x <= in;

int1 <= int1 + x;

int2 <= int2 + int1;

int3 <= int3 + int2;

int4 <= int4 + int3;

if (state) begin

count <= 6'b0;

int_out <= int4;

end else begin

count <= count + 1;

end


if ((count > 16) && (count < 32)) begin

clk2 <= 1'b1;

end else begin

clk2 <= 1'b0;

end

end

always @(posedge clk2) begin

combd1 <= int_out;

comb1 <= int_out - combd1;

combd2 <= comb1;

comb2 <= comb1 - combd2;

combd3 <= comb2;

comb3 <= comb2 - combd3;

combd4 <= comb3;

comb4 <= comb3 - combd4;

end

assign clk_out = clk2;

assign out = comb4[53:22];

endmodule


"Bhaskar Thiagarajan" <bhaskart@deja.com> wrote in message 
news:428b7038$0$79458$14726298@news.sunsite.dk...
> "Paul Solomon" <psolomon@tpg.com.au> wrote in message > news:428add1a@dnews.tpgi.com.au... >> Hi Bhaskar, >> >> thanks for this info, it has helped alot, and that article nicely > explained >> the finer details of >> CIC that I was confused about. >> >> I am trying to do the design in matlab and am currently stalled as I do > not >> have the fixed point toolbox >> that the filter design toolbox wants to do CIC filters.. I think that I > have >> now made a correct FIR correction >> filter but it would be nice to be able to cascade this with a CIC filter >> inmatlab and see the cumulative response. > > While a CIC filter is typically modeled (and implemented) in fixed point, > I > don't think you absolutely need the fixed point toolbox to do what you > want. > Either you can implement the fixed precision manually in your matlab code > or > go ahead and use double precision arithmetic to model it for now. What is > of > importance here is that you model the frequency response of the CIC > correctly (since that is what you are trying to study)..esp to see if your > FIR correction is doing it's job. The frequency response of the CIC is > quite > well defined (see references). So you should be able to stick that your > current simulation and see what happens. (Yes, I know that it would > certainly be a lot more convenient to take a canned solution from > Mathworks > and get this to happen but I can guarantee that you'll learn more this way > and save a bunch of cash) > > Cheers > Bhaskar > > Note - A CIC implementation takes advantage of fixed precision arithmetic > to > work right - so I suggest you *model* your CIC rather than implement it in > matlab for your simulation. > > >> So I think it will be a few days before I can report back sucsess, >> however > I >> think I am on the right track now >> thanks to your assistance. >> >> regards, >> >> Paul Solomon >> >> >> "Bhaskar Thiagarajan" <bhaskart@deja.com> wrote in message >> news:428a1b87$0$79456$14726298@news.sunsite.dk... >> > "Tim Wescott" <tim@seemywebsite.com> wrote in message >> > news:118jvijkhj28t22@corp.supernews.com... >> >> Paul Solomon wrote: >> >> >> >> > Hi All, >> >> > >> >> > I am working on a project in which we are attempting to demod > multiple >> >> > (analog) FM radio stations in a FPGA. >> >> > I have been trying to work out how to design the CIC / FIR filter > pair >> > in >> >> > the DDC section of this design. >> >> >> >> This paragraph has put me into abbreviation overload. FM, FPGA and >> >> FIR >> >> all make sense to me -- what do CIC and DDC mean in this context? >> > >> > CIC - Cascaded Integrated Comb >> > DDC - Digital Down Converter >> > >> > >> >> > I have a input sampling rate of 80MSPS, which undersamples a clean >> > spectrum >> >> > of 88 - 108MHz i.e. the FM band. >> >> > this should give me the FM band at 8 - 28MHz with an alias at 52 - >> > 72MHz. >> >> > >> >> > I then take this input and mix with a NCO generated carrier at say >> > 20.5MHz >> >> > to try to pull out one of the stations. >> >> > The output of the mixer needs to then be filtered to approx 200kHz >> > bandwidth >> >> > and decimated to maybe 800kSPS? >> >> >> >> Is it quadrature demodulation? If so 200kHz is strictly correct only > if >> >> you mean -100kHz to 100kHz. You could go out more than that if you >> >> wanted to, but why? >> >> > >> >> > this is the part I am unsure of how to do.. I believe that I will > need >> >> > a >> > CIC >> >> > followed by a FIR however >> >> > I am not sure the relevant paramaters of the CIC and how to set >> >> > them, >> >> > i.e. (decimation Rate) R = 128, but (stages)N = ?? and (differential >> > delay)M >> >> > = ??. >> >> >> >> Apparantly a CIC is some sort of a polyphase filter with decimation? > If >> >> so, why do you need a FIR filter at all? In fact if you were clever > you >> >> should be able to follow the quadrature demodulation with a >> >> single-step >> >> lowpass/decimation filter to get a nicely conditioned baseband signal >> >> that you would then have to work on to extract the FM signal. >> > >> > A CIC is a box-car filter that (just google for lotsa references and > very >> > detailed explanations - Rick just had one of his artciles on this very >> > topic >> > in EE times I think) doesn't use any multipliers, supports large >> > decimation >> > ratios, works well in fixed point arithmentic. So these are excellent >> > candiates for 'coarse' decimation blocks that need to be implemented in >> > FPGAs. Since they are box-car to begin with, their frequency response >> > is >> > pretty bad - so they are typically followed by a FIR filter that does > any >> > 'fine' decimation that may be needed as well as correct for the > amplitude >> > droop in the pass-band caused by the CICs. >> > >> > Given Paul's system requirements, I would think that a single FIR >> > (non-CIC) >> > to get him from 80 Msps to 800ksps in one step wouldn't be easy. So he > is >> > correct in considering CICs in his design. >> > >> > Here is Rick's article for reference - Paul would be wise to read it >> > before >> > moving forward. >> > http://www.embedded.com/showArticle.jhtml?articleID=160400592 >> > >> > Paul - it seems you are shooting for a decimation of about 100. I'd >> > suggest >> > a CIC decimation of say 64 and the rest can be handled by your final > FIR. >> > Rick's article discusses the trade-offs related to stages and > differential >> > delay choices for these filters. If you still aren't sure of what you >> > need, >> > ask again (with some background on what you don't get). >> > >> > Since the CIC filters' frequency response is known exactly, you can >> > then >> > create an 'inverse' of this response in the frequency domain and then >> > perform an IFFT to get filter coeffs for your FIR filter that can > correct >> > for the CIC. >> > Note that you probably want a combination FIR - one that will correct > the >> > CIC as well as provide filtering to remove images and good stop band >> > attenuation for the spectrum of interest. So you'd need to combine the >> > 2 >> > responses together to get your filter coeffs. >> > >> > Cheers >> > Bhaskar >> > >> >> > >> >> > I have read Hogenauer and still feel none the wiser.. >> >> > >> >> > also once the filter parameters are decided, how do you design the >> > following >> >> > FIR filter to straighten up the passband?? >> >> > >> >> > Anyhow, Hopefully someone out there will be able to help. >> >> > >> >> > Cheers, >> >> > >> >> > Paul Solomon >> >> > >> >> > >> >> >> >> >> >> -- >> >> ------------------------------------------- >> >> Tim Wescott >> >> Wescott Design Services >> >> http://www.wescottdesign.com >> > >> > >> >> > >
Posted by Steve Conahan May 18, 2005
"Rick Lyons" <R.Lyons@_BOGUS_ieee.org> wrote in message 
news:428b4b55.1377594562@news.sf.sbcglobal.net...
> On Tue, 17 May 2005 17:23:41 -0400, "Steve Conahan" > <Steve.Conahan@mathworks.com> wrote: > > (snipped) >> >>Hi Paul, >> >>There is a demo that is in the Filter Design Toolbox for MATLAB (Release >>14, >>Service Pack 2) that may help you. The demo file is named >>ddcfilterchaindemo.m (see complete code below). It illustrates how to >>design a similar DDC system for GSM. It looks like a very similar example >>for what you are interested in doing (at least it could get you started). >> >>Also there is a similar "GSM Digital Downconverter" Simulink demo that >>ships >>with the Signal Processing Blockset product. >> >>Cheers, >>Steve Conahan >>Signal Processing and Communications Development >>The MathWorks, Inc. >> >>P.S. Here is the complete M code for the demo: >> > > (MATLAB code snipped) > > Hello Steve, > > I was tickled that you posted that code. > > However, trying to run it failed because > I don't have a "called" routine titled > "mfilt.cicdecim". > > Any chance you could provide that > "mfilt.cicdecim" code? > > Thanks, > [-Rick-] > I'm just being greedy. :-) >
Hi Rick, Our Filter Design Toolbox MFILT multirate filter object code is not open source. ;-) However, as a friendly gesture, I have included below some close/equivalent/similar MATLAB fixed-point M code that can be used to do CIC decimation filtering. This code may explain some of the lower-level fixed-point arithmetic that you are interested in simulating. (Note that the code below uses fixed-point arithmetic in MATLAB, and hence requires the Fixed-Point Toolbox but it does not use Filter Design Toolbox MFILT objects). Cheers, Steve function y = hcicdecimalgo(x,n,m,r,offset,inbits,infraclen,obits,bps,varargin) %HCICDECIMALGO Cascaded Integrator-Comb Decimator M-file. % Y = HCICDECIMALGO(X,N,M,R,OFFSET,INBITS,INFRACLEN,OBITS,BPS) filters the % data in X with N-section cascaded integrator-comb decimation filter with % M differential delays and a rate-change factor of R. X can be a % row/column vector or a matrix. % % Inputs: % N is the number of sections % M is the differential delay of the comb part % R is the decimation factor % OFFSET is the phase offset factor for downsampling % INBITS is the Word Length of the input signal. % INFRACLEN is the Fractional Length of the input signal % OBITS is the wordlength of the output signal % BPS can be a scalar or vector (of length 2*N). BPS defines the word length % section used during either the accumulation of the data in the integrator % sections or the subtraction of the data performed by the comb sections % (using 'wrap' arithmetic). If BPS is a scalar, that value is applied % to each filter stage. % % Optional arguments: % Y = HCICDECIMALGO(...,'zerolat') filters the data in X % with N-stage cascaded integrator-comb decimation filter with M % differential delays and a rate-change factor of R with NO LATENCY at % the output % % Note: This function is used to emulate the functionality of the % CIC-Decimator in the Signal Processing Blockset % Vectorize bps if it is a scalar if(isscalar(bps)) bps = repmat(bps,[1 2*n]); end % Include the output bits bps(end+1) = obits; % Compute the bits to remove per section b2rm = [abs(diff(bps)) abs(bps(end)-obits)]; % Compute the fraction lengths that will be propagated through the filter. for i = 1:(2*n)+ 1 if(i==1) fraclen(i) = infraclen; else fraclen(i) = fraclen(i-1) - b2rm(i-1); end end % Create a vector of FIMATH objects (2*n) and initialize the states for each stage for i = 1:2*n fm(i) = fimath('SumMode','SpecifyPrecision','SumWordLength',bps(i),'SumFractionLength',fraclen(i),... 'RoundMode','floor','OverflowMode','wrap','CastBeforeSum',1); z{i,1} = fi(0,'fimath',fm(i)); end fm_integ = fm(1:n); % assign the fimath operators(for addition) to the % integrator section fm_comb = fm(n+1:end); % assign the fimath operators(for subtraction) % to the comb section z_integ = z(1:n,:); % assign initial delays to each integrator stage z_comb = z(n+1:end,:); % assign initial delays to each comb stage % Default is to exhibit latency latency = true; if((nargin > 9) && strcmpi(varargin{1},'zerolat')) latency = false; end % Convert input to FI % % NOTE: % In order to match the results of the CIC Block, we use a test model with % the DSP Constant block. The RoundMode of the DSP Constant Block is % 'round' and the OverFlowMode is 'Saturate.' xfi = fi(x,true,inbits,infraclen,'RoundMode','round','OverflowMode','saturate'); % Preallocate for the output of the integrator portion of the filter using % the attributes of section N (last section in the integrator side) [nx,nchans] = size(x); yint_out = fi(zeros(ceil(nx/r),nchans),'WordLength',bps(n),... 'FractionLength',fraclen(n),'fimath',fm_integ(n)); [yrows,ycols] = size(yint_out); % Multichannel loop for l = 1:nchans, % Intergrate and Decimate Portion if latency, [yint(:,l), zfint(:,l)] = cic_integratendecim(r,m,n,xfi(:,l),bps,b2rm,fm_integ,z_integ,yint_out(:,l),offset); else [yint(:,l), zfint(:,l)] = cic_integratendecim_zlat(r,m,n,xfi(:,l),bps,b2rm,fm_integ,z_integ,yint_out(:,l),offset); end % Comb Portion y_comb(:,l) = comb(yint(:,l),yrows,m,n,fm_comb,bps,fraclen,b2rm); end % Cast output to correct size fm_out = fimath('SumMode','SpecifyPrecision','SumWordLength',obits,'SumFractionLength',fraclen(end),... 'RoundMode','floor','OverflowMode','wrap','CastBeforeSum',1); y = fi(y_comb,'WordLength',obits,'FractionLength',fraclen(end),... 'fimath',fm_out); % ------------------------------------------------------------------------- % CIC_INTEGRATENDECIM: Integrate and decimate portion of a CIC decimator % ------------------------------------------------------------------------- function [yout,zf] = cic_integratendecim(R,M,N,x,BPS,b2rm,fm_integ,z,yout,offset) % Initialize variables n = 1; modj = 0; for j = 1:length(x), % % Decimation portion % if modj == offset, % Select an output sample yout(n) = z{N}; n = n+1; end modj = mod(modj+1,R); % % Integrator section % for k = N:-1:2, % Use the FIMATH add method when adding two FIs w/ diff. FIMATHs fm = fm_integ(k); z{k} = fm.add(z{k-1},z{k}); end fm = fm_integ(1); z{1} = fm.add(x(j),z{1}); end zf = z; % ------------------------------------------------------------------------- % CIC_INTEGRATENDECIM_ZLAT: Integrate and decim portion of a ZLAT CIC decim % ------------------------------------------------------------------------- function [yout,zf] = cic_integratendecim_zlat(R,M,N,x,BPS,b2rm,fm_integ,z,yout,offset) % Initialize variables n = 1; modj = 0; for j = 1:length(x), % % Integrator section % % for k = N:-1:2, % Use the FIMATH add method when adding two FIs w/ diff. FIMATHs % fm = fm_integ(k); % z{k} = fm.add(z{k-1},z{k}); % end % fm = fm_integ(1); % z{1} = fm.add(x(j),z{1}); % Use the FIMATH add method when adding two FIs w/ diff. FIMATHs fm = fm_integ(1); z{1} = fm.add(x(j),z{1}); for k = 2:N, fm = fm_integ(k); z{k} = fm.add(z{k-1},z{k}); end % % Decimation portion % if modj == offset, % Select an output sample yout(n) = z{N}; n = n+1; end modj = mod(modj+1,R); end zf = z; %-------------------------------------------------------------------------- % COMB: Comb portion of a CIC decimation filter. %-------------------------------------------------------------------------- function y_comb = comb(yint,ny,M,N,fm_comb,bps,fraclen,b2rm) zcomb = cell(1,N); bps_comb = bps(N+1:end-1); fraclen_comb = fraclen(N+1:end-1); for k = 1:N zcomb{k} = fi(zeros(M,1),true,bps_comb(k),fraclen_comb(k),... 'fimath',fm_comb(k)); end % In order to retain the attributes of the states (for the comb side), % we'll need to loop over each section of the filter (N) and compute the % output and state. y_comb = yint; for sec = 1:N,% Number of sections [y_comb,zfcomb] = modcomb(y_comb,ny,M,N,zcomb{sec},fm_comb(sec),b2rm(N+sec)); end %-------------------------------------------------------------------------- % MODCOMB: One comb section in a CIC decimation filter. %-------------------------------------------------------------------------- function [y_comb,zcomb] = modcomb(yint,ny,M,N,zcomb,fm_comb,b2rm) for j = 0:ny-1, % Length of signal acc = yint(j+1); % Using the FIMATH method y_comb(j+1,1) = sub(fm_comb,acc,zcomb(end)); % Can't use the following because the FIMATHs for both operands must % be equal. % y_comb(j+1,1) = bitshift(acc-zcomb(end),-b2rm); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Shift the contents of the states (should be Circular buffer) for dd = M:-1:2, zcomb(dd) = zcomb(dd-1); end zcomb(1) = acc; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% end % [EOF]
Posted by Bhaskar Thiagarajan May 18, 2005
"Paul Solomon" <psolomon@tpg.com.au> wrote in message
news:428add1a@dnews.tpgi.com.au...
> Hi Bhaskar, > > thanks for this info, it has helped alot, and that article nicely
explained
> the finer details of > CIC that I was confused about. > > I am trying to do the design in matlab and am currently stalled as I do
not
> have the fixed point toolbox > that the filter design toolbox wants to do CIC filters.. I think that I
have
> now made a correct FIR correction > filter but it would be nice to be able to cascade this with a CIC filter > inmatlab and see the cumulative response.
While a CIC filter is typically modeled (and implemented) in fixed point, I don't think you absolutely need the fixed point toolbox to do what you want. Either you can implement the fixed precision manually in your matlab code or go ahead and use double precision arithmetic to model it for now. What is of importance here is that you model the frequency response of the CIC correctly (since that is what you are trying to study)..esp to see if your FIR correction is doing it's job. The frequency response of the CIC is quite well defined (see references). So you should be able to stick that your current simulation and see what happens. (Yes, I know that it would certainly be a lot more convenient to take a canned solution from Mathworks and get this to happen but I can guarantee that you'll learn more this way and save a bunch of cash) Cheers Bhaskar Note - A CIC implementation takes advantage of fixed precision arithmetic to work right - so I suggest you *model* your CIC rather than implement it in matlab for your simulation.
> So I think it will be a few days before I can report back sucsess, however
I
> think I am on the right track now > thanks to your assistance. > > regards, > > Paul Solomon > > > "Bhaskar Thiagarajan" <bhaskart@deja.com> wrote in message > news:428a1b87$0$79456$14726298@news.sunsite.dk... > > "Tim Wescott" <tim@seemywebsite.com> wrote in message > > news:118jvijkhj28t22@corp.supernews.com... > >> Paul Solomon wrote: > >> > >> > Hi All, > >> > > >> > I am working on a project in which we are attempting to demod
multiple
> >> > (analog) FM radio stations in a FPGA. > >> > I have been trying to work out how to design the CIC / FIR filter
pair
> > in > >> > the DDC section of this design. > >> > >> This paragraph has put me into abbreviation overload. FM, FPGA and FIR > >> all make sense to me -- what do CIC and DDC mean in this context? > > > > CIC - Cascaded Integrated Comb > > DDC - Digital Down Converter > > > > > >> > I have a input sampling rate of 80MSPS, which undersamples a clean > > spectrum > >> > of 88 - 108MHz i.e. the FM band. > >> > this should give me the FM band at 8 - 28MHz with an alias at 52 - > > 72MHz. > >> > > >> > I then take this input and mix with a NCO generated carrier at say > > 20.5MHz > >> > to try to pull out one of the stations. > >> > The output of the mixer needs to then be filtered to approx 200kHz > > bandwidth > >> > and decimated to maybe 800kSPS? > >> > >> Is it quadrature demodulation? If so 200kHz is strictly correct only
if
> >> you mean -100kHz to 100kHz. You could go out more than that if you > >> wanted to, but why? > >> > > >> > this is the part I am unsure of how to do.. I believe that I will
need
> >> > a > > CIC > >> > followed by a FIR however > >> > I am not sure the relevant paramaters of the CIC and how to set them, > >> > i.e. (decimation Rate) R = 128, but (stages)N = ?? and (differential > > delay)M > >> > = ??. > >> > >> Apparantly a CIC is some sort of a polyphase filter with decimation?
If
> >> so, why do you need a FIR filter at all? In fact if you were clever
you
> >> should be able to follow the quadrature demodulation with a single-step > >> lowpass/decimation filter to get a nicely conditioned baseband signal > >> that you would then have to work on to extract the FM signal. > > > > A CIC is a box-car filter that (just google for lotsa references and
very
> > detailed explanations - Rick just had one of his artciles on this very > > topic > > in EE times I think) doesn't use any multipliers, supports large > > decimation > > ratios, works well in fixed point arithmentic. So these are excellent > > candiates for 'coarse' decimation blocks that need to be implemented in > > FPGAs. Since they are box-car to begin with, their frequency response is > > pretty bad - so they are typically followed by a FIR filter that does
any
> > 'fine' decimation that may be needed as well as correct for the
amplitude
> > droop in the pass-band caused by the CICs. > > > > Given Paul's system requirements, I would think that a single FIR > > (non-CIC) > > to get him from 80 Msps to 800ksps in one step wouldn't be easy. So he
is
> > correct in considering CICs in his design. > > > > Here is Rick's article for reference - Paul would be wise to read it > > before > > moving forward. > > http://www.embedded.com/showArticle.jhtml?articleID=160400592 > > > > Paul - it seems you are shooting for a decimation of about 100. I'd > > suggest > > a CIC decimation of say 64 and the rest can be handled by your final
FIR.
> > Rick's article discusses the trade-offs related to stages and
differential
> > delay choices for these filters. If you still aren't sure of what you > > need, > > ask again (with some background on what you don't get). > > > > Since the CIC filters' frequency response is known exactly, you can then > > create an 'inverse' of this response in the frequency domain and then > > perform an IFFT to get filter coeffs for your FIR filter that can
correct
> > for the CIC. > > Note that you probably want a combination FIR - one that will correct
the
> > CIC as well as provide filtering to remove images and good stop band > > attenuation for the spectrum of interest. So you'd need to combine the 2 > > responses together to get your filter coeffs. > > > > Cheers > > Bhaskar > > > >> > > >> > I have read Hogenauer and still feel none the wiser.. > >> > > >> > also once the filter parameters are decided, how do you design the > > following > >> > FIR filter to straighten up the passband?? > >> > > >> > Anyhow, Hopefully someone out there will be able to help. > >> > > >> > Cheers, > >> > > >> > Paul Solomon > >> > > >> > > >> > >> > >> -- > >> ------------------------------------------- > >> Tim Wescott > >> Wescott Design Services > >> http://www.wescottdesign.com > > > > > >
Posted by Rick Lyons May 18, 2005
On Tue, 17 May 2005 17:23:41 -0400, "Steve Conahan"
<Steve.Conahan@mathworks.com> wrote:

  (snipped)
> >Hi Paul, > >There is a demo that is in the Filter Design Toolbox for MATLAB (Release 14, >Service Pack 2) that may help you. The demo file is named >ddcfilterchaindemo.m (see complete code below). It illustrates how to >design a similar DDC system for GSM. It looks like a very similar example >for what you are interested in doing (at least it could get you started). > >Also there is a similar "GSM Digital Downconverter" Simulink demo that ships >with the Signal Processing Blockset product. > >Cheers, >Steve Conahan >Signal Processing and Communications Development >The MathWorks, Inc. > >P.S. Here is the complete M code for the demo: >
(MATLAB code snipped) Hello Steve, I was tickled that you posted that code. However, trying to run it failed because I don't have a "called" routine titled "mfilt.cicdecim". Any chance you could provide that "mfilt.cicdecim" code? Thanks, [-Rick-] I'm just being greedy. :-)