Files
tcad-bodeplot/scratch/test_filter.py

56 lines
1.6 KiB
Python

import numpy as np
from scipy import signal
def integer_lfilter(b_int, a_int, x_float, shift_in, shift_out, shift_b, shift_a):
x_int = np.round(x_float * (2**shift_in)).astype(np.int64)
y_int = np.zeros(len(x_int), dtype=np.int64)
q_bx = shift_in + shift_b
q_ay = shift_out + shift_a
q_acc = max(q_bx, q_ay)
s_bx = q_acc - q_bx
s_ay = q_acc - q_ay
A0 = a_int[0]
nb = len(b_int)
na = len(a_int)
for n in range(len(x_int)):
acc = 0
for i in range(nb):
if n - i >= 0:
acc += (b_int[i] * x_int[n - i]) << s_bx
for j in range(1, na):
if n - j >= 0:
acc -= (a_int[j] * y_int[n - j]) << s_ay
# 原本的邏輯:(acc // A0) >> s_ay
# 修正後的邏輯:直接計算總位移,減少除法誤差
# y_int[n] = (acc // A0) >> s_ay
# 模擬 DSP 的 A0 通常是 2^shift_a
# 所以 acc / 2^shift_a >> (q_acc - shift_a - shift_out)
# 等於 acc >> (q_acc - shift_out)
total_shift = q_acc - shift_out
y_int[n] = acc >> total_shift
return y_int.astype(float) / (2**shift_out)
# 測試 1: 低通濾波器
fs = 1000
fc = 10
b, a = signal.butter(1, fc / (fs/2), 'low')
# b = [0.03046, 0.03046], a = [1.0, -0.939]
shift = 14
b_int = [int(round(x * (2**shift))) for x in b]
a_int = [int(round(x * (2**shift))) for x in a]
x = np.ones(100) # Step input
y_float = signal.lfilter(b, a, x)
y_fixed = integer_lfilter(b_int, a_int, x, shift, shift, shift, shift)
print("Float Final:", y_float[-1])
print("Fixed Final:", y_fixed[-1])
print("Diff:", y_float[-1] - y_fixed[-1])