mirror of https://github.com/thesofproject/sof.git
115 lines
3.3 KiB
Matlab
115 lines
3.3 KiB
Matlab
function crossover = crossover_gen_coefs(fs, fc_low, fc_mid, fc_high)
|
|
|
|
addpath ./../eq/
|
|
switch nargin
|
|
case 2, crossover = crossover_generate_2way(fs, fc_low);
|
|
case 3, crossover = crossover_generate_3way(fs, fc_low, fc_mid);
|
|
case 4, crossover = crossover_generate_4way(fs, fc_low, fc_mid, fc_high);
|
|
otherwise, error("Invalid number of arguments");
|
|
end
|
|
rmpath ./../eq
|
|
end
|
|
|
|
function crossover_2way = crossover_generate_2way(fs, fc)
|
|
crossover_2way.lp = [lp_iir(fs, fc, 0)];
|
|
crossover_2way.hp = [hp_iir(fs, fc, 0)];
|
|
end
|
|
|
|
function crossover_3way = crossover_generate_3way(fs, fc_low, fc_high)
|
|
% Duplicate one set of coefficients. The duplicate set will be used to merge back the
|
|
% output that is out of phase.
|
|
crossover_3way.lp = [lp_iir(fs, fc_low, 0) lp_iir(fs, fc_high, 0) lp_iir(fs, fc_high, 0)];
|
|
crossover_3way.hp = [hp_iir(fs, fc_low, 0) hp_iir(fs, fc_high, 0) hp_iir(fs, fc_high, 0)];
|
|
end
|
|
|
|
function crossover_4way = crossover_generate_4way(fs, fc_low, fc_mid, fc_high)
|
|
crossover_4way.lp = [lp_iir(fs, fc_low, 0) lp_iir(fs, fc_mid, 0) lp_iir(fs, fc_high, 0)];
|
|
crossover_4way.hp = [hp_iir(fs, fc_low, 0) hp_iir(fs, fc_mid, 0) hp_iir(fs, fc_high, 0)];
|
|
end
|
|
|
|
% Generate the a,b coefficients for a second order
|
|
% low pass butterworth filter
|
|
function lp = lp_iir(fs, fc, gain_db)
|
|
[lp.b, lp.a] = low_pass_2nd_resonance(fc, 0, fs);
|
|
end
|
|
|
|
% Generate the a,b coefficients for a second order
|
|
% low pass butterworth filter
|
|
function hp = hp_iir(fs, fc, gain_db)
|
|
[hp.b, hp.a] = high_pass_2nd_resonance(fc, 0, fs);
|
|
end
|
|
|
|
function [b, a] = high_pass_2nd_resonance(f, resonance, fs)
|
|
cutoff = f/(fs/2);
|
|
% Limit cutoff to 0 to 1.
|
|
cutoff = max(0.0, min(cutoff, 1.0));
|
|
|
|
if cutoff == 1 || cutoff == 0
|
|
% When cutoff is one, the z-transform is 0.
|
|
% When cutoff is zero, we need to be careful because the above
|
|
% gives a quadratic divided by the same quadratic, with poles
|
|
% and zeros on the unit circle in the same place. When cutoff
|
|
% is zero, the z-transform is 1.
|
|
|
|
b = [1 - cutoff, 0, 0];
|
|
a = [1, 0, 0];
|
|
return;
|
|
end
|
|
|
|
% Compute biquad coefficients for highpass filter
|
|
resonance = max(0.0, resonance); % can't go negative
|
|
g = 10.0^(0.05 * resonance);
|
|
d = sqrt((4 - sqrt(16 - 16 / (g * g))) / 2);
|
|
|
|
theta = pi * cutoff;
|
|
sn = 0.5 * d * sin(theta);
|
|
beta = 0.5 * (1 - sn) / (1 + sn);
|
|
gamma = (0.5 + beta) * cos(theta);
|
|
alpha = 0.25 * (0.5 + beta + gamma);
|
|
|
|
b0 = 2 * alpha;
|
|
b1 = 2 * -2 * alpha;
|
|
b2 = 2 * alpha;
|
|
a1 = 2 * -gamma;
|
|
a2 = 2 * beta;
|
|
|
|
b = [b0, b1, b2];
|
|
a = [1.0, a1, a2];
|
|
end
|
|
|
|
function [b, a] = low_pass_2nd_resonance(f, resonance, fs)
|
|
cutoff = f/(fs/2);
|
|
% Limit cutoff to 0 to 1.
|
|
cutoff = max(0.0, min(cutoff, 1.0));
|
|
|
|
if cutoff == 1 || cutoff == 0
|
|
% When cutoff is 1, the z-transform is 1.
|
|
% When cutoff is zero, nothing gets through the filter, so set
|
|
% coefficients up correctly.
|
|
|
|
b = [cutoff, 0, 0];
|
|
a = [1, 0, 0];
|
|
return;
|
|
end
|
|
|
|
% Compute biquad coefficients for lowpass filter
|
|
resonance = max(0.0, resonance); % can't go negative
|
|
g = 10.0^(0.05 * resonance);
|
|
d = sqrt((4 - sqrt(16 - 16 / (g * g))) / 2);
|
|
|
|
theta = pi * cutoff;
|
|
sn = 0.5 * d * sin(theta);
|
|
beta = 0.5 * (1 - sn) / (1 + sn);
|
|
gamma = (0.5 + beta) * cos(theta);
|
|
alpha = 0.25 * (0.5 + beta - gamma);
|
|
|
|
b0 = 2 * alpha;
|
|
b1 = 2 * 2 * alpha;
|
|
b2 = 2 * alpha;
|
|
a1 = 2 * -gamma;
|
|
a2 = 2 * beta;
|
|
|
|
b = [b0, b1, b2];
|
|
a = [1.0, a1, a2];
|
|
end
|