FPGA 23 - DSP FIR Lowpass Filter with Verilog

แชร์
ฝัง
  • เผยแพร่เมื่อ 3 ต.ค. 2024
  • In this episode, we're building a 9-tap finite impulse response (FIR) lowpass filter in Verilog that has a cutoff frequency at ~10MHz with a 100MHz sampling clock.
    In order to test this FIR lowpass filter, we're also building a testbench that synthesize two sine waves, one at 2MHz and the other at 30MHz. These two sine waves are added together and the resulting noisy signal is resampled at 100MHz before feeding the FIR lowpass filter.
    As you will see, the FIR lowpass filter would attenuate the 30MHz component of the noisy signal and leave the 2MHz component untouched.
    #fpga #vivado #verilog #xilinx #dsp #impulseresponse #simulation
    Recommended prerequisite:
    FPGA 18 - Xilinx Verilog Cordic Sine/Cosine generator
    • FPGA 18 - AMD Xilinx V...
    FPGA 7 - Verilog Vivado two's complement fixed-point arithmetic
    • FPGA 7 - Verilog Vivad...

ความคิดเห็น • 21

  • @dillanrainerpereira806
    @dillanrainerpereira806 6 หลายเดือนก่อน

    Thank You

    • @GauravKatiyar-yi8ro
      @GauravKatiyar-yi8ro 5 หลายเดือนก่อน

      module fir_tb();
      localparam CORDIC_CLK_PERIOD = 1250; // Clock period for the CORDIC at 800 Hz
      localparam FIR_CLK_PERIOD = 1250; // Clock period for the FIR filter at 800 Hz
      localparam signed [15:0] PI_POS = 16'h6488; // Positive PI constant
      localparam signed [15:0] PI_NEG = 16'h9878; // Negative PI constant
      localparam PHASE_INC_150HZ = 122; // Phase increment for 150 Hz signal at 800 Hz
      localparam PHASE_INC_400HZ = 326; // Phase increment for 400 Hz signal at 800 Hz
      reg cordic_clk = 1'b0;
      reg fir_clk = 1'b0;
      reg phase_tvalid = 1'b0;
      reg signed [15:0] phase_150Hz = 0;
      reg signed [15:0] phase_400Hz = 0;
      wire sincos_150Hz_tvalid;
      wire signed [15:0] sin_150Hz, cos_150Hz;
      wire sincos_400Hz_tvalid;
      wire signed [15:0] sin_400Hz, cos_400Hz;
      reg signed [15:0] noisy_signal = 0;
      wire signed [15:0] filtered_signal;
      // Instantiate CORDIC for 150 Hz sine wave generation
      // Ensure cordic_0 is defined or imported in your project
      cordic_0 cordic_inst_150Hz(
      .aclk(cordic_clk),
      .s_axis_phase_tvalid(phase_tvalid),
      .s_axis_phase_tdata(phase_150Hz),
      .m_axis_dout_tvalid(sincos_150Hz_tvalid),
      .m_axis_dout_tdata({sin_150Hz, cos_150Hz})
      );
      // Instantiate CORDIC for 400 Hz sine wave generation
      cordic_0 cordic_inst_400Hz(
      .aclk(cordic_clk),
      .s_axis_phase_tvalid(phase_tvalid),
      .s_axis_phase_tdata(phase_400Hz),
      .m_axis_dout_tvalid(sincos_400Hz_tvalid),
      .m_axis_dout_tdata({sin_400Hz, cos_400Hz})
      );
      // Phase sweep for 150 Hz and 400 Hz sine wave generation
      always @(posedge cordic_clk) begin
      phase_tvalid

  • @阿才-f1x
    @阿才-f1x 10 หลายเดือนก่อน

    love you

    • @GauravKatiyar-yi8ro
      @GauravKatiyar-yi8ro 5 หลายเดือนก่อน

      module fir(
      input wire clk,
      input wire signed [15:0] noisy_signal,
      output wire signed [15:0] filtered_signal
      );
      // Declare the loop variable here, outside the always block
      integer i;
      integer j;
      // Coefficients for 5-tap FIR filter
      //reg signed [15:0] coeff [0:4] = {16'h04F6, 16'h0AE4, 16'h160F, 16'h0AE4, 16'h04F6};
      reg signed [15:0] coeff [0:4];
      initial begin
      coeff[0] = 16'h04F6;
      coeff[1] = 16'h0AE4;
      coeff[2] = 16'h160F;
      coeff[3] = 16'h0AE4;
      coeff[4] = 16'h04F6;
      end
      // Delayed signals for the FIR filter
      reg signed [15:0] delayed_signal [0:4];
      // Multiplication products
      reg signed [31:0] prod [0:4];
      // Accumulation stages
      reg signed [32:0] sum_0 [0:2];
      reg signed [33:0] sum_1;

      // Delay line and pipeline the noisy signal
      always @(posedge clk) begin
      // Declare the loop variable outside the loop
      delayed_signal[0]

  • @bachur6306
    @bachur6306 2 หลายเดือนก่อน

    hey, why do you make 1.3.28 and not 1.2.28 fixed point from multiplying two 1.1.14 and why do you increase the integer part of the number by 1 each time sum index increases? second questions, how do we know that we can only cut the oldest bits at the end? thanks in advance

  • @ArjunRam-pr5yb
    @ArjunRam-pr5yb 5 หลายเดือนก่อน

    please can you tell how its actually cofficient convert into hexadecimal value? it will be very help for me

  • @AnkitPandey-w8e
    @AnkitPandey-w8e หลายเดือนก่อน

    Could you please provide this code

  • @sbhtkfxph4444
    @sbhtkfxph4444 2 หลายเดือนก่อน

    hy, how can i get the coefficient numbers? there is easy way to know them?

  • @ngocmanprocoder
    @ngocmanprocoder 9 หลายเดือนก่อน

    could you show me the way to integrate it into SoC System (qsys or platform designer), please? Thank you so much.

  • @skywalkerluke-7705
    @skywalkerluke-7705 9 หลายเดือนก่อน

    Hi, how did you generate coefficients values in hex format and i want to generate 2khz frequency, what changes should i do.

  • @劉珩-m1q
    @劉珩-m1q 9 หลายเดือนก่อน

    hi! I was just wondering how you determined the frequencies of sine wave by the phase jump in testbench, if there are any formula or some references, I would be very appreciate! thank you!

    • @FPGARevolution
      @FPGARevolution  9 หลายเดือนก่อน +1

      The phase resolution is fixed in this IP and the total number of steps is 2*PI or 51,472. The equation for synthesizing the exact frequency is Fout = (phase_jump * sampling_frequency) / 51,472 so plug in your required Fout and tune the two parameters in the numerator accordingly.

  • @hightlightlol2106
    @hightlightlol2106 ปีที่แล้ว

    Hi, how could you know exactly where to put those peplined sum_0, sum_1, sum_2 and sum_3. What will happened with those sum when you increase the tap number? If you have any document about how to put those sum registers together, I would be very appreciate!! Thanks

    • @FPGARevolution
      @FPGARevolution  ปีที่แล้ว

      Good curiosity, the RTL was put together straight from the brain without any intermediate document so don't overthink regarding documents but let me elaborate on what's important. Where to put the sums depend on your pipeline architecture. In this demonstration, the pipeline ensures each multiplication or addition would have no more than two terms so if you look at all the product terms, each pair would then get summed and this drives the sum chains resulting in one sum at the end which is the result of the convolution.
      When you increase the tap number, you would have more product terms so you would just need to make sure in the first pipeline stage of the summation all product terms are included and paired up then in subsequent pipeline stages, you continue to break down those sum terms until you end up with one.

  • @NarutoUzumaki-hu2rp
    @NarutoUzumaki-hu2rp 10 หลายเดือนก่อน

    Hi, which windoing method you used to generate coefficient values

    • @FPGARevolution
      @FPGARevolution  10 หลายเดือนก่อน

      Kaiser

    • @NarutoUzumaki-hu2rp
      @NarutoUzumaki-hu2rp 10 หลายเดือนก่อน

      @@FPGARevolution thanks

    • @NarutoUzumaki-hu2rp
      @NarutoUzumaki-hu2rp 10 หลายเดือนก่อน

      Hi, how did you convert decimals coefficients in to 16 bit hex.

  • @MATHSBLAZE07
    @MATHSBLAZE07 11 หลายเดือนก่อน

    Getting error “module cordic_0 not found “please help

    • @FPGARevolution
      @FPGARevolution  11 หลายเดือนก่อน

      There's a step starting at 05:28 for configuring the cordic ip that you mentioned missing.

  • @GauravKatiyar-yi8ro
    @GauravKatiyar-yi8ro 5 หลายเดือนก่อน

    fir_tb.v
    module fir_tb();
    localparam CORDIC_CLK_PERIOD = 1250; // Clock period for the CORDIC at 800 Hz
    localparam FIR_CLK_PERIOD = 1250; // Clock period for the FIR filter at 800 Hz
    localparam signed [15:0] PI_POS = 16'h6488; // Positive PI constant
    localparam signed [15:0] PI_NEG = 16'h9878; // Negative PI constant
    localparam PHASE_INC_150HZ = 122; // Phase increment for 150 Hz signal at 800 Hz
    localparam PHASE_INC_400HZ = 326; // Phase increment for 400 Hz signal at 800 Hz
    reg cordic_clk = 1'b0;
    reg fir_clk = 1'b0;
    reg phase_tvalid = 1'b0;
    reg signed [15:0] phase_150Hz = 0;
    reg signed [15:0] phase_400Hz = 0;
    wire sincos_150Hz_tvalid;
    wire signed [15:0] sin_150Hz, cos_150Hz;
    wire sincos_400Hz_tvalid;
    wire signed [15:0] sin_400Hz, cos_400Hz;
    reg signed [15:0] noisy_signal = 0;
    wire signed [15:0] filtered_signal;
    // Instantiate CORDIC for 150 Hz sine wave generation
    // Ensure cordic_0 is defined or imported in your project
    cordic_0 cordic_inst_150Hz(
    .aclk(cordic_clk),
    .s_axis_phase_tvalid(phase_tvalid),
    .s_axis_phase_tdata(phase_150Hz),
    .m_axis_dout_tvalid(sincos_150Hz_tvalid),
    .m_axis_dout_tdata({sin_150Hz, cos_150Hz})
    );
    // Instantiate CORDIC for 400 Hz sine wave generation
    cordic_0 cordic_inst_400Hz(
    .aclk(cordic_clk),
    .s_axis_phase_tvalid(phase_tvalid),
    .s_axis_phase_tdata(phase_400Hz),
    .m_axis_dout_tvalid(sincos_400Hz_tvalid),
    .m_axis_dout_tdata({sin_400Hz, cos_400Hz})
    );
    // Phase sweep for 150 Hz and 400 Hz sine wave generation
    always @(posedge cordic_clk) begin
    phase_tvalid