Compare commits

2 Commits

Author SHA1 Message Date
Joppe Blondel
49b8a77480 Combined all sigmadelta things to one input block 2025-10-19 20:03:51 +02:00
Joppe Blondel
165faefa59 Added decimation 2025-10-19 17:26:09 +02:00
5 changed files with 138 additions and 67 deletions

View File

@@ -22,6 +22,7 @@ files_verilog = rtl/toplevel/top_generic.v
rtl/core/nco_q15.v rtl/core/nco_q15.v
rtl/core/sigmadelta_sampler.v rtl/core/sigmadelta_sampler.v
rtl/core/sigmadelta_rcmodel_q15.v rtl/core/sigmadelta_rcmodel_q15.v
rtl/core/sigmadelta_input_q15.v
rtl/core/mul_const.v rtl/core/mul_const.v
rtl/core/lpf_iir_q15_k.v rtl/core/lpf_iir_q15_k.v
rtl/core/decimate_by_r_q15.v rtl/core/decimate_by_r_q15.v
@@ -51,6 +52,7 @@ files_verilog = sim/tb/tb_nco_q15.v
rtl/core/nco_q15.v rtl/core/nco_q15.v
rtl/core/lvds_comparator.v rtl/core/lvds_comparator.v
rtl/core/sigmadelta_rcmodel_q15.v rtl/core/sigmadelta_rcmodel_q15.v
rtl/core/sigmadelta_input_q15.v
rtl/core/mul_const.v rtl/core/mul_const.v
rtl/core/lpf_iir_q15_k.v rtl/core/lpf_iir_q15_k.v
rtl/core/decimate_by_r_q15.v rtl/core/decimate_by_r_q15.v

View File

