diff m-toolbox/classes/@ao/welchparse.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/@ao/welchparse.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,256 @@
+% WELCHPARSE   Parser for the PWELCH & SPECTROGRAM functions
+%
+% Outputs:
+% X        - First input signal (used when esttype = MS & PSD)
+% M        - An integer containing the length of the data to be segmented
+% isreal_x - Boolean for input complexity
+% Y        - Second input signal (used when esttype = CPSD, TFE, MSCOHERE)
+% Ly       - Length of second input signal (used when esttype = CPSD, TFE, MSCOHERE)
+% WIN      - A scalar or vector containing the length of the window or the
+%            window respectively (Note that the length of the window determines
+%            the length of the segments)
+% WINNAME  - String with the window name.
+% WINPARAM - Window parameter.
+% NOVERLAP - An integer containing the number of samples to overlap (may
+%            be empty)
+% K        - Number of segments
+% OPTIONS  - A structure with the following fields:
+% OPTIONS.nfft  - number of freq. points at which the psd is estimated
+% OPTIONS.Fs    - sampling freq. if any
+% OPTIONS.range - 'onesided' or 'twosided' psd
+%
+% Direct copy from MATLAB
+%
+% M Hewitson 08-05-08
+%
+% $Id: welchparse.m,v 1.3 2010/07/23 14:53:40 mauro Exp $
+%
+
+%   Author(s): P. Costa
+%   Copyright 1988-2006 The MathWorks, Inc.
+%   $Revision: 1.3 $  $Date: 2010/07/23 14:53:40 $
+
+function [x,M,isreal_x,y,Ly,win,winName,winParam,noverlap,k,L,options] = ...
+    welchparse(x,esttype,varargin)
+
+  % Parse input arguments.
+  [x,M,isreal_x,y,Ly,win,winName,winParam,noverlap,opts,errid,errmsg] = ...
+    parse_inputs(x,esttype,varargin{:});
+  if ~isempty(errmsg), error(errid,errmsg); end
+
+  % Obtain the necessary information to segment x and y.
+  [L,noverlap,win,errid,errmsg] = segment_info(M,win,noverlap);
+  if ~isempty(errmsg), error(errid,errmsg); end
+
+  % Parse optional args nfft, fs, and spectrumType.
+  [options,msg] = welch_options(isreal_x,L,opts{:});
+  if ~isempty(msg), error(generatemsgid('InvalidParam'),msg); end
+
+  % Compute the number of segments
+  k = (M-noverlap)./(L-noverlap);
+
+  % Uncomment the following line to produce a warning each time the data
+  % segmentation does not produce an integer number of segements.
+  %if fix(k) ~= k,
+  %   warning(generatemsgid('MustBeInteger'),'The number of segments is not an integer, truncating data.');
+  %end
+
+  k = fix(k);
+end
+
+%-----------------------------------------------------------------------------------------------
+function [x,Lx,isreal_x,y,Ly,win,winName,winParam,noverlap,opts,errid,errmsg] = ...
+    parse_inputs(x,esttype,varargin)
+  % Parse the inputs to the welch function.
+
+  % Assign defaults in case of early return.
+  isreal_x = 1;
+  y        = [];
+  Ly       = 0;
+  is2sig   = false;
+  win      = [];
+  winName  = 'User Defined';
+  winParam = '';
+  noverlap = [];
+  opts     = {};
+  errid    = '';
+  errmsg   = '';
+
+  % Determine if one or two signal vectors was specified.
+  Lx = length(x);
+  if iscell(x),
+    if Lx > 1, % Cell array.
+      y = x{2};
+      is2sig = true;
+    end
+    x = x{1};
+    Lx = length(x);
+  else
+    if ~any(strcmpi(esttype,{'psd','ms'})),
+      errid = generatemsgid('invalidSignalVectors');
+      errmsg = 'You must specify a cell array with two signal vectors to estimate either the cross power spectral density or the transfer function.';
+      return;
+    end
+  end
+
+  x = x(:);
+  isreal_x = isreal(x);
+
+  % Parse 2nd input signal vector.
+  if is2sig,
+    y = y(:);
+    isreal_x = isreal(y) && isreal_x;
+    Ly = length(y);
+    if Ly ~= Lx,
+      errid = generatemsgid('invalidSignalVectors');
+      errmsg = 'The length of the two input vectors must be equal to calculate the cross spectral density.';
+      return;
+    end
+  end
+
+  % Parse window and overlap, and cache remaining inputs.
+  lenargin = length(varargin);
+  if lenargin >= 1,
+    win = varargin{1};
+    if lenargin >= 2,
+      noverlap = varargin{2};
+
+      % Cache optional args nfft, fs, and spectrumType.
+      if lenargin >= 3,  opts = varargin(3:end); end
+    end
+  end
+
+  if isempty(win) | isscalar(win),
+    winName = 'hamming';
+    winParam = 'symmetric';
+  end
+
+end
+
+%-----------------------------------------------------------------------------------------------
+%SEGMENT_INFO   Determine the information necessary to segment the input data.
+%
+%   Inputs:
+%      M        - An integer containing the length of the data to be segmented
+%      WIN      - A scalar or vector containing the length of the window or the window respectively
+%                 (Note that the length of the window determines the length of the segments)
+%      NOVERLAP - An integer containing the number of samples to overlap (may be empty)
+%
+%   Outputs:
+%      L        - An integer containing the length of the segments
+%      NOVERLAP - An integer containing the number of samples to overlap
+%      WIN      - A vector containing the window to be applied to each section
+%      ERRID    - A string containing possible error identifier
+%      ERRMSG   - A string containing possible error messages
+%
+%
+%   The key to this function is the following equation:
+%
+%      K = (M-NOVERLAP)/(L-NOVERLAP)
+%
+%   where
+%
+%      K        - Number of segments
+%      M        - Length of the input data X
+%      NOVERLAP - Desired overlap
+%      L        - Length of the segments
+%
+%   The segmentation of X is based on the fact that we always know M and two of the set
+%   {K,NOVERLAP,L}, hence determining the unknown quantity is trivial from the above
+%   formula.
+
+function [L,noverlap,win,errid,errmsg] = segment_info(M,win,noverlap)
+
+  % Initialize outputs
+  L = [];
+  errid = '';
+  errmsg = '';
+
+  % Check that noverlap is a scalar
+  if any(size(noverlap) > 1),
+    errid = generatemsgid('invalidNoverlap');
+    errmsg = 'You must specify an integer number of samples to overlap.';
+    return;
+  end
+
+  if isempty(win),
+    % Use 8 sections, determine their length
+    if isempty(noverlap),
+      % Use 50% overlap
+      L = fix(M./4.5);
+      noverlap = fix(0.5.*L);
+    else
+      L = fix((M+7.*noverlap)./8);
+    end
+    % Use a default window
+    win = hamming(L);
+  else
+    % Determine the window and its length (equal to the length of the segments)
+    if ~any(size(win) <= 1) | ischar(win),
+      errid = generatemsgid('invalidWindow');
+      errmsg = 'The WINDOW argument must be a vector or a scalar.';
+      return
+    elseif length(win) > 1,
+      % WIN is a vector
+      L = length(win);
+    elseif length(win) == 1,
+      L = win;
+      win = hamming(win);
+    end
+    if isempty(noverlap),
+      % Use 50% overlap
+      noverlap = fix(0.5.*L);
+    end
+  end
+
+  % Do some argument validation
+  if L > M,
+    errid = generatemsgid('invalidSegmentLength');
+    errmsg = 'The length of the segments cannot be greater than the length of the input signal.';
+    return;
+  end
+
+  if noverlap >= L,
+    errid = generatemsgid('invalidNoverlap');
+    errmsg = 'The number of samples to overlap must be less than the length of the segments.';
+    return;
+  end
+end
+
+%------------------------------------------------------------------------------
+%WELCH_OPTIONS   Parse the optional inputs to the PWELCH function.
+%   WELCH_OPTIONS returns a structure, OPTIONS, with following fields:
+%
+%   options.nfft         - number of freq. points at which the psd is estimated
+%   options.Fs           - sampling freq. if any
+%   options.range        - 'onesided' or 'twosided' psd
+
+function [options,msg] = welch_options(isreal_x,N,varargin)
+
+  % Generate defaults
+  options.nfft = max(256,2^nextpow2(N));
+  options.Fs = []; % Work in rad/sample
+
+  % Determine if frequency vector specified
+  freqVecSpec = false;
+  if (length(varargin) > 0 && length(varargin{1}) > 1)
+    freqVecSpec = true;
+  end
+
+  if isreal_x && ~freqVecSpec,
+    options.range = 'onesided';
+  else
+    options.range = 'twosided';
+  end
+  msg = '';
+
+  if any(strcmp(varargin, 'whole'))
+    warning(generatemsgid('invalidRange'), '''whole'' is not a valid range, use ''twosided'' instead.');
+  elseif any(strcmp(varargin, 'half'))
+    warning(generatemsgid('invalidRange'), '''half'' is not a valid range, use ''onesided'' instead.');
+  end
+
+  [options,msg] = psdoptions(isreal_x,options,varargin{:});
+
+end
+