gusucode.com > 信号处理工具箱 - signal源码程序 > signal\signal\signal\pwelch.m
function varargout = pwelch(varargin) %PWELCH Power Spectral Density estimate via Welch's method. % Pxx = PWELCH(X) returns the Power Spectral Density (PSD) estimate, % Pxx(w), of a discrete-time signal vector X using Welch's averaged, % modified periodogram method. Pxx(w) is a function of normalized % angular frequency, w=2*pi*f/Fs [rads/sample]. % % The single-sided PSD is returned for real signals and the % double-sided PSD is returned for complex signals. % % [Pxx,W] = PWELCH(X) returns a frequency vector, W, in units of % rads/sample at which the PSD is estimated. Pxx(w) is computed over % the interval [0, Pi] for a real signal X and over the interval % [0, 2*Pi] for a complex X. % % [Pxx,F] = PWELCH(X,NFFT,Fs) returns the PSD estimate and the frequency % vector, F, in Hz, at which the PSD is estimated. The PSD estimate is % computed over the interval [0, Fs/2] for a real signal X and over the % interval [0, Fs] for a complex X. % % [Pxx,F] = PWELCH(X,NFFT,Fs,WINDOW,NOVERLAP) X is divided into overlap- % ping sections, then windowed by the WINDOW parameter, then zero-padded % to length NFFT. The magnitude squared of the length NFFT DFTs of the % sections are averaged to form Pxx. Pxx is length NFFT/2+1 for NFFT % even, (NFFT+1)/2 for NFFT odd, or NFFT if the signal X is complex. If % you specify a scalar for WINDOW, a Hanning window of that length is % used. % % [Pxx, Pxxc, F] = PWELCH(X,NFFT,Fs,WINDOW,NOVERLAP,P) where P is a % scalar between 0 and 1, returns the P*100% confidence interval for Pxx. % % PWELCH with no output arguments plots the PSD in the current figure % window, with confidence intervals if you provide the P parameter. By % default, PWELCH will plot the power spectral density, in dB per unit % frequency. The plot will have a frequency interval of [0,pi) for a % real signal vector X, and a frequency interval of [0,2pi) for a complex % vector X. If Fs is specified then the intervals become [0,Fs/2) and % [0,Fs), respectively. % % PWELCH(X,NFFT,Fs,WINDOW,NOVERLAP,P,RANGE,MAGUNITS), where RANGE can % be 'half' or 'whole', specifies the frequency intervals [0,Fs/2) and % [0,Fs) respectively. MAGUNITS can be either 'squared' or 'db' and % it specifies the units of the PSD plot. The MAGUNITS option only % affects the plot. To plot the PSD without converting to decibels, % over the interval [0,Fs) for a real X use: % PWELCH(X,NFFT,Fs,WINDOW,NOVERLAP,P,'whole','squared'). % % RANGE can take the place of any parameter in the parameter list % (besides X) as long as it is last, e.g. PWELCH(X,'whole'); % % The default values for the parameters are NFFT = 256 (or LENGTH(X), % whichever is smaller), NOVERLAP = 0, WINDOW = HANNING(NFFT), Fs = 1, % P = .95, RANGE = 'half', and MAGUNITS = 'db'. You can obtain a % default parameter by leaving it off or inserting an empty matrix [], % e.g. PWELCH(X,[],10000). % % See also CSD, COHERE, TFE, PCOV, PMCOV, PBURG, PYULEAR, PEIG, PMTM % and PMUSIC. ETFE, SPA, and ARX in the System Identification Toolbox. % Author(s): P. Pacheco % Copyright (c) 1988-98 by The MathWorks, Inc. % $Revision: 1.14.1.2 $ $Date: 1999/01/22 03:42:33 $ % References: % [1] Petre Stoica and Randolph Moses, Introduction To Spectral % Analysis, Prentice-Hall, 1997, pg. 15 % [2] A.V. Oppenheim and R.W. Schafer, Digital Signal % Processing, Prentice-Hall, 1975, pg. 556 error(nargchk(1,9,nargin)) x = varargin{1}; [params,msg] = pwelchparse(varargin(2:end),x); error(msg); % Extract individual variables from structure; easier to use in calculations nfft = params.nfft; Fs = params.Fs; noverlap = params.noverlap; p = params.p; range = params.range; % Zero-pad x if it has length less than the window length window = params.window(:); n = length(x); % Number of data points nwind = length(window); % length of window if n < nwind x(nwind)=0; n=nwind; end % Make x a column vector; do this AFTER the zero-padding in case x is a scalar. x = x(:); % Number of windows; (k = fix(n/nwind) for noverlap=0) k = fix((n-noverlap)/(nwind-noverlap)); index = 1:nwind; KMU = k*norm(window)^2; % Normalizing scale factor ==> asymptotically unbiased % KMU = k*sum(window)^2;% alt. Nrmlzng scale factor ==> peaks are about right % Calculate PSD Spec = zeros(nfft,1); for i=1:k xw = window.*x(index); index = index + (nwind - noverlap); Xx = abs(fft(xw,nfft)).^2; Spec = Spec + Xx; end % Select first half - real or complex case if strmatch(range,'half'), if rem(nfft,2), % nfft odd select = (2:(nfft+1)/2-1)'; % don't include DC or Nyquist components nyq = (nfft+1)/2; % they're included below else select = (2:nfft/2)'; nyq = nfft/2+1; end if isreal(x), % Calculate the single-sided spectrum which includes the full power Spec = [Spec(1); 2*Spec(select); Spec(nyq)]; else error('Range parameter must be ''WHOLE'' for complex signals.'); end end % Normalize, and scale by 1/Fs or 1/2pi in order to get % Power per unit of frequency if params.fsFlag, % Linear freq (Hz) specified scaleFactor = Fs; else % Using default normalized, angular freq scaleFactor = 2*pi; end Spec = Spec / (KMU *scaleFactor); % Default frequency vector is normalized angular frequency; either [0,pi) % or [0,2*pi). If user specifies Fs, linear frequency in Hz is returned. [freq_vector,xlab,xtickFlag,xlim] = calcfreqvector(length(Spec),Fs,... params.fsFlag,range); % Find confidence interval if needed if (nargout == 3)|((nargout == 0)&~isempty(p)), if isempty(p), p = .95; % default end % Confidence interval from Kay, p. 76, eqn 4.16: % (first column is lower edge of conf int., 2nd col is upper edge) confid = Spec*chi2conf(p,k); if noverlap > 0 warning('Confidence intervals inaccurate for NOVERLAP > 0.') end end % Set up output parameters if nargout >=1, varargout{1} = Spec; if (nargout == 2), varargout{2} = freq_vector; elseif (nargout == 3), varargout{2} = confid; varargout{3} = freq_vector; end else % (nargout == 0), if ~isempty(p), P = [Spec confid]; else P = Spec; end pxxplot('Welch',P,freq_vector,range,xlab,xtickFlag,xlim,params.magUnits); end %%%%%%%%%%%%%%%%%%%%%%%%%%%% % Local Functions % %%%%%%%%%%%%%%%%%%%%%%%%%%%% %---------------------------------------------------------------------- function window = calcWindow(w,nfft) % CALCWINDOW Caculate the window based on the input variable 'window'. if length(w) == 1, % Scalar input window = hanning(w); elseif isempty(w), % []; use default window = hanning(nfft); else window = w; % User specified window vector end %---------------------------------------------------------------------- function [params, msg] = pwelchparse(P, x) %PWELCHPARSE Parses and validates the inputs to PWELCH. % % Inputs: % P - cell array which has between 0 and 8 elements which are the % arguments to pwelch, after the x argument % x - input data % Outputs: % msg - error message, [] if no error % % params - structure containing the complete set of input arguments % accepted by the pwelch function % Default Values nfft = min(length(x),256); Fs = 1; window = hanning(nfft); noverlap = 0; p = []; magUnits = 'db'; fsFlag = 1; % Fs specified by the user if isreal(x), range = 'half'; else range = 'whole'; end switch length(P) case 0, % psd(x) fsFlag = 0; % Fs not specified by user case 1, % psd(x,nfft) or psd(x,range) fsFlag = 0; % Fs not specified by user if isstr(P{1}), range = P{1}; elseif ~isempty(P{1}), nfft = P{1}; end window = hanning(nfft); case 2, % pwelch(x,nfft,Fs) or pwelch(x,nfft,range) if ~isempty(P{1}), nfft=P{1}; end if isstr(P{2}), % Range passed fsFlag = 0; % Fs not specified by user range = P{2}; elseif ~isempty(P{2}), % Fs passed Fs = P{2}; end window = hanning(nfft); case 3, % pwelch(x,nfft,Fs,window) or pwelch(x,nfft,Fs,range) if ~isempty(P{1}), nfft=P{1}; end if ~isempty(P{2}), Fs = P{2}; end if isstr(P{3}), range = P{3}; window = hanning(nfft); else window = calcWindow(P{3},nfft); % Handles the [] case end case 4, % pwelch(x,nfft,Fs,window,noverlap) or pwelch(x,nfft,Fs,window,range) if ~isempty(P{1}), nfft=P{1}; end if ~isempty(P{2}), Fs = P{2}; end window = calcWindow(P{3},nfft); % Handles the [] case if isstr(P{4}), range = P{4}; elseif ~isempty(P{4}), noverlap = P{4}; end case {5,6,7,8}, % 5 pwelch(x,nfft,Fs,window,noverlap,p) or pwelch(x,nfft,Fs,window,noverlap,range) % 6 pwelch(x,nfft,Fs,window,noverlap,p,range) % 7 pwelch(x,nfft,Fs,window,noverlap,p,range,magUnits) if ~isempty(P{1}), nfft=P{1}; end if ~isempty(P{2}), Fs = P{2}; end window = calcWindow(P{3},nfft); % Handles the [] case if ~isempty(P{4}), noverlap = P{4}; end if isstr(P{5}) range = P{5}; elseif isempty(P{5}), p = .95; else p = P{5}; end if length(P) > 5, range = lower(P{6}); if length(P) > 6, magUnits = lower(P{7}); end end end % end swicth-case statement params.nfft = nfft; params.Fs = Fs; params.window = window; params.noverlap = noverlap; params.p = p; params.range = range; params.magUnits = magUnits; params.fsFlag = fsFlag; % An error message is returned if input validation fails. msg = pwelchErrorChk(x,params); %---------------------------------------------------------------------- function msg = pwelchErrorChk(x,params), % PWELCHERRORCHK Validate input to the pwelch function and return error % message if input is invalid. % Inputs: % x - data passed to pwelch % params - structure containing the following fields % nfft - fft length % Fs - sampling frequency (not used here) % window - window vector % noverlap - overlap of sections, in samples % p - confidence interval, [] if none desired % range - specifies the interval to be [0,Fs/2) (default for real) % or [0,Fs) (default for complex) % magUnits - specifies the magnitude units, squared or db (default) % fsFlag - flag indicating when Fs is specified by the user (not used here) % Outputs: % msg - error message, [] if no error % Extract some individual variables from structure for ease of caculations. nfft = params.nfft; p = params.p; msg = []; % Start error checking if (nfft < length(params.window)), msg = 'Requires window''s length to be no greater than the FFT length.'; end if (params.noverlap >= length(params.window)), msg = 'Requires NOVERLAP to be strictly less than the window length.'; end if (nfft ~= abs(round(nfft)))|(params.noverlap ~= abs(round(params.noverlap))), msg = 'Requires positive integer values for NFFT and NOVERLAP.'; end if ~isempty(p), if (prod(size(p))>1)|(p(1,1)>1)|(p(1,1)<0), msg = 'Requires confidence parameter to be a scalar between 0 and 1.'; end end if min(size(x))~=1 | ~isnumeric(x) | length(size(x))>2 msg = 'Requires vector (either row or column) input.'; end % Determine if user specified 'whole' or 'half' for the intervals [0,Fs) or [0,Fs/2) wholeopts={'half','whole'}; if ~isstr(params.range), msg = 'The parameter RANGE, must be a string.'; return else indx = strmatch(params.range,wholeopts); if isempty(indx), msg = 'The parameter RANGE, must be either ''WHOLE'' or ''HALF''.'; end end % Determine if user specified 'squared' or 'db' for the magnitude units magopts={'squared','db'}; if ~isstr(params.magUnits), msg = 'The parameter MAGUNITS, must be a string.'; return else indx = strmatch(params.magUnits,magopts); if isempty(indx), msg = 'The parameter MAGUNITS, must be either ''SQUARED'' or ''DB''.'; end end % [EOF] pwelch.m