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
|