diff --git a/project.cfg b/project.cfg index 53bc7fc..7098231 100644 --- a/project.cfg +++ b/project.cfg @@ -24,6 +24,7 @@ files_verilog = rtl/toplevel/top_generic.v rtl/core/sigmadelta_rcmodel_q15.v rtl/core/mul_const.v rtl/core/lpf_iir_q15_k.v + rtl/core/decimate_by_r_q15.v rtl/arch/spartan-6/lvds_comparator.v rtl/arch/spartan-6/clk_gen.v files_con = boards/mimas_v1/constraints.ucf @@ -52,6 +53,7 @@ files_verilog = sim/tb/tb_nco_q15.v rtl/core/sigmadelta_rcmodel_q15.v rtl/core/mul_const.v rtl/core/lpf_iir_q15_k.v + rtl/core/decimate_by_r_q15.v sim/overrides/sigmadelta_sampler.v sim/overrides/clk_gen.v files_other = rtl/util/conv.vh diff --git a/rtl/core/decimate_by_r_q15.v b/rtl/core/decimate_by_r_q15.v new file mode 100644 index 0000000..60df0c3 --- /dev/null +++ b/rtl/core/decimate_by_r_q15.v @@ -0,0 +1,74 @@ +`timescale 1ns/1ps + +// ============================================================================= +// Decimator by R +// Reduces the effective sample rate by an integer factor R by selecting every +// R-th input sample. Generates a one-cycle 'out_valid' pulse each time a new +// decimated sample is produced. +// +// Implements: +// For each valid input sample: +// if (count == R-1): +// count <= 0 +// out_q15 <= in_q15 +// out_valid <= 1 +// else: +// count <= count + 1 +// +// parameters: +// -- R : integer decimation factor (e.g., 400) +// output sample rate = input rate / R +// -- CNT_W : counter bit width, must satisfy 2^CNT_W > R +// +// inout: +// -- clk : input clock (same rate as 'in_valid') +// -- rst_n : active-low synchronous reset +// -- in_valid : input data strobe; assert 1'b1 if input is always valid +// -- in_q15 : signed 16-bit Q1.15 input sample (full-rate) +// -- out_valid : single-cycle pulse every R samples (decimated rate strobe) +// -- out_q15 : signed 16-bit Q1.15 output sample (decimated stream) +// +// Notes: +// - This module performs *pure downsampling* (sample selection only). +// It does not include any anti-alias filtering; high-frequency content +// above the new Nyquist limit (Fs_out / 2) will alias into the baseband. +// - For most applications, an anti-alias low-pass filter such as +// lpf_iir_q15 or a FIR stage should precede this decimator. +// - The output sample rate is given by: +// Fs_out = Fs_in / R +// - Typical usage: interface between high-rate sigma-delta or oversampled +// data streams and lower-rate processing stages. +// ============================================================================= +module decimate_by_r_q15 #( + parameter integer R = 400, // decimation factor + parameter integer CNT_W = 10 // width so that 2^CNT_W > R (e.g., 10 for 750) +)( + input wire clk, + input wire rst_n, + input wire in_valid, // assert 1'b1 if always valid + input wire signed [15:0] in_q15, // Q1.15 sample at full rate + output reg out_valid, // 1-cycle pulse every R samples + output reg signed [15:0] out_q15 // Q1.15 sample at decimated rate +); + reg [CNT_W-1:0] cnt; + + always @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + cnt <= {CNT_W{1'b0}}; + out_valid <= 1'b0; + out_q15 <= 16'sd0; + end else begin + out_valid <= 1'b0; + + if (in_valid) begin + if (cnt == R-1) begin + cnt <= {CNT_W{1'b0}}; + out_q15 <= in_q15; + out_valid <= 1'b1; + end else begin + cnt <= cnt + 1'b1; + end + end + end + end +endmodule diff --git a/sim/tb/tb_sigmadelta.v b/sim/tb/tb_sigmadelta.v index 1948a80..3adeb5a 100644 --- a/sim/tb/tb_sigmadelta.v +++ b/sim/tb/tb_sigmadelta.v @@ -13,7 +13,7 @@ module tb_sigmadelta(); initial begin $dumpfile("out.vcd"); $dumpvars; - #1_000_000 + #2_000_000 $finish; end; @@ -35,10 +35,17 @@ module tb_sigmadelta(); ); wire signed [15:0] y_q15; - lpf_iir_q15_k #(8) lpf( + lpf_iir_q15_k #(10) lpf( .clk(clk), .rst_n(resetn), .x_q15(sample_q15), .y_q15(y_q15) ); + wire signed [15:0] decimated_q15; + decimate_by_r_q15 #(400, 10) decimate( + .clk(clk), .rst_n(resetn), + .in_valid(1'b1), .in_q15(y_q15), + .out_valid(), .out_q15(decimated_q15) + ); + endmodule