Added K IIR lpf filter

This commit is contained in:
Joppe Blondel
2025-10-19 17:02:29 +02:00
parent b2858ac5ee
commit 771fa58769
4 changed files with 115 additions and 1 deletions

64
rtl/core/lpf_iir_q15_k.v Normal file
View File

@@ -0,0 +1,64 @@
`timescale 1ns/1ps
// =============================================================================
// Low-Pass IIR Filter (Q1.15)
// Simple first-order infinite impulse response filter, equivalent to an
// exponential moving average. Provides an adjustable smoothing factor based
// on parameter K.
//
// Implements:
// Y[n+1] = Y[n] + (X[n] - Y[n]) / 2^K
//
// This is a purely digital one-pole low-pass filter whose time constant
// approximates that of an analog RC filter, where alpha = 1 / 2^K.
//
// The larger K is, the slower the filter responds (stronger smoothing).
// The smaller K is, the faster it reacts to changes.
//
// parameters:
// -- K : filter shift factor (integer, 4..14 typical)
// cutoff frequency Fs / ( * 2^K)
// larger K lower cutoff
//
// inout:
// -- clk : input clock
// -- rst_n : active-low reset
// -- x_q15 : signed 16-bit Q1.15 input sample (e.g., 0..0x7FFF)
// -- y_q15 : signed 16-bit Q1.15 filtered output
//
// Notes:
// - The arithmetic right shift implements division by 2^K.
// - Internal arithmetic is Q1.15 fixed-point with saturation
// to [0, 0x7FFF] (for non-negative signals).
// - Useful for smoothing noisy ADC / sigma-delta data streams
// or modeling an RC envelope follower.
// =============================================================================
module lpf_iir_q15_k #(
parameter integer K = 10 // try 8..12; bigger = more smoothing
)(
input wire clk,
input wire rst_n,
input wire signed [15:0] x_q15, // Q1.15 input (e.g., 0..0x7FFF)
output reg signed [15:0] y_q15 // Q1.15 output
);
wire signed [15:0] e_q15 = x_q15 - y_q15;
wire signed [15:0] delta_q15 = e_q15 >>> K; // arithmetic shift
wire signed [15:0] y_next = y_q15 + delta_q15; // clamp to [0, 0x7FFF] (handy if your signal is non-negative)
function signed [15:0] clamp01;
input signed [15:0] v;
begin
if (v < 16'sd0)
clamp01 = 16'sd0;
else if (v > 16'sh7FFF)
clamp01 = 16'sh7FFF;
else
clamp01 = v;
end
endfunction
always @(posedge clk or negedge rst_n) begin
if (!rst_n) y_q15 <= 16'sd0;
else y_q15 <= clamp01(y_next);
end
endmodule