@@ -0,0 +1,58 @@
`timescale 1ns/1ps
module sigmadelta_input #(
parameter integer R_OHM = 3300,
parameter integer C_PF = 220
)(
input wire clk_15,
input wire resetn,
input wire adc_a,
input wire adc_b,
output wire adc_o,
output wire signed [15:0] signal_q15,
output wire signal_valid
);
`include "rc_alpha_q15.vh"
wire sd_signal;
wire signed [15:0] raw_sample_q15;
wire signed [15:0] lpf_sample_q15;
sigmadelta_sampler sd_sampler(
.clk(clk_15),
.a(adc_a), .b(adc_b),
.o(sd_signal)
);
assign adc_o = sd_signal;
localparam integer alpha_q15_int = alpha_q15_from_rc(R_OHM, C_PF, 15000000);
localparam signed [15:0] alpha_q15 = alpha_q15_int[15:0];
localparam signed [15:0] alpha_q15_top = alpha_q15 & 16'hff00;
sigmadelta_rcmodel_q15 #(
.alpha_q15(alpha_q15_top)
) rc_model (
.clk(clk_15), .resetn(resetn),
.sd_sample(sd_signal),
.sample_q15(raw_sample_q15)
);
lpf_iir_q15_k #(
.K(10)
) lpf (
.clk(clk_15), .rst_n(resetn),
.x_q15(raw_sample_q15),
.y_q15(lpf_sample_q15)
);
decimate_by_r_q15 #(
.R(375), // 15MHz/375 = 40KHz
.CNT_W(10)
) decimate (
.clk(clk_15), .rst_n(resetn),
.in_valid(1'b1), .in_q15(lpf_sample_q15),
.out_valid(signal_valid), .out_q15(signal_q15)
);
endmodule

View File

@@ -1,3 +1,6 @@
`ifndef CONV_VH
`define CONV_VH
// ============================================================================= // =============================================================================
// Convert Q1.15 to a biased UQ0.16 signal // Convert Q1.15 to a biased UQ0.16 signal
// ============================================================================= // =============================================================================
@@ -8,4 +11,6 @@ begin
biased = q15 + 17'sd32768; biased = q15 + 17'sd32768;
q15_to_uq16 = biased[15:0]; q15_to_uq16 = biased[15:0];
end end
endfunction endfunction
`endif

View File

@@ -7,61 +7,82 @@
`define RC_ALPHA_Q15_VH `define RC_ALPHA_Q15_VH
function integer alpha_q15_from_rc; function integer alpha_q15_from_rc;
input integer R_OHM; // resistance in ohms input integer R_OHM; // ohms
input integer C_PF; // capacitance in picofarads input integer C_PF; // picofarads
input integer FS_HZ; // sampling frequency in Hz input integer FS_HZ; // Hz
integer N; // fractional bits for x (QN)
reg [127:0] num_1e12_sllN;
reg [127:0] denom_u;
reg [127:0] x_qN; // x in QN
reg [255:0] x2; // x^2 in Q(2N)
reg [383:0] x3; // x^3 in Q(3N)
integer term1_q15; // x -> Q1.15
integer term2_q15; // x^2/2 -> Q1.15
integer term3_q15; // x^3/6 -> Q1.15
integer acc; // accumulator for result
begin
// Choose QN for x. N=24 is a good balance for accuracy/width. // Choose QN for x. N=24 is a good balance for accuracy/width.
N = 24; integer N;
// x = 1 / (Fs * R * C) with C in pF ==> x = 1e12 / (Fs * R * C_PF) // We'll keep everything as unsigned vectors; inputs copied into vectors first.
reg [63:0] R_u, C_u, FS_u;
// x = 1 / (Fs * R * C) with C in pF -> x = 1e12 / (Fs*R*C_pf)
// x_qN = round( x * 2^N ) = round( (1e12 << N) / denom ) // x_qN = round( x * 2^N ) = round( (1e12 << N) / denom )
num_1e12_sllN = 128'd1000000000000 << N; reg [127:0] NUM_1E12_SLLN; // big enough for 1e12 << N
reg [127:0] DENOM; // Fs*R*C
// denom = Fs * R * C_PF (fits in 64..96 bits for typical values) reg [127:0] X_qN; // x in QN
denom_u = 0;
denom_u = denom_u + FS_HZ[127:0];
denom_u = denom_u * R_OHM[127:0];
denom_u = denom_u * C_PF[127:0];
// rounded divide for x_qN
x_qN = (num_1e12_sllN + (denom_u >> 1)) / denom_u;
// Powers // Powers
x2 = x_qN * x_qN; // 128x128 -> 256 reg [255:0] X2; // x^2 in Q(2N)
x3 = x2 * x_qN; // 256x128 -> 384 reg [383:0] X3; // x^3 in Q(3N)
// term1 = x -> shift from QN to Q15 integer term1_q15;
term1_q15 = (x_qN >> (N - 15)) & 16'hFFFF; integer term2_q15;
integer term3_q15;
integer acc;
// term2 = x^2 / 2 -> shift from Q(2N) to Q15 and divide by 2 begin
term2_q15 = (x2 >> (2*N - 15 + 1)) & 16'hFFFF; N = 24;
// term3 = x^3 / 6 -> shift from Q(3N) to Q15, then divide by 6 (rounded) // Copy integer inputs into 64-bit vectors (no bit-slicing of integers)
begin : gen_term3 R_u = R_OHM[31:0];
C_u = C_PF[31:0];
FS_u = FS_HZ[31:0];
// Denominator = Fs * R * C_pf (fits in < 2^64 for typical values)
DENOM = 128'd0;
DENOM = FS_u;
DENOM = DENOM * R_u;
DENOM = DENOM * C_u;
// // Guard: avoid divide by zero
// if (DENOM == 0) begin
// alpha_q15_from_rc = 0;
// disable alpha_q15_from_rc;
// end
// Numerator = (1e12 << N). 1e12 * 2^24 ≈ 1.6777e19 (fits in 2^64..2^65),
// so use 128 bits to be safe.
NUM_1E12_SLLN = 128'd1000000000000 << N;
// x_qN = rounded division
X_qN = (NUM_1E12_SLLN + (DENOM >> 1)) / DENOM;
// Powers
X2 = X_qN * X_qN;
X3 = X2 * X_qN;
// Convert terms to Q1.15:
// term1 = x -> shift from QN to Q15
term1_q15 = (X_qN >> (N - 15)) & 16'hFFFF;
// term2 = x^2 / 2 -> Q(2N) to Q15 and /2
term2_q15 = (X2 >> (2*N - 15 + 1)) & 16'hFFFF;
// term3 = x^3 / 6 -> Q(3N) to Q15, then /6 with rounding
begin : gen_t3
reg [383:0] tmp_q15_wide; reg [383:0] tmp_q15_wide;
reg [383:0] tmp_div6; reg [383:0] tmp_div6;
tmp_q15_wide = (x3 >> (3*N - 15)); tmp_q15_wide = (X3 >> (3*N - 15));
tmp_div6 = (tmp_q15_wide + 6'd3) / 6; // +3 for rounding tmp_div6 = (tmp_q15_wide + 6'd3) / 6;
term3_q15 = tmp_div6[15:0]; term3_q15 = tmp_div6[15:0];
end end
// Combine: alpha_q15 = x - x^2/2 + x^3/6 ; clamp to [0, 0x7FFF] // Combine and clamp
acc = term1_q15 - term2_q15 + term3_q15; acc = term1_q15 - term2_q15 + term3_q15;
if (acc < 0) acc = 0; if (acc < 0) acc = 0;
else if (acc > 16'h7FFF) acc = 16'h7FFF; else if (acc > 16'h7FFF) acc = 16'h7FFF;
alpha_q15_from_rc = acc; alpha_q15_from_rc = acc;
end end

View File

@@ -13,39 +13,24 @@ module tb_sigmadelta();
initial begin initial begin
$dumpfile("out.vcd"); $dumpfile("out.vcd");
$dumpvars; $dumpvars;
#1_000_000 #2_000_000
$finish; $finish;
end; end;
wire sd_a; wire sd_a;
wire sd_b; wire sd_b;
wire sd_o; wire sd_o;
// 3K3R 220PC 15MHZT
sigmadelta_sampler sd_sampler(
.clk(clk),
.a(sd_a), .b(sd_b),
.o(sd_o)
);
wire signed [15:0] sample_q15;
sigmadelta_rcmodel_q15 rc_model(
.clk(clk), .resetn(resetn),
.sd_sample(sd_o),
.sample_q15(sample_q15)
);
wire signed [15:0] y_q15;
lpf_iir_q15_k #(9) lpf(
.clk(clk), .rst_n(resetn),
.x_q15(sample_q15),
.y_q15(y_q15)
);
wire signed [15:0] decimated_q15; wire signed [15:0] decimated_q15;
decimate_by_r_q15 #(400, 10) decimate( wire decimated_valid;
.clk(clk), .rst_n(resetn),
.in_valid(1'b1), .in_q15(y_q15), sigmadelta_input #(
.out_valid(), .out_q15(decimated_q15) .R_OHM(3300),
.C_PF(220)
) dut(
.clk_15(clk), .resetn(resetn),
.adc_a(sd_a), .adc_b(sd_b), .adc_o(sd_o),
.signal_q15(decimated_q15),
.signal_valid(decimated_valid)
); );
endmodule endmodule