summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Nordby <jononor@gmail.com>2025-08-08 23:01:15 +0200
committerJon Nordby <jononor@gmail.com>2025-08-08 23:01:15 +0200
commite7ef91cde0e25e2b4aedb7a19c7de53c6a1b18d3 (patch)
tree17e28926d26ba090a32856cf686edae339ad3896
parent549688cc3b1175538788361e379719dbd18306cd (diff)
pdm: Leaky integrator for DC blocking seems better
-rw-r--r--bindings/test_galearn_pdm.py10
-rw-r--r--cocotb_try/cic3_pdm.v42
2 files changed, 30 insertions, 22 deletions
diff --git a/bindings/test_galearn_pdm.py b/bindings/test_galearn_pdm.py
index 3a19762..6274868 100644
--- a/bindings/test_galearn_pdm.py
+++ b/bindings/test_galearn_pdm.py
@@ -126,19 +126,19 @@ def test_dc():
function = sys._getframe().f_code.co_name # looks up function name
test_name = f'{function}'
sr = SAMPLERATE_DEFAULT
- test_duration = 0.0013
+ test_duration = 0.030
# Generate test data
frequency = 1000
pcm_input = generate_test_tone(duration_sec=test_duration,
- freqs=[frequency], noise_level=0.0, sample_rate=sr, amplitude=0.01,
- ) + 0.10 # DC
+ freqs=[frequency], noise_level=0.0, sample_rate=sr, amplitude=0.1,
+ ) + 0.20 # DC
pdm_input = convert(pcm_input)
out = numpy.zeros(shape=len(pdm_input)//DECIMATION, dtype=numpy.int16)
# Process using filter
- n_samples = galearn_pdm.process(pdm_input, out, 200, 1)
- out = out / (2**15) # XXX: where does this magical come from?
+ n_samples = galearn_pdm.process(pdm_input, out, 128, 5)
+ out = out / (2**12)
# Compensate for delay through filter
delay = find_forward_shift(pcm_input, out)
diff --git a/cocotb_try/cic3_pdm.v b/cocotb_try/cic3_pdm.v
index 4e8d664..c53e867 100644
--- a/cocotb_try/cic3_pdm.v
+++ b/cocotb_try/cic3_pdm.v
@@ -25,17 +25,23 @@ module cic3_pdm (
reg signed [15:0] scaled_out;
reg cic_valid;
- // HPF registers
- reg signed [15:0] hpf_x_prev;
- reg signed [15:0] hpf_y_prev;
+ // Leaky integrator HPF registers
+ reg signed [23:0] hpf_integrator; // 24-bit for precision
+ reg signed [15:0] hpf_output;
// HPF calculation wires
+ wire signed [8:0] hpf_complement;
+ wire signed [23:0] hpf_scaled_input;
+ wire signed [23:0] hpf_dc_estimate;
/* verilator lint_off UNUSEDSIGNAL */
- wire signed [23:0] hpf_temp;
+ wire signed [23:0] hpf_temp_result;
/* verilator lint_on UNUSEDSIGNAL */
- wire signed [15:0] hpf_calc;
- // Convert 1-bit PDM to signed
+ // HPF wire assignments
+ assign hpf_complement = 9'd256 - {1'b0, hpf_alpha};
+ assign hpf_scaled_input = {{8{scaled_out[15]}}, scaled_out};
+ assign hpf_dc_estimate = hpf_integrator >>> 8;
+ assign hpf_temp_result = hpf_scaled_input - hpf_dc_estimate;
wire signed [CIC_WIDTH-1:0] pdm_signed = pdm_in ? 17'sd1 : -17'sd1;
// CIC Integrator stages (run at PDM rate)
@@ -95,15 +101,13 @@ module cic3_pdm (
endcase
end
- // HPF calculation
- assign hpf_temp = ((hpf_alpha * hpf_y_prev) + (({8'd0, scaled_out} - {8'd0, hpf_x_prev}) << 8)) >>> 8;
- assign hpf_calc = hpf_temp[15:0];
-
- // High-pass filter (1st order IIR: y[n] = alpha/256 * y[n-1] + (x[n] - x[n-1]))
+ // Leaky integrator-based DC blocker
+ // y[n] = x[n] - dc_estimate
+ // dc_estimate[n] = alpha/256 * dc_estimate[n-1] + (1-alpha/256) * x[n]
always @(posedge clk) begin
if (rst) begin
- hpf_x_prev <= 0;
- hpf_y_prev <= 0;
+ hpf_integrator <= 0;
+ hpf_output <= 0;
pcm_out <= 0;
pcm_valid <= 0;
end else begin
@@ -114,10 +118,14 @@ module cic3_pdm (
// Bypass HPF completely
pcm_out <= scaled_out;
end else begin
- // HPF computation: y[n] = alpha/256 * y[n-1] + (x[n] - x[n-1])
- pcm_out <= hpf_calc;
- hpf_x_prev <= scaled_out;
- hpf_y_prev <= hpf_calc;
+ // Update leaky integrator (DC estimate)
+ // integrator = alpha * integrator + (256-alpha) * input
+ hpf_integrator <= (hpf_alpha * hpf_dc_estimate) +
+ (hpf_complement * hpf_scaled_input);
+
+ // Output = input - DC estimate
+ hpf_output <= hpf_temp_result[15:0];
+ pcm_out <= hpf_output;
end
pcm_valid <= 1;
end