The least squares design of linear phase filters is a special case, and its solution is implemented in the Matlab/Octave function firls.m. Here I want to describe the general case of approximating a complex desired frequency response, i.e., a response that prescribes not only the magnitude but also the phase response of the filter. If the prescribed phase response is linear and if the corresponding delay matches the chosen filter length, then the resulting filter will have a linear phase. Otherwise, the designed filter will have a non-linear phase response approximating the prescribed phase response.
The described method cannot only design filters with real-valued coefficients but it can also design FIR filters with complex coefficients. This is simply achieved by prescribing a complex desired frequency response that is not conjugate symmetric. Let D(ejω) denote the complex desired frequency response. A complex FIR filter is obtained if D(ejω)≠D∗(e−jω)
Define the complex desired frequency D(ejω) on a dense grid of frequencies ωi, i=1…M, in the interval (−π,π]. Let H(ejω) be the frequency response of the FIR filter with coefficients h[n]: H(ejω)=N−1∑n=0h[n]e−jnω
It can be desirable to modify (1) by introducing a strictly positive weight function W(ω). For notational convenience when formulating the least squares problem we use the square root of W(ω) in the overdetermined system: √W(ω)H(ejωi)!=√W(ω)D(ejωi),i=1…M
For formulating the weighted least squares approximation problem it is advantageous to write (2) in matrix notation. Let C be a complex M×N matrix with rows ci given by ci=[1,e−jωi,e−2jωi,…,e−(N−1)jωi]
Solving (3) in a least squares sense is equivalent to minimizing the following error measure: ϵ=M∑i=1W(ωi)|H(ejωi)−D(ejωi)|2=(Ch−d)HW(Ch−d)=hHCHWCh−hHCHWd−dHWCh+dHd
Minimizing (4) results in the following N×N system of linear equations for the unknown filter coefficients: CHWCh=CHWd
Now we can either solve (5) using some linear equation solver, or we can directly use the overdetermined system (3) as input to a QR-solver. Matlab and Octave offer both possibilities with the backslash `\` operator. Solving the overdetermined system directly using a QR-solver has numerical advantages, whereas solving the square system (5) has the advantage that no matrix needs to be stored because the system matrix CHWC has a Toeplitz structure, and is therefore completely determined by its first row. Such a system can be solved efficiently using Levinson's algorithm.
In general, the solutions to (3) and (5) are complex-valued. If we want to design real-valued filters, then for every frequency point ωi>0 there must be a point −ωi for which D(e−jωi)=D∗(ejωi) and W(−ωi)=W(ωi) are satisfied. Another more efficient way to guarantee real-valued solutions is to slightly modify the systems (3) and (5). With these modifications we only need to specify frequency points in the interval [0,π]. The overdetermined system (3) becomes [W1/2CRW1/2CI]h!=[W1/2dRW1/2dI]
I've implemented the method described above in the Matlab/Octave function cfirls.ml:
function h = cfirls(N,f,d,w,hreal) | |
% function h = cfirls(N,f,d,w,hreal) | |
% Least-squares FIR filter design with prescribed magnitude and phase | |
% responses and with possibly complex coefficients | |
% | |
% h real or complex-valued impulse response | |
% N desired filter length | |
% f frequency grid | |
% for complex-valued filters ('hreal=0'): -1 <= f < 1 | |
% ( '1' corresponds to Nyquist) or 0 <= f < 2 | |
% for real-valued filters ('hreal=1'): 0 <= f <= 1 | |
% d desired complex-valued frequency response on the grid f: | |
% d = ( desired_magnitude ) .* exp( 1i * desired_phase ) | |
% w (positive) weighting function on the grid f | |
% hreal flag for constraining the filter coefficients h to be real-valued | |
% hreal=1: h is real-valued | |
% hreal=0: h can be complex-valued | |
% h will be real-valued (up to numerical accuracy) if for | |
% every grid point f[i] there is a point -f[i] and the | |
% desired response at -f[i] is the complex conjugate of d | |
% at f[i], and the weights at f[i] and -f[i] must be equal | |
% differences with firls.m: | |
% 1. the desired phase response can be non-linear | |
% 2. the filter coefficients can be complex (i.e., the specified | |
% frequency response does not need to be symmetrical) | |
% 3. the desired magnitude doesn't need to be piecewise linear, | |
% but it is specified as a vector defined on a frequency grid | |
% 4. the weighting does not need to be piecewise constant | |
% EXAMPLE 1: real-valued linear phase bandpass filter | |
% N = 61; | |
% tau = (N-1)/2; | |
% f = [linspace(0,.23,230),linspace(.3,.5,200),linspace(.57,1,430)]; | |
% d = [zeros(1,230),ones(1,200),zeros(1,430)] .* exp(-j*tau*pi*f); | |
% w = [10*ones(1,230),ones(1,200),10*ones(1,430)]; | |
% h = cfirls(N,f,d,w,1); | |
% EXAMPLE 2: same as Ex. 1 but with reduced delay in the passband | |
% N = 61; | |
% tau = 25; | |
% f = [linspace(0,.23,230),linspace(.3,.5,200),linspace(.57,1,430)]; | |
% d = [zeros(1,230),ones(1,200),zeros(1,430)] .* exp(-j*tau*pi*f); | |
% w = [10*ones(1,230),ones(1,200),10*ones(1,430)]; | |
% h = cfirls(N,f,d,w,1); | |
% EXAMPLE 3: linear phase complex low pass filter | |
% N = 51; | |
% tau = (N-1)/2; | |
% f = [linspace(-1,-.18,328),linspace(-.1,.3,160),linspace(.38,1,248)]; | |
% d = [zeros(1,328),ones(1,160),zeros(1,248)].*exp(-1i*pi*f*tau); | |
% w = [10*ones(1,328),ones(1,160),10*ones(1,248)]; | |
% h = cfirls(N,f,d,w); | |
% EXAMPLE 4: same as Ex. 3 but with reduced delay in the passband | |
% N = 51; | |
% tau = 20; | |
% f = [linspace(-1,-.18,328),linspace(-.1,.3,160),linspace(.38,1,248)]; | |
% d = [zeros(1,328),ones(1,160),zeros(1,248)].*exp(-1i*pi*f*tau); | |
% w = [10*ones(1,328),ones(1,160),10*ones(1,248)]; | |
% h = cfirls(N,f,d,w); | |
% | |
% author: Mathias Lang, 2018-01-01 | |
% revision 2022-10-17: added option 'hreal' for designing exactly | |
% real-valued filters | |
% mattsdspblog@gmail.com | |
% check arguments | |
if ( nargin > 5 | nargin < 4 ), | |
error('wrong number of input arguments'); | |
end | |
if ( nargin == 4 ), hreal = 0; end | |
L = length(f); | |
if ( length(d) ~= L ), error('d and f must have the same lengths.'); end | |
if ( length(w) ~= L ), error('w and f must have the same lengths.'); end | |
if ( N < 1 ), error('N must be greater than 0.'); end | |
if ~all( w ), | |
error('All elements of the weight vector w must be positive.'); | |
end | |
minf = min(f); maxf = max(f); | |
if ( hreal ), | |
if ( minf < 0 | maxf > 1 ), | |
error('f must be in the range [0,1] for real-valued filters.'); | |
end | |
else | |
if ~( ( minf >= -1 & maxf <= 1 ) | ( minf >= 0 & maxf <= 2 ) ), | |
error('f must be in the interval [-1,1) or [0,2).'); | |
end | |
end | |
f = f(:); | |
d = d(:); | |
w = sqrt(w(:)); | |
% solve overdetermined system in a least squares sense | |
A = w( :, ones(1,N) ) .* exp( -1i * pi * f * (0:N-1) ); | |
b = w .* d; | |
if ( hreal ) | |
h = [real(A); imag(A)] \ [real(b); imag(b)]; | |
else | |
h = A \ b; | |
end |
No comments:
Post a Comment