【无标题】stft-fsst

function [sst,f,t] = fsst(x,varargin)
%FSST Fourier synchrosqueezed transform
%   SST = FSST(X) returns the Fourier synchrosqueezed transform of X. Each
%   column of SST contains the synchrosqueezed spectrum of a windowed
%   segment of X. The number of columns of SST is equal to the number of
%   samples of the input X, which is padded with zeros on each side. Each
%   spectrum is one-sided for real X and two-sided and centered for complex
%   X. By default, a Kaiser window of length 256 and a beta of 10 is used.
%   If X has fewer than 256 samples, then the Kaiser window has the same
%   length as X.
% 
%   [SST,W,S] = FSST(X) returns a vector of normalized frequencies, W,
%   corresponding to the rows of SST, and a vector of sample numbers, S,
%   corresponding to the columns of SST. Each element of S is the sample
%   number of the midpoint of a windowed segment of X.
%
%   [SST,F,T] = FSST(X,Fs) specifies the sampling frequency, Fs, in hertz,
%   as a positive scalar. The output contains sample times, T, expressed in
%   seconds and frequencies, F, expressed in hertz.
%
%   [SST,F,T] = FSST(X,Ts) specifies the sampling interval, Ts, as a 
%   <a href="matlab:help duration">duration</a>. Ts is the time between samples of X. T has the same units 
%   as the duration. The units of F are in cycles/unit time of the
%   duration.
%
%   [...] = FSST(X,...,WINDOW) when WINDOW is a vector, divides X into
%   segments of the same length as WINDOW and then multiplies each segment
%   by WINDOW.  If WINDOW is an integer, a Kaiser window with length WINDOW
%   and a beta of 10 is used. If WINDOW is not specified, the default
%   Kaiser window is used.
%
%   FSST(...) with no output arguments plots the synchrosqueezed transform
%   of the input vector x on the current figure.
%
%   FSST(...,FREQLOCATION) controls where MATLAB displays the frequency
%   axis on the plot. This string can be either 'xaxis' or 'yaxis'.
%   Setting FREQLOCATION to 'yaxis' displays frequency on the y-axis and
%   time on the x-axis.  The default is 'xaxis', which displays frequency
%   on the x-axis. FREQLOCATION is ignored when output arguments are
%   specified.
%
%   % Example 1: 
%   %   Compute and plot the Fourier synchrosqueezed transform (SST) of a
%   % signal that consists of two chirps. 
%   fs = 3000;
%   t = 0:1/fs:1-1/fs;   
%   x1 = 2*chirp(t,500,t(end),1000);
%   x2 = chirp(t,400,t(end),800); 
%   fsst(x1+x2,fs,'yaxis')
%   title('Magnitude of Fourier Synchrosqueezed Transform of Two Chirps')
%
%   % Compute and plot the short-time Fourier transform.
%   [stft,f,t] = spectrogram(x1+x2,kaiser(256,10),255,256,fs);
%   figure
%   h = imagesc(t,f,abs(stft));
%   xlabel('Time (s)') 
%   ylabel('Frequency (Hz)')
%   title('Magnitude of Short-time Fourier Transform of Two Chirps')
%   h.Parent.YDir = 'normal';
%
%   % Example 2
%   %   Compute the Fourier synchrosqueezed transform of a speech signal.
%   load mtlb
%   fsst(mtlb,Fs,hann(256),'yaxis')
%
%   See also ifsst, tfridge, spectrogram, duration.

% Copyright 2015-2016 MathWorks, Inc.

narginchk(1,4);
nargoutchk(0,3);

% Parse inputs. Fs is populated as used throughout the bulk of the code
% even if Ts is specified. fNorm specifies normalized frequencies.
[Fs,Ts,win,fNorm,freqloc] = parseInputs(x,varargin{:});

validateInputs(x,Fs,Ts,win);

% Parameters based on window size - noverlap is fixed so the transform is
% invertible.
nwin = length(win);
nfft = nwin;
noverlap = nwin-1;

% Convert to column vectors
x = signal.internal.toColIfVect(x);
win = win(:);

% Compute the output time vector (one time per sample point of the input)
if fNorm
  tout = (1:length(x));
else
  tout = (0:length(x)-1)/Fs;
end

