Skip to content

Instantly share code, notes, and snippets.

@janeshdev
Created June 24, 2013 00:55
Show Gist options
  • Save janeshdev/5847127 to your computer and use it in GitHub Desktop.
Save janeshdev/5847127 to your computer and use it in GitHub Desktop.
Lanczos filter code by Carlos Adrián Vargas Aguilera. [email protected]
function [y,coef,window,Cx,Ff] = lanczosfilter(x,varargin)
%LANCZOSFILTER Filters a time series via Lanczos method (cosine filter).
% [Y,coef,window,Cx,Ff] = LANCZOSFILTER(X,dT,Cf,M,pass) Filters the time
% series via the Lanczos filter in the frequency space (FFT), where
%
% INPUTS:
% X - Time series
% dT - Sampling interval (default: 1)
% Cf - Cut-off frequency (default: half Nyquist)
% M - Number of coefficients (default: 100)
% pass - Low or high-pass filter (default: 'low')
%
% OUTPUTS:
% Y - Filtered time series
% coef - Coefficients of the time window (cosine)
% window - Frequency window (aprox. ones for Ff lower(greater) than Fc
% if low(high)-pass filter and ceros otherwise)
% Cx - Complex Fourier Transform of X for Ff frequencies
% Ff - Fourier frequencies, from 0 to the Nyquist frequency.
%
% The program removes from the time series the frequencies greater than
% the cut off frequency if "pass" is 'low', i.e., low-pass filter .
% Otherwise, if pass is 'high', frequencies from zero to Cf are removed,
% i.e., a high-pass filter. Units of the cut-off frequency, [Cf], must be
% [dT]^{-1}.
%
% In consequence, when used as a low-pass the time series is smoothed
% like a cosine filter in time space with M coefficients where greater is
% better (see the reference).
%
% If any option is empty, defaults are used.
%
% Note: NaN's elements are replaced by the mean of the time series and
% ignored. If you have a better idea, just let me know.
%
% Reference:
% Emery, W. J. and R. E. Thomson. "Data Analysis Methods in Physical
% Oceanography". Elsevier, 2d ed., 2004. On pages 533-539.
%
% Example:
% dT = 30; % min
% N = 7*24*60/dT; t = (0:N-1)*dT; % data for 7 days
% pnoise = 0.30;
% T1 = 12.4*60; T2 = 24*60; T3 = 15*24*60; Tc = 10*60; % min
% xn = 5 + 3*cos(2*pi*t/T1) + 2*cos(2*pi*t/T2) + 1*cos(2*pi*t/T3);
% xn = xn + pnoise*max(xn-mean(xn))*(0.5 - rand(size(xn)));
% [xs,c,h,Cx,f] = lanczosfilter(xn,dT,1/Tc,[],'low');
% subplot(211), plot(t,xn,t,xs), legend('noisy','smooth'), axis tight
% subplot(212), plot(f,h,f,abs(Cx)/max(abs(Cx)),...
% [1 1]/Tc,[min(h) max(h)],'-.',...
% [1/T1 1/T2 1/T3],([1/T1 1/T2 1/T3]<=1/Tc),'o'), axis tight
%
% See also FILTER, FFT, IFFT
% Written by
% Lic. on Physics Carlos Adrián Vargas Aguilera
% Physical Oceanography MS candidate
% UNIVERSIDAD DE GUADALAJARA
% Mexico, 2004
%
% [email protected]
% Check arguments:
if nargin<1 || nargin>5
error('Lanczosfilter:ArgumentNumber','Incorrect number of arguments.')
elseif ~isvector(x) || ~isreal(x)
error('Lanczosfilter:ArgumentType','Incorrect time series.')
end
if nargin<2 || isempty(varargin{1})
dT = 1;
elseif ~(numel(varargin{1})==1) || ~isreal(varargin{1})
error('Lanczosfilter:ArgumentType','Incorrect time interval.')
else
dT = varargin{1};
end
Nf = 1/(2*dT); % Nyquist frequency
if nargin<3 || isempty(varargin{2})
Cf = Nf/2;
elseif ~(numel(varargin{2})==1) || ~isreal(varargin{2}) || varargin{2}<=0 || varargin{2}>Nf
error('Lanczosfilter:ArgumentType','Incorrect cut-off frequency.')
else
Cf = varargin{2};
end
if nargin<4 || isempty(varargin{3})
M = 100;
elseif ~(numel(varargin{3})==1) || ~isreal(varargin{3}) || (varargin{3}==round(varargin{3}))
error('Lanczosfilter:ArgumentType','Incorrect Number of coeffients.')
else
M = varargin{3};
end
if nargin<5 || isempty(varargin{4})
LoH = 'l';
elseif ~ischar(varargin{4}) || isempty(strfind('lh',lower(varargin{4}(1))))
error('Lanczosfilter:ArgumentType','Incorrect filter pass type.')
else
LoH = varargin{4};
end
if strcmpi(LoH(1),'h')
LoH = 2;
else
LoH = 1;
end
% Normalize the cut off frequency with the Nyquist frequency:
Cf = Cf/Nf;
% Lanczos cosine coeficients:
coef = lanczos_filter_coef(Cf,M); coef = coef(:,LoH);
% Filter in frequency space:
[window,Ff] = spectral_window(coef,length(x)); Ff = Ff*Nf;
% Replace NaN's with the mean (ideas?):
inan = isnan(x);
xmean = mean(x(~inan));
x(inan) = xmean;
% Filtering:
[y,Cx] = spectral_filtering(x,window);
function coef = lanczos_filter_coef(Cf,M)
% Positive coeficients of Lanczos [low high]-pass.
hkcs = lowpass_cosine_filter_coef(Cf,M);
sigma = [1 sin(pi*(1:M)/M)./(pi*(1:M)/M)];
hkB = hkcs.*sigma;
hkA = -hkB; hkA(1) = hkA(1)+1;
coef = [hkB(:) hkA(:)];
function coef = lowpass_cosine_filter_coef(Cf,M)
% Positive coeficients of cosine filter low-pass.
coef = Cf*[1 sin(pi*(1:M)*Cf)./(pi*(1:M)*Cf)];
function [window,Ff] = spectral_window(coef,N)
% Window of cosine filter in frequency space.
Ff = 0:2/N:1; window = zeros(length(Ff),1);
for i = 1:length(Ff)
window(i) = coef(1) + 2*sum(coef(2:end).*cos((1:length(coef)-1)'*pi*Ff(i)));
end
function [y,Cx] = spectral_filtering(x,window)
% Filtering in frequency space is multiplication, (convolution in time
% space).
Nx = length(x);
Cx = fft(x(:)); Cx = Cx(1:floor(Nx/2)+1);
CxH = Cx.*window(:);
CxH(length(CxH)+1:Nx) = conj(CxH(Nx-length(CxH)+1:-1:2));
y = real(ifft(CxH));
% Carlos Adrián Vargas Aguilera. [email protected]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment