I have been working on making a 3-band audio crossover in C++, with the goal of activating/deactivating a different device depending on whether the low, mid, or high range of the input is above a threshold. I got as far as using GNU Octave to generate and graph out the low, band, and high pass filter coefficients using the Elliptic IIR method. I'm pleased with the coefficient characteristics, but this is my first DSP software project so I don't know how to use them to actually implement the filter program.
I looked at a bunch of articles on the topic online, and I saw people say using the Biquad Direct type 2 form is the most efficient approach for this situation. When I looked at the math on Wikipedia I understood the concepts somewhat but became confused as to how to implement it, partially because the order of my filters is greater than 2, and partially because comparing the formulas to other sources it seems like there might even be a mistake in the Wiki source??
I feel like I am incredibly close to understanding what to do, but I need that final nudge in the right direction.
I'm not sure if it is helpful at this stage, but here is what I have made in Octave so far:
function iir_elliptic_version
clf
close all
pkg load signal;
sample_freq = 192000;
[lp_nums, lp_denoms] = Gen_Low_Pass_Filter_Coeffs(159, sample_freq)
[mp_nums, mp_denoms] = Gen_Mid_Pass_Filter_Coeffs(160, 1999, sample_freq)
[hp_nums, hp_denoms] = Gen_High_Pass_Filter_Coeffs(2000, sample_freq)
f = 0:sample_freq/2;
W = f*(2*pi/sample_freq);
H1 = freqz(lp_nums, lp_denoms, W);
H2 = freqz(mp_nums, mp_denoms, W);
H3 = freqz(hp_nums, hp_denoms, W);
plot(f, 20*log10(abs(H1)), f, 20*log10(abs(H2)), f, 20*log10(abs(H3)))
axis([0 4000 -60 20])
title('Filter Frequency Response of Elliptic IIR filters')
xlabel('Frequency (Hz)')
ylabel('Magnitude (dB)')
grid on
endfunction
function [nums, denoms] = Gen_Low_Pass_Filter_Coeffs( passband_end,
Fs)
%This function generates the coefficients for a low pass filter for the
%low range given the passband end frequency, and the sampling rate.
stopband_start = passband_end + 25;
pass_ripple_dB = 5;
atten_dB = 20;
norm_pass_freq = passband_end/(Fs/2);
norm_stop_freq = stopband_start/(Fs/2);
[order, cutoff_radians] = ellipord(norm_pass_freq, norm_stop_freq, pass_ripple_dB, atten_dB);
printf("The order of the low-pass is %d\n", order);
[nums, denoms] = ellip(order, pass_ripple_dB, atten_dB, cutoff_radians);
endfunction
function [nums, denoms] = Gen_Mid_Pass_Filter_Coeffs( passband_start,
passband_end,
Fs)
%This function generates the coefficients for a band pass filter for the
%mid range given the passband start and end frequencies, and the sampling rate.
pass_freqs = [passband_start, passband_end];
stop_freqs = [passband_start - 160, passband_end + 170];
pass_ripple_dB = 5;
atten_dB = 20;
norm_pass_freqs = pass_freqs/(Fs/2);
norm_stop_freqs = stop_freqs/(Fs/2);
[order, cutoff_radians] = ellipord(norm_pass_freqs, norm_stop_freqs, pass_ripple_dB, atten_dB);
printf("The order of the band-pass is %d\n", order);
[nums, denoms] = ellip(order, pass_ripple_dB, atten_dB, cutoff_radians);
endfunction
function [nums, denoms] = Gen_High_Pass_Filter_Coeffs( passband_start,
Fs)
%This function generates the coefficients for a high pass filter for the
%high range given the passband start frequency, and the sampling rate.
stopband_end = passband_start - 25;
pass_ripple_dB = 5;
atten_dB = 20;
norm_pass_freq = passband_start/(Fs/2);
norm_stop_freq = stopband_end/(Fs/2);
[order, cutoff_radians] = ellipord(norm_pass_freq, norm_stop_freq, pass_ripple_dB, atten_dB);
printf("The order of the high-pass is %d\n", order);
[nums, denoms] = ellip(order, pass_ripple_dB, atten_dB, cutoff_radians, 'high');
endfunction