% cast to enforce precision rules (we already checked that the inputs are
% numeric.
% cast to enforce precision rules
if (isa(x,'single') || isa(win,'single'))
  x = single(x);
  win = single(win);
  Fs = single(Fs);
  tout = single(tout);
else
  Fs = double(Fs);
end
  
% Pad the signal vector x
if mod(nwin,2)
  xp = [zeros((nwin-1)/2,1) ; x ; zeros((nwin-1)/2,1)];
else
  xp = [zeros((nwin)/2,1) ; x ; zeros((nwin-2)/2,1)];
end

nxp = length(xp);

% Place xp into columns for the STFT
xin = signal.internal.reassignSpec.getSTFTColumns(xp,nxp,nwin,noverlap,Fs);

% Compute the STFT
[sstout,fout] = computeDFT(bsxfun(@times,win,xin),nfft,Fs); 
stftc = computeDFT(bsxfun(@times,signal.internal.reassignSpec.dtwin(win,Fs),xin),nfft,Fs);

clear xin;

% Compute the reassignment vector
fcorr = -imag(stftc./ sstout);
fcorr(~isfinite(fcorr)) = 0;
fcorr = bsxfun(@plus,fout,fcorr);
tcorr = bsxfun(@plus,tout,zeros(size(fcorr)));

clear stftc;

% Mulitply STFT by a linear phase shift to produce the modified STFT
m = floor(nwin/2);
inds = 0:nfft-1;
ez = exp(-1i*2*pi*m*inds/nfft)';
sstout = bsxfun(@times,sstout,ez); 

% Reassign the modified STFT
options.range = 'twosided';
options.nfft = nfft;
sstout = signal.internal.reassignSpec.reassignSpectrum(sstout, fout, tout, fcorr, tcorr, options);

% Reduce to one-sided spectra if the input is real, otherwise return a
% two-sided (centered) spectra.
if isreal(x)
  fout = psdfreqvec('npts',nfft,'Fs',Fs,'Range','half');
  sstout = sstout(1:length(fout),:);
else
  % Centered spectra
  sstout = signal.internal.reassignSpec.centerest(sstout);
  fout = signal.internal.reassignSpec.centerfreq(fout);
end

% Scale fout and tout if the input is a duration object
if ~isempty(Ts)
  [~,~,timeScale] = getDurationandUnits(Ts);
  tout = tout*timeScale;
  fout = fout/timeScale;
end

if nargout == 0
  plotsst(tout,fout,sstout,Ts,fNorm,freqloc);
else
  sst = sstout;
  f = fout;
  t = tout(:)';
end
%--------------------------------------------------------------------------
function [Fs,Ts,win,fNorm,freqloc] = parseInputs(x,varargin)
% Set defaults
Fs = [];
Ts = [];
win = kaiser(min(256,length(x)),10); %#ok<*NASGU>
fNorm = false;
freqloc = '';

% Parse optional inputs
if nargin > 1 
  if isduration(varargin{1})
    if isempty(varargin{1})
      % Throw error is empty duration object is supplied
      error(message('signal:fsst:EmptyDuration'));
    else
      Ts = varargin{1};
      Fs = 1/seconds(Ts);
    end
  elseif ischar(varargin{1})
    freqloc = validatestring(varargin{1},{'xaxis','yaxis'});  
  else
    if ~isempty(varargin{1})
      Fs = varargin{1};
    end
  end
end

if isempty(Fs) && isempty(Ts)
  fNorm = true;
  Fs = 2*pi;
end

if nargin > 2 
  if ischar(varargin{2})
    freqloc = validatestring(varargin{2},{'xaxis','yaxis'});  
  elseif ~isempty(varargin{2})
    win = varargin{2};
    if isscalar(win)
      validateattributes(win,{'numeric'},{'positive'},'fsst','WINDOW');
      win = kaiser(double(win),10);
    end
  end
end

if nargin > 3
  freqloc = validatestring(varargin{3},{'xaxis','yaxis'}); 
end
%--------------------------------------------------------------------------
function validateInputs(x,Fs,Ts,win)

validateattributes(x,{'single','double'},...
  {'nonsparse','finite','nonnan','vector'},'fsst','X');
validateattributes(Fs,{'numeric'},...
    {'real','positive','finite','nonnan','scalar'},'fsst','Fs');
validateattributes(win,{'single','double'},...
  {'real','finite','nonnegative','nonnan','vector'},'fsst','WINDOW');  
  
if ~isempty(Ts)
  dt = getDurationandUnits(Ts);
  validateattributes(dt,{'numeric'},...
    {'real','positive','finite','nonnan','scalar'},'fsst','Ts');
end

% Check X has at least 2 samples
if length(x) < 2
  error(message('signal:fsst:MustBeMinLengthX'));
end

% Check WINDOW has at least 2 samples
if length(win) < 2
  error(message('signal:fsst:MustBeMinLengthWin'));
end

% Check window length is not more than the length of the input signal.
if length(win) > length(x)
  error(message('signal:fsst:WinLength'));
end
%--------------------------------------------------------------------------
function [dt,units,timeScale] = getDurationandUnits(Ts)
% This function returns the sampling interval and a format string
% The Units string is only for plotting.
tsformat = Ts.Format;
% Use first character of format string to determine correct
% duration object method.
tsformat = tsformat(1);
% Using the same time units as engunits. Units in engunits are
% not localized.
% time_units = {'secs','mins','hrs','days','years'};
switch tsformat
    case 's'
        dt = seconds(Ts);
        units = 'sec';
        timeScale = 1;
    case 'm'
        dt = minutes(Ts);
        units = 'min';
        timeScale = 1/seconds(minutes(1));
    case 'h'
        dt = hours(Ts);
        units = 'hr';
        timeScale = 1/seconds(hours(1));
    case 'd'
        dt = days(Ts);
        units = 'day';
        timeScale = 1/seconds(days(1));
    case 'y'
        dt = years(Ts);
        units = 'year';
        timeScale = 1/seconds(years(1));
end
%--------------------------------------------------------------------------
function plotsst(t,f,sst,Ts,fNorm,freqloc)
  % Plot the FSST in the current figure
  if fNorm
    xlbl = getString(message('signal:fsst:SampNum'));
    ylbl = [getString(message('signal:sigtools:getfrequnitstrs:NormalizedFrequency')) '  (\times\pi rad/sample)'];
    f = f/pi;
  elseif isempty(Ts) 
    % No duration object specified
    % Scale range and add corresponding label (e.g. MHz)
    [f,~,uf] = engunits(f,'unicode');
    [t,~,ut] = engunits(t,'unicode','time');
    xlbl = [getString(message('signal:spectrogram:Time')) ' (' ut ')'];
    ylbl = getfreqlbl([uf 'Hz']);
  else
    [~,timeUnit] = getDurationandUnits(Ts);
    xlbl = [getString(message('signal:spectrogram:Time')) ' (',timeUnit,'s)'];
    ylbl = [getString(message('signal:sigtools:getfrequnitstrs:Frequency')) ' (cycles/',timeUnit,')'];
  end
  
  
  if strcmp(freqloc,'yaxis')
      h = imagesc(t,f,abs(sst));
      set(h.Parent, 'Ydir', 'normal')
      xlabel(xlbl); 
      ylabel(ylbl);
  else
      h = imagesc(f,t,abs(sst)');
      set(h.Parent, 'Ydir', 'normal')
      xlabel(ylbl); 
      ylabel(xlbl);
  end
  
  title(getString(message('signal:fsst:titleFSST')));
function xrec = ifsst(sst,varargin)
%IFSST Inverse Fourier synchrosqueezed transform
%   XREC = IFSST(SST) returns the inverse of the Fourier synchrosqueezed
%   transform matrix, SST. XREC is a 1-by-N vector, where N is the number
%   of columns in SST. XREC is reconstructed using the default window and
%   the entire time-frequency plane.
%
%   XREC = IFSST(SST,WINDOW) reconstructs the signal whose SST was computed
%   by FSST using WINDOW. WINDOW is a positive vector containing the window
%   function or a scalar specifying the length of a Kaiser window with a
%   beta parameter of 10. You can leave WINDOW unspecified or as an empty
%   array in IFSST and the default Kaiser window will be used. 
%
%   XREC = IFSST(SST,WINDOW,F,FREQRANGE) uses the frequency vector F and
%   the two-element vector FREQRANGE to invert the synchrosqueezed
%   transform. F is the vector of frequencies corresponding to the rows of
%   SST. The synchrosqueezed transform is inverted for the bins in SST with
%   frequencies in FREQRANGE. FREQRANGE is a two-element vector with
%   strictly increasing values and must lie in the range of F.
%
%   XREC = IFSST(SST,WINDOW,IRIDGE) inverts the synchrosqueezed transform
%   along the time-frequency ridges specified by the index vector or matrix
%   IRIDGE. IRIDGE is an output of TFRIDGE. If IRIDGE is a matrix, IFSST
%   first inverts the synchrosqueezed transform along the first column of
%   IRIDGE, then iteratively reconstructs along subsequent columns of
%   IRIDGE. XREC has the same size as IRIDGE.
%
%   XREC = IFSST(SST,WINDOW,IRIDGE,'NumFrequencyBins',NBINS) specifies the
%   number of frequency bins on each side of IRIDGE to use in the
%   reconstruction. If the index of the time-frequency ridge +/- NBINS
%   exceeds the range of frequency bins at any time step, IFSST truncates
%   the reconstruction at the first or last frequency bin. If unspecified,
%   NBINS defaults to 4. The name-value pair 'NumFrequencyBins', NBINS is
%   valid only if you provide the IRIDGE input.
%
%   % Example 1
%   %   Extract and reconstruct each of two signal components using the
%   %   Fourier synchrosqueezed transform.  
%   fs = 3000; 
%   t = 0:1/fs:1-1/fs; 
%   x1 = 2*chirp(t,500,t(end),1000); 
%   x2 = chirp(t,400,t(end),800); 
%   [sst,f] = fsst(x1+x2,fs);
%
%   %   Extract a ridge for each component.
%   [~,iridge] = tfridge(sst,f,'NumRidges',2);
%
%   %   Reconstruct a waveform for each ridge.
%   xrec = ifsst(sst,[],iridge);
%
%   %   Plot the extracted waveforms.
%   figure, subplot(2,1,1)
%   plot(t,xrec(:,1))
%   title('Waveform Extraction')
%   xlabel('Time (s)'), ylabel('Amplitude')
%   legend('Chirp 1')
%   grid
%   subplot(2,1,2)
%   plot(t,xrec(:,2),'Color',[0.85 0.325 0.098])
%   xlabel('Time (s)'), ylabel('Amplitude')
%   legend('Chirp 2')
%   grid
%
%   % Example 2
%   %   Compute the Fourier synchrosqueezed transform of a speech signal.
%   %   Invert the transform to reconstruct the signal, plot the
%   %   reconstructed signal, and compare the original and reconstructed 
%   %   signals using the L-infinity norm.
%   
%   %   Load the speech signal and compute the synchrosqueezed transform.
%   load mtlb
%   [sst,f] = fsst(mtlb,Fs);
%
%   %   Invert the synchrosqueezed transform and reconstruct the signal.
%   xrec = ifsst(sst);
%
%   %   Plot the orignal and reconstructed signals.
%   t = (0:length(mtlb)-1)/Fs;
%   plot(t,mtlb,t,xrec)
%   xlabel('Time (s)')
%   legend('Original','Reconstructed')
%   title('Original and Reconstructed Speech Signals')
%   
%   %   Compute the L-infinity norm of the difference between original and
%   %   reconstructed signals.
%   Linf = norm(abs(mtlb-xrec),Inf)
%
%   See also fsst, tfridge.

% Copyright 2015-2016 MathWorks, Inc.

narginchk(1,5);
nargoutchk(0,1);

[win,iridge,f,freqrange,nfft,nbins,fReal] = parseInputs(sst,varargin{:});

validateInputs(sst,win,iridge,f,freqrange,nbins);

% Cast to enforce precision rules
% The output xrec will be single only if the input sst is single. If the
% window used was single, sst would be single.
win = double(win);

% Convert to column vectors
win = win(:);
f = f(:);
freqrange = freqrange(:);

% Compute window scale factor, frequency interval, and real input flag
g0 = win(round(length(win)/2)); 
df = 1/nfft;

% Determine the last index to use in the second side of the spectrum.
% For an even length fft, the one-sided spectrum has (nfft/2)+1 elements,
% while for an odd length fft, the one-sided spectrum has (nfft+1)/2
% elements.
if mod(nfft,2)
  iend = size(sst,1);
else
  iend = size(sst,1)-1;
end
% Extract ridges if provided
if ~isempty(iridge)
  xrec = zeros(size(iridge));
  for j = 1:size(iridge,2)
    Mask = zeros(size(sst));
    for i = 1:size(iridge,1)
       Mask(max(iridge(i,j)-nbins,1):min(iridge(i,j)+nbins,size(sst,1)),i) = 1;
    end
    % Do the inverse 
    maskSST = sst.*Mask;
    if fReal
      xrec(:,j) = 1/g0*df*real(sum(maskSST)+ ...
        conj(sum(maskSST(2:iend,:))))';
    else
      xrec(:,j) = 1/g0*df*(sum(maskSST)).';  
    end
  end
elseif ~isempty(freqrange);
  [~,i1] = min(abs(f - freqrange(1)));  
  [~,i2] = min(abs(f - freqrange(2)));
   % Do the inverse 
    if fReal
      xrec = 1/g0*df*real(sum(sst(i1:i2,:)) + ...
        conj(sum(sst(max(i1,2):min(i2,iend),:))));
    else
      xrec = 1/g0*df*(sum(sst(i1:i2,:)));
    end
  xrec = xrec(:);
else
  % Do the inverse 
  if fReal
    xrec = 1/g0*df*real(sum(sst) + conj(sum(sst(2:iend,:))));
  else
    xrec = 1/g0*df*(sum(sst));
  end
  xrec = xrec(:);
end

%--------------------------------------------------------------------------
function [win,iridge,f,freqrange,nfft,nbins,fReal] = parseInputs(sst,varargin)

sstSize=size(sst);

if sstSize(2) < 256
   win = kaiser(sstSize(2),10);
else
   win = kaiser(256,10);
end

iridge = [];
f = [];
freqrange = [];
nbins = 4; %#ok<*NASGU>

if nargin > 1
  % The first optional argument is WINDOW
    win = getWin(varargin{1},win);
end

if nargin == 3
  % This is a ridge
    iridge = varargin{2};
end

if nargin == 4
  % This F and FREQRANGE
  if ~ischar(varargin{3})
    f = varargin{2};
    freqrange = varargin{3};
  else
    error(message('signal:ifsst:NVMustBeEven'));
  end
end

if nargin == 5
  iridge = varargin{2};
  % This is ridge and name-value pair
  validatestring(varargin{3},{'NumFrequencyBins'});
  nbins = varargin{4};
end

nfft = length(win);

if sstSize(1) == nfft
  fReal = false;
else
  fReal = true;
end

%--------------------------------------------------------------------------
function win = getWin(newwin,currentWin)
  if isempty(newwin)
    win = currentWin;
  elseif isscalar(newwin)
      validateattributes(newwin,{'single','double'},{'positive'},'ifsst','WINDOW');
      win = kaiser(newwin,10);
  else
    win = newwin;
  end
%--------------------------------------------------------------------------
function validateInputs(sst,win,iridge,f,freqrange,nbins)

validateattributes(sst,{'single','double'},...
  {'nonsparse','finite','nonnan','nonempty'},'ifsst','SST');
validateattributes(win,{'single','double'},...
  {'real','finite','nonnegative','nonnan','vector'},'ifsst','WINDOW');

if ~isempty(iridge)
  validateattributes(iridge,{'single','double'},...
    {'real','positive','integer','nonsparse','finite','nonnan'},'ifsst','IRIDGE');
end
if ~isempty(f) || ~isempty(freqrange)
  validateattributes(f,{'single','double'},...
    {'real','finite','nonnan','vector'},'ifsst','F');
  validateattributes(freqrange,{'single','double'},...
    {'real','finite','nonnan','vector'},'ifsst','FREQRANGE');
end
validateattributes(nbins,{'numeric'},...
  {'real','positive','integer','finite','nonnan','scalar','nonempty'},'ifsst','BINS');

% check that sst is a matrix. fsst has a minimum signal size of 2, which
% will produce a 2x2 array.
if isvector(sst)
  error(message('signal:ifsst:SSTisVector'));
end  

% Window length matches the size of sst
sizeSST = size(sst);
winLen = length(win);

% Expected window length for a real signal
if mod(winLen,2)
  winLenReal = 2*sizeSST(1)-1; 
else
  winLenReal = 2*(sizeSST(1)-1); 
end

if ~(winLen == sizeSST(1) || winLen == winLenReal)
  error(message('signal:ifsst:winLen'));
end

% Size of f matches SST
if ~isempty(f) && ~(length(f) == size(sst,1))
  error(message('signal:ifsst:fSize'));
  % The length of F must match the number of rows of SST. 
end

% Size of iridge matches SST
if ~isempty(iridge) && ~(size(iridge,1) == size(sst,2))
  error(message('signal:ifsst:iridgeSize'));
  % The number of rows of IRIDGE must match the number of rows of SST.
end

% Length of freqrange is 2, values are within the range of f and strictly
% increasing
if ~isempty(freqrange) && (~(length(freqrange) == 2) || ... 
  freqrange(2) <= freqrange(1) || freqrange(1) < f(1) || freqrange(2) > f(end)) 
  error(message('signal:ifsst:freqrange'));
end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值