1
0
Fork 0

Rename linear-phase low-pass FIR design function

This commit is contained in:
Robbert van der Helm 2022-06-06 15:37:39 +02:00
parent cbb380a9b7
commit f4b3999916

View file

@ -221,10 +221,11 @@ impl FirFilter {
} }
impl FirCoefficients { impl FirCoefficients {
/// A somewhat crude but very functional and relatively fast way create a linear phase FIR /// A somewhat crude but very functional and relatively fast way create linear phase FIR
/// **low-pass** filter that matches the frequency response of a biquad filter. This normalizes /// **low-pass** filter that matches the frequency response of a fourth order biquad low-pass
/// the result, so biquad coefficients for high- and band-pass filters will not work correctly. /// filter. As in, this matches the frequency response magnitudes of applying those biquads to a
/// The algorithm works as follows: /// signal twice. This only works for low-pass filters, as the function normalizes the result to
/// hae unity gain at the DC bin. The algorithm works as follows:
/// ///
/// - An impulse function (so all zeroes except for the first element) of length `FILTER_LEN / 2 /// - An impulse function (so all zeroes except for the first element) of length `FILTER_LEN / 2
/// + 1` is filtered with the biquad. /// + 1` is filtered with the biquad.
@ -241,7 +242,7 @@ impl FirCoefficients {
/// this starts at unity gain for the first sample and then tapers off towards the right. /// this starts at unity gain for the first sample and then tapers off towards the right.
/// - The impulse response is then normalized such that the final linear-phase FIR kernel has a /// - The impulse response is then normalized such that the final linear-phase FIR kernel has a
/// sum of 1.0. Since it will be symmetrical around the IRs first sample, the would-be final /// sum of 1.0. Since it will be symmetrical around the IRs first sample, the would-be final
/// sum can be computed as `ir.sum() * 2 - ir[0]`> /// sum can be computed as `ir.sum() * 2 - ir[0]`.
/// ///
/// Lastly the linear phase FIR filter simply needs to be constructed from this right half: /// Lastly the linear phase FIR filter simply needs to be constructed from this right half:
/// ///
@ -251,7 +252,7 @@ impl FirCoefficients {
/// the coefficients. (one of the copies doesn't need to include the centermost coefficient) /// the coefficients. (one of the copies doesn't need to include the centermost coefficient)
/// ///
/// The corresponding high-pass filter can be computed through spectral inversion. /// The corresponding high-pass filter can be computed through spectral inversion.
pub fn design_linear_phase_low_pass_from_biquad( pub fn design_fourth_order_linear_phase_low_pass_from_biquad(
biquad_coefs: BiquadCoefficients<f32x2>, biquad_coefs: BiquadCoefficients<f32x2>,
) -> Self { ) -> Self {
const CENTER_IDX: usize = FILTER_SIZE / 2; const CENTER_IDX: usize = FILTER_SIZE / 2;
@ -286,8 +287,8 @@ impl FirCoefficients {
*sample *= f32x2::splat(0.42 - (0.5 * cos_1) + (0.08 * cos_2)); *sample *= f32x2::splat(0.42 - (0.5 * cos_1) + (0.08 * cos_2));
} }
// Since this final filter will be symmetrical around `impulse_response[CENTER_IDX]`, we can // Since this final filter will be symmetrical around `impulse_response[CENTER_IDX]`, we
// simply normalized based on that fact: // can simply normalize based on that fact:
let would_be_impulse_response_sum = let would_be_impulse_response_sum =
impulse_response.iter().skip(CENTER_IDX - 1).sum::<f32x2>() * f32x2::splat(2.0) impulse_response.iter().skip(CENTER_IDX - 1).sum::<f32x2>() * f32x2::splat(2.0)
- impulse_response[CENTER_IDX]; - impulse_response[CENTER_IDX];