annotate Code/Descriptors/Matlab/MPEG7/FromWeb/h_specgram2.m @ 4:92ca03a8fa99 tip

Update to ICASSP 2013 benchmark
author Dawn Black
date Wed, 13 Feb 2013 11:02:39 +0000
parents
children
rev   line source
Dawn@4 1 function [yo,fo,to] = h_specgram2(varargin)
Dawn@4 2 %SPECGRAM Calculate spectrogram from signal.
Dawn@4 3 % B = SPECGRAM(A,NFFT,Fs,WINDOW,SHIFT) calculates the spectrogram for
Dawn@4 4 % the signal in vector A. SPECGRAM splits the signal into overlapping
Dawn@4 5 % segments, windows each with the WINDOW vector and forms the columns of
Dawn@4 6 % B with their zero-padded, length NFFT discrete Fourier transforms. Thus
Dawn@4 7 % each column of B contains an estimate of the short-term, time-localized
Dawn@4 8 % frequency content of the signal A. Time increases linearly across the
Dawn@4 9 % columns of B, from left to right. Frequency increases linearly down
Dawn@4 10 % the rows, starting at 0. If A is a length NX complex signal, B is a
Dawn@4 11 % complex matrix with NFFT rows and
Dawn@4 12 % k = fix((NX-NOVERLAP)/(length(WINDOW)-NOVERLAP))
Dawn@4 13 % columns, where NOVERLAP = length(WINDOW)-mean(SHIFT)
Dawn@4 14 % If A is real, B still has k columns but the higher frequency
Dawn@4 15 % components are truncated (because they are redundant); in that case,
Dawn@4 16 % SPECGRAM returns B with NFFT/2+1 rows for NFFT even and (NFFT+1)/2 rows
Dawn@4 17 % for NFFT odd. If you specify a scalar for WINDOW, SPECGRAM uses a
Dawn@4 18 % Hanning window of that length. WINDOW must have length smaller than
Dawn@4 19 % or equal to NFFT and greater than NOVERLAP. NOVERLAP is the number of
Dawn@4 20 % samples the sections of A overlap. Fs is the sampling frequency
Dawn@4 21 % which does not effect the spectrogram but is used for scaling plots.
Dawn@4 22 %
Dawn@4 23 % [B,F,T] = SPECGRAM(A,NFFT,Fs,WINDOW,NOVERLAP) returns a column of
Dawn@4 24 % frequencies F and one of times T at which the spectrogram is computed.
Dawn@4 25 % F has length equal to the number of rows of B, T has length k. If you
Dawn@4 26 % leave Fs unspecified, SPECGRAM assumes a default of 2 Hz.
Dawn@4 27 %
Dawn@4 28 % B = SPECGRAM(A) produces the spectrogram of the signal A using default
Dawn@4 29 % settings; the defaults are NFFT = minimum of 256 and the length of A, a
Dawn@4 30 % Hanning window of length NFFT, and NOVERLAP = length(WINDOW)/2. You
Dawn@4 31 % can tell SPECGRAM to use the default for any parameter by leaving it
Dawn@4 32 % off or using [] for that parameter, e.g. SPECGRAM(A,[],1000)
Dawn@4 33 %
Dawn@4 34 % See also PWELCH, CSD, COHERE and TFE.
Dawn@4 35
Dawn@4 36 % Author(s): L. Shure, 1-1-91
Dawn@4 37 % T. Krauss, 4-2-93, updated
Dawn@4 38 % Copyright 1988-2000 The MathWorks, Inc.
Dawn@4 39 % $Revision: 1.6 $ $Date: 2000/06/09 22:07:35 $
Dawn@4 40
Dawn@4 41 error(nargchk(1,5,nargin))
Dawn@4 42 [msg,x,nfft,Fs,window,shift]=specgramchk(varargin);
Dawn@4 43 error(msg)
Dawn@4 44
Dawn@4 45 nx = length(x);
Dawn@4 46 nwind = length(window);
Dawn@4 47 if nx < nwind % zero-pad x if it has length less than the window length
Dawn@4 48 x(nwind)=0; nx=nwind;
Dawn@4 49 end
Dawn@4 50 x = x(:); % make a column vector for ease later
Dawn@4 51 window = window(:); % be consistent with data set
Dawn@4 52 noverlap = nwind - mean(shift);
Dawn@4 53 ncol = fix((nx-noverlap)/(nwind-noverlap));
Dawn@4 54
Dawn@4 55 totalshift = sum(shift);
Dawn@4 56 numshift = length(shift);
Dawn@4 57 progshift = (cumsum(shift)-shift(1))';
Dawn@4 58 overshift = 1:totalshift:nx;
Dawn@4 59 shifts = progshift(:,ones(1,length(overshift)))+overshift(ones(length(progshift),1),:);
Dawn@4 60 colindex = reshape(shifts,1,prod(size(shifts)));
Dawn@4 61 colindex = colindex(1:ncol);
Dawn@4 62 %colindex = 1 + (0:(ncol-1))*(nwind-noverlap);
Dawn@4 63 rowindex = (1:nwind)';
Dawn@4 64 if length(x)<(nwind+colindex(ncol)-1)
Dawn@4 65 x(nwind+colindex(ncol)-1) = 0; % zero-pad x
Dawn@4 66 end
Dawn@4 67
Dawn@4 68 y = zeros(nwind,ncol);
Dawn@4 69
Dawn@4 70 % put x into columns of y with the proper offset
Dawn@4 71 % should be able to do this with fancy indexing!
Dawn@4 72 y(:) = x(rowindex(:,ones(1,ncol))+colindex(ones(nwind,1),:)-1);
Dawn@4 73
Dawn@4 74 % Apply the window to the array of offset signal segments.
Dawn@4 75 y = window(:,ones(1,ncol)).*y;
Dawn@4 76
Dawn@4 77 % now fft y which does the columns
Dawn@4 78 y = fft(y,nfft);
Dawn@4 79 if ~any(any(imag(x))) % x purely real
Dawn@4 80 if rem(nfft,2), % nfft odd
Dawn@4 81 select = [1:(nfft+1)/2];
Dawn@4 82 else
Dawn@4 83 select = [1:nfft/2+1];
Dawn@4 84 end
Dawn@4 85 y = y(select,:);
Dawn@4 86 else
Dawn@4 87 select = 1:nfft;
Dawn@4 88 end
Dawn@4 89 f = (select - 1)'*Fs/nfft;
Dawn@4 90
Dawn@4 91 t = (colindex-1)'/Fs;
Dawn@4 92
Dawn@4 93 % take abs, and use image to display results
Dawn@4 94 if nargout == 0
Dawn@4 95 % newplot;
Dawn@4 96 % if length(t)==1
Dawn@4 97 % imagesc([0 1/f(2)],f,20*log10(abs(y)+eps));axis xy; colormap(jet)
Dawn@4 98 % else
Dawn@4 99 % imagesc(t,f,20*log10(abs(y)+eps));axis xy; colormap(jet)
Dawn@4 100 % end
Dawn@4 101 % xlabel('Time')
Dawn@4 102 % ylabel('Frequency')
Dawn@4 103 elseif nargout == 1,
Dawn@4 104 yo = y;
Dawn@4 105 elseif nargout == 2,
Dawn@4 106 yo = y;
Dawn@4 107 fo = f;
Dawn@4 108 elseif nargout == 3,
Dawn@4 109 yo = y;
Dawn@4 110 fo = f;
Dawn@4 111 to = t;
Dawn@4 112 end
Dawn@4 113
Dawn@4 114 function [msg,x,nfft,Fs,window,shift] = specgramchk(P)
Dawn@4 115 %SPECGRAMCHK Helper function for SPECGRAM.
Dawn@4 116 % SPECGRAMCHK(P) takes the cell array P and uses each cell as
Dawn@4 117 % an input argument. Assumes P has between 1 and 5 elements.
Dawn@4 118
Dawn@4 119 msg = [];
Dawn@4 120
Dawn@4 121 x = P{1};
Dawn@4 122 if (length(P) > 1) & ~isempty(P{2})
Dawn@4 123 nfft = P{2};
Dawn@4 124 else
Dawn@4 125 nfft = min(length(x),256);
Dawn@4 126 end
Dawn@4 127 if (length(P) > 2) & ~isempty(P{3})
Dawn@4 128 Fs = P{3};
Dawn@4 129 else
Dawn@4 130 Fs = 2;
Dawn@4 131 end
Dawn@4 132 if length(P) > 3 & ~isempty(P{4})
Dawn@4 133 window = P{4};
Dawn@4 134 else
Dawn@4 135 if length(nfft) == 1
Dawn@4 136 window = hanning(nfft);
Dawn@4 137 else
Dawn@4 138 msg = 'You must specify a window function.';
Dawn@4 139 end
Dawn@4 140 end
Dawn@4 141 if length(window) == 1, window = hanning(window); end
Dawn@4 142 if (length(P) > 4) & ~isempty(P{5})
Dawn@4 143 shift = P{5};
Dawn@4 144 else
Dawn@4 145 shift = ceil(length(window)/2);
Dawn@4 146 end
Dawn@4 147
Dawn@4 148 % NOW do error checking
Dawn@4 149 if (length(nfft)==1) & (nfft<length(window)),
Dawn@4 150 msg = 'Requires window''s length to be no greater than the FFT length.';
Dawn@4 151 end
Dawn@4 152 if (min(shift) <= 0),
Dawn@4 153 msg = 'Requires SHIFT to be strictly positive.';
Dawn@4 154 end
Dawn@4 155 if (length(nfft)==1) & (nfft ~= abs(round(nfft)))
Dawn@4 156 msg = 'Requires positive integer values for NFFT.';
Dawn@4 157 end
Dawn@4 158 if sum(shift ~= abs(round(shift))),
Dawn@4 159 msg = 'Requires positive integer value for NOVERLAP.';
Dawn@4 160 end
Dawn@4 161 if min(size(x))~=1,
Dawn@4 162 msg = 'Requires vector (either row or column) input.';
Dawn@4 163 end