import numpy as np from scipy import signal from .config import BODE_MAX_MULTIPLIER, BODE_POINTS from .schemas import BodeParams from .validation import require_finite, validate_coefficients def calculate_bode_response(params: BodeParams): fs_val = require_finite(params.fs, "fs") b_vals = validate_coefficients(params.b, "b") a_vals = validate_coefficients(params.a, "a") f_min = params.fs / 50000.0 f_max = params.fs * BODE_MAX_MULTIPLIER f_eval = np.logspace(np.log10(f_min), np.log10(f_max), BODE_POINTS) _, h = signal.freqz(b_vals, a_vals, worN=f_eval, fs=fs_val) mag = 20 * np.log10(np.abs(h) + 1e-12) phase = np.angle(h, deg=True) return { "freq": f_eval.tolist(), "mag": mag.tolist(), "phase": phase.tolist(), }