gusucode.com > 信号处理工具箱 - signal源码程序 > signal\signal\signal\dpss.m
function [E,V]=dpss(N, NW, varargin) %DPSS Discrete prolate spheroidal sequences (Slepian sequences). % [E,V] = DPSS(N,NW) are the first 2*NW discrete prolate spheroidal sequences % (DPSSs, or Slepian sequences) of length N (in the columns of E) and % their corresponding concentrations (in vector V) in the frequency band % |w|<=(2*pi*W) (where W = NW/N is the half-bandwidth and w is in radians). % E(:,1) is the length N signal most concentrated in the frequency band % |w|<=(2*pi*W) radians, E(:,2) is the signal orthogonal to E(:,1) which % is most concentrated in this band, E(:,3) is the signal orthogonal to % both E(:,1) and E(:,2) which is most concentrated in this band, etc. % % For multi-taper spectral analysis, typical choices for NW are 2, 5/2, 3, % 7/2, or 4. % % [E,V] = DPSS(N,NW,K) are the K most band-limited discrete prolate spheroidal % sequences. [E,V] = DPSS(N,NW,[K1 K2]) returns the K1-th through the % K2-th sequences. % % [E,V] = DPSS(N,NW,'spline') uses spline interpolation to compute the DPSSs % from existing DPSSs in the DPSS database with length closest to N. % [E,V] = DPSS(N,NW,'spline',Ni) interpolates from existing length Ni DPSSs. % DPSS(N,NW,'linear') and DPSS(N,NW,'linear',Ni) use linear interpolation, % which is much faster but less accurate than spline interpolation. % 'linear' requires Ni > N. % % Use a trailing 'trace' argument to find out which method DPSS uses, e.g. % DPSS(N,NW,'trace') or DPSS(N,NW,'int','trace'). % % See also PMTM, DPSSLOAD, DPSSDIR, DPSSSAVE, DPSSCLEAR. % Author: Eric Breitenberger, 10/3/95 % Copyright (c) 1988-98 by The MathWorks, Inc. % $Revision: 1.1 $ $Date: 1998/06/03 14:42:29 $ method = 'calc'; TRACE = 'notrace'; Ni = []; k = min(round(2*NW),N); % Default number of sequences to return k = max(k,1); if nargin > 2 if ~isstr(varargin{1}) k = varargin{1}; if isempty(k) | any(k~=round(abs(k))) | any(k>N) | length(k)>2 error('K must be a positive integer in the range 1:N') end else method = lower(varargin{1}); if strcmp(method,'trace') method = 'calc'; TRACE = 'trace'; end end end if nargin > 3 if isstr(varargin{2}) TRACE = lower(varargin{2}); else Ni = varargin{2}; end end if nargin > 4 TRACE = lower(varargin{3}); end if NW >= N/2 error('NW must be less than N/2.') end switch method case 'calc' if strcmp(TRACE,'trace') disp('Computing the DPSS using direct algorithm...') end [E,V] = dpsscalc(N,NW,k); case {'spline','linear'} errmsg = ''; if isempty(Ni) ind = dpssdir(NW,'NW'); if ~isempty(ind) Nlist = [ind.N]; % find closest length and use that one [dum,i] = min(abs(N-Nlist)); Ni = Nlist(i); if strcmp(method,'linear') & Ni<N if i<length(Nlist) Ni = Nlist(i+1); else Ni = []; errmsg = sprintf('No DPSS with NW = %g and N > %g in database.',NW,N); end end else errmsg = sprintf('No DPSS with NW = %g in database.',NW); end end error(errmsg) if strcmp(TRACE,'trace') disp(['Computing DPSS using ' method ' interpolation from length ' int2str(Ni) '...']) end [E,V]=dpssint(N,NW,Ni,method); otherwise error('Method string should be ''calc'', ''spline'' or ''linear''.') end %------------------------------------ function [E,V] = dpsscalc(N,NW,k) %DPSSCALC Calculate slepian sequences. % [E,V] = dpsscalc(N,NW,k) uses tridieig() to get eigenvalues 1:k if k is % a scalar, and k(1):k(2) if k is a matrix, of the sparse tridiagonal matrix. % It then uses inverse iteration using the exact eigenvalues on a starting % vector with approximate shape, to get the eigenvectors required. It then % computes the eigenvalues V of the Toeplitz sinc matrix using a fast % autocorrelation technique. % Authors: T. Krauss, C. Moler, E. Breitenberger W=NW/N; if nargin < 3 k = min(round(2*N*W),N); k = max(k,1); end if length(k) == 1 k = [1 k]; end % Generate the diagonals d=((N-1-2*(0:N-1)').^2)*.25*cos(2*pi*W); % diagonal of B ee=(1:N-1)'.*(N-1:-1:1)'/2; % super diagonal of B % Get the eigenvalues of B. v = tridieig(d,[0; ee],N-k(2)+1,N-k(1)+1); v = v(end:-1:1); Lv = length(v); %B = spdiags([[ee;0] d [0;ee]],[-1 0 1],N,N); %I = speye(N,N); % Compute the eigenvectors by inverse iteration with % starting vectors of roughly the right shape. E = zeros(N,k(2)-k(1)+1); t = (0:N-1)'/(N-1)*pi; warn_save = warning; warning('off') % Turn off warnings in case tridisolve encounters % an exactly singular matrix. for j = 1:Lv e = sin((j+k(1)-1)*t); e = tridisolve(ee,d-v(j),e,N); e = tridisolve(ee,d-v(j),e/norm(e),N); e = tridisolve(ee,d-v(j),e/norm(e),N); E(:,j) = e/norm(e); end warning(warn_save) d=mean(E); for i=k(1):k(2) if rem(i,2) % i is odd % Polarize symmetric dpss if d(i-k(1)+1)<0, E(:,i-k(1)+1)=-E(:,i-k(1)+1); end else % i is even % Polarize anti-symmetric dpss if E(2,i-k(1)+1)<0, E(:,i-k(1)+1)=-E(:,i-k(1)+1); end end end % get eigenvalues of sinc matrix % Reference: Percival & Walden, Exercise 8.1, p.390 s = [2*W; 4*W*sinc(2*W*(1:N-1)')]; q = zeros(size(E)); blksz = Lv; % <-- set this to some small number if OUT OF MEMORY!!! for i=1:blksz:Lv blkind = i:min(i+blksz-1,Lv); q(:,blkind) = fftfilt(E(N:-1:1,blkind),E(:,blkind)); end V = q'*flipud(s); % return 1 for any eigenvalues greater than 1 due to finite precision errors V = min(V,1); % return 0 for any eigenvalues less than 0 due to finite precision errors V = max(V,0); %------------------------------------ function [En,V] = dpssint(N, NW, M, int, E,V) % Syntax: [En,V]=dpssint(N,NW); [En,V]=dpssint(N,NW,M,'spline'); % Dpssint calculates discrete prolate spheroidal % sequences for the parameters N and NW. Note that % NW is normally 2, 5/2, 3, 7/2, or 4 - not i/N. The % dpss are interpolated from previously calculated % dpss of order M (128, 256, 512, or 1024). 256 is the % default for M. The interpolation can be 'linear' % or 'spline'. 'Linear' is faster, 'spline' the default. % Linear interpolation can only be used for M>N. % Returns: % E: matrix of dpss (N by 2NW) % V: eigenvalue vector (2NW) % % Errors in the interpolated dpss are very small but should be % checked if possible. The differences between interpolated % values and values from dpsscalc are generally of order % 10ee-5 or better. Spline interpolation is generally more % accurate. Fractional errors can be very large near % the zero-crossings but this does not seriously affect % windowing calculations. The error can be reduced by using % values for M which are close to N. % % Written by Eric Breitenberger, version date 10/3/95. % Please send comments and suggestions to eric@gi.alaska.edu % W = NW/N; if nargin==2, M=256; int='spline'; elseif nargin==3, if isstr(M), int=M; M=256; else, int='spline';, end end if int=='linear' & N>M error('Linear interpolation cannot be used for N>M. Use splining instead.') end if nargin<=4 [E,V] = dpssload(M,NW); else if size(E,1)~=M error('M and row size of E don''t match.') end end k=min(round(2*NW),N); % Return only first k values k = max(k,1); E=E(:,1:k); V=V(1:k); x=1:M; % The scaling for the interpolation: % This is not necessarily optimal, and % changing s can improve accuracy. s=M/N; midm=(M+1)/2; midn=(N+1)/2; delta=midm-s*midn; xi=linspace(1-delta, M+delta, N); % Interpolate from M values to N % Spline interpolation is a bit better, % but takes about twice as long. % Errors from linear interpolation are % usually smaller than errors from scaling. En=interp1(x,E,xi,['*' int]); % Re-normalize the eigenvectors En=En./(ones(N,1)*sqrt(sum(En.*En)));