71 lines
2.3 KiB
Systemverilog
71 lines
2.3 KiB
Systemverilog
// rc_alpha_q15.vh
|
|
// Plain Verilog-2001 constant function: R(ohm), C(pF), Fs(Hz) -> alpha_q15 (Q1.15)
|
|
// Uses fixed-point approximation: 1 - exp(-x) ≈ x - x^2/2 + x^3/6, where x = 1/(Fs*R*C)
|
|
// All integer math; suitable for elaboration-time constant folding (e.g., XST).
|
|
|
|
`ifndef RC_ALPHA_Q15_VH
|
|
`define RC_ALPHA_Q15_VH
|
|
|
|
function integer alpha_q15_from_rc;
|
|
input integer R_OHM; // resistance in ohms
|
|
input integer C_PF; // capacitance in picofarads
|
|
input integer FS_HZ; // sampling frequency in 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.
|
|
N = 24;
|
|
|
|
// 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 )
|
|
num_1e12_sllN = 128'd1000000000000 << N;
|
|
|
|
// denom = Fs * R * C_PF (fits in 64..96 bits for typical values)
|
|
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
|
|
x2 = x_qN * x_qN; // 128x128 -> 256
|
|
x3 = x2 * x_qN; // 256x128 -> 384
|
|
|
|
// term1 = x -> shift from QN to Q15
|
|
term1_q15 = (x_qN >> (N - 15)) & 16'hFFFF;
|
|
|
|
// term2 = x^2 / 2 -> shift from Q(2N) to Q15 and divide by 2
|
|
term2_q15 = (x2 >> (2*N - 15 + 1)) & 16'hFFFF;
|
|
|
|
// term3 = x^3 / 6 -> shift from Q(3N) to Q15, then divide by 6 (rounded)
|
|
begin : gen_term3
|
|
reg [383:0] tmp_q15_wide;
|
|
reg [383:0] tmp_div6;
|
|
tmp_q15_wide = (x3 >> (3*N - 15));
|
|
tmp_div6 = (tmp_q15_wide + 6'd3) / 6; // +3 for rounding
|
|
term3_q15 = tmp_div6[15:0];
|
|
end
|
|
|
|
// Combine: alpha_q15 = x - x^2/2 + x^3/6 ; clamp to [0, 0x7FFF]
|
|
acc = term1_q15 - term2_q15 + term3_q15;
|
|
if (acc < 0) acc = 0;
|
|
else if (acc > 16'h7FFF) acc = 16'h7FFF;
|
|
|
|
alpha_q15_from_rc = acc;
|
|
end
|
|
endfunction
|
|
|
|
`endif
|