|
| 1 | +function status = test_linkwitz_riley(modus) |
| 2 | +%TEST_LINKWITZ_RILEY tests the design of the Linkwitz-Riley Filters |
| 3 | +% |
| 4 | +% Usage: status = test_linkwitz_riley(modus) |
| 5 | +% |
| 6 | +% Input parameters: |
| 7 | +% modus - 0: numerical |
| 8 | +% 1: visual |
| 9 | +% |
| 10 | +% Output parameters: |
| 11 | +% status - true or false |
| 12 | + |
| 13 | +%***************************************************************************** |
| 14 | +% The MIT License (MIT) * |
| 15 | +% * |
| 16 | +% Copyright (c) 2010-2019 SFS Toolbox Developers * |
| 17 | +% * |
| 18 | +% Permission is hereby granted, free of charge, to any person obtaining a * |
| 19 | +% copy of this software and associated documentation files (the "Software"), * |
| 20 | +% to deal in the Software without restriction, including without limitation * |
| 21 | +% the rights to use, copy, modify, merge, publish, distribute, sublicense, * |
| 22 | +% and/or sell copies of the Software, and to permit persons to whom the * |
| 23 | +% Software is furnished to do so, subject to the following conditions: * |
| 24 | +% * |
| 25 | +% The above copyright notice and this permission notice shall be included in * |
| 26 | +% all copies or substantial portions of the Software. * |
| 27 | +% * |
| 28 | +% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * |
| 29 | +% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * |
| 30 | +% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * |
| 31 | +% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * |
| 32 | +% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * |
| 33 | +% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * |
| 34 | +% DEALINGS IN THE SOFTWARE. * |
| 35 | +% * |
| 36 | +% The SFS Toolbox allows to simulate and investigate sound field synthesis * |
| 37 | +% methods like wave field synthesis or higher order ambisonics. * |
| 38 | +% * |
| 39 | +% http://sfstoolbox.org sfstoolbox@gmail.com * |
| 40 | +%***************************************************************************** |
| 41 | + |
| 42 | +status = false; |
| 43 | + |
| 44 | +%% ===== Checking of input parameters =================================== |
| 45 | +nargmin = 1; |
| 46 | +nargmax = 1; |
| 47 | +narginchk(nargmin,nargmax); |
| 48 | + |
| 49 | +%% ===== Main ============================================================ |
| 50 | +fs = 44100; % sampling frequency in Hz |
| 51 | +fc = 1000; % crossover frequency in Hz |
| 52 | +f = logspace(-3,log10(fs/2),10000); % frequeny-axis in Hz |
| 53 | +omega = 2*pi*f; % angular frequency |
| 54 | + |
| 55 | +ftype = {'low' 'high' 'all'}; % filter types |
| 56 | +Hs = zeros(3,length(f)); % s-domain frequency spectra |
| 57 | +Hz = Hs; % z-domain frequency spectra |
| 58 | + |
| 59 | +for Nlr = [2 4 12] % filter orders |
| 60 | + |
| 61 | + for tdx = 1:3 |
| 62 | + % Laplace-Domain |
| 63 | + [zs,ps,ks] = linkwitz_riley(Nlr,2*pi*fc,ftype{tdx},'s'); |
| 64 | + [soss,gs] = zp2sos(zs,ps,ks,'down','none'); |
| 65 | + |
| 66 | + s = [-omega.^2; 1i*omega]; |
| 67 | + s(3,:) = 1; |
| 68 | + |
| 69 | + if isoctave && strcmp(ftype{tdx}, 'low') |
| 70 | + % WORKAROUND for Octave bug (https://savannah.gnu.org/bugs/?51936) |
| 71 | + Hs(tdx,:) = gs.*prod( (soss(:,3:-1:1)*s)./(soss(:,4:6)*s),1); |
| 72 | + else |
| 73 | + Hs(tdx,:) = gs.*prod( (soss(:,1:3)*s)./(soss(:,4:6)*s),1); |
| 74 | + end |
| 75 | + |
| 76 | + % z-Domain |
| 77 | + [zz,pz,kz] = linkwitz_riley(Nlr,fc./fs*2,ftype{tdx},'z'); |
| 78 | + [sosz,gz] = zp2sos(zz,pz,kz,'down','none'); |
| 79 | + |
| 80 | + z = [exp(0.*omega./fs); exp(-1j.*omega./fs); exp(-2j.*omega./fs)]; |
| 81 | + Hz(tdx,:) = gz.*prod( (sosz(:,1:3)*z)./(sosz(:,4:6)*z),1); |
| 82 | + end |
| 83 | + |
| 84 | + % plotting |
| 85 | + if modus |
| 86 | + figure; |
| 87 | + subplot(2,2,1); |
| 88 | + plot_amp(f, Hs); |
| 89 | + title(sprintf('Amplitude Spectrum, s-Domain, order=%d', Nlr)); |
| 90 | + subplot(2,2,2); |
| 91 | + plot_phase(f, Hs); |
| 92 | + title(sprintf('Phase Spectrum, s-Domain, order=%d', Nlr)); |
| 93 | + subplot(2,2,3); |
| 94 | + plot_amp(f, Hz); |
| 95 | + title(sprintf('Amplitude Spectrum, z-Domain, order=%d', Nlr)); |
| 96 | + subplot(2,2,4); |
| 97 | + plot_phase(f, Hz); |
| 98 | + title(sprintf('Phase Spectrum, z-Domain, order=%d', Nlr)); |
| 99 | + end |
| 100 | +end |
| 101 | + |
| 102 | +status = true; |
| 103 | + |
| 104 | +end |
| 105 | + |
| 106 | +function plot_amp(f, H) |
| 107 | +semilogx( ... |
| 108 | + f, db(H(1,:)), 'b', ... |
| 109 | + f, db(H(2,:)), 'r', ... |
| 110 | + f, db(H(1,:)+H(2,:)), 'g.', ... |
| 111 | + f, db(H(3,:)), 'k--' ... |
| 112 | + ); |
| 113 | +legend('Lowpass', 'Highpass', 'Lowpass + Highpass', 'Allpass', 'Location', 'southwest'); |
| 114 | +xlabel('f / Hz'); |
| 115 | +ylabel('20 lg |H| / dB') |
| 116 | +xlim([f(1), f(end)]); |
| 117 | +ylim([-90, 10]); |
| 118 | +end |
| 119 | + |
| 120 | +function plot_phase(f, H) |
| 121 | +semilogx( ... |
| 122 | + f, unwrap(angle(H(1,:))), 'b', ... |
| 123 | + f, unwrap(angle(H(2,:))), 'r', ... |
| 124 | + f, unwrap(angle(H(1,:)+H(2,:))), 'g.', ... |
| 125 | + f, unwrap(angle(H(3,:))), 'k--' ... |
| 126 | + ); |
| 127 | +legend('Lowpass', 'Highpass', 'Lowpass + Highpass', 'Allpass', 'Location', 'southwest'); |
| 128 | +xlabel('f / Hz'); |
| 129 | +ylabel('angle(H) / rad') |
| 130 | +xlim([f(1), f(end)]); |
| 131 | +end |
0 commit comments