Mercurial > hg > ltpda
comparison m-toolbox/classes/+utils/@math/music.m @ 0:f0afece42f48
Import.
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Wed, 23 Nov 2011 19:22:13 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0afece42f48 |
---|---|
1 function [music_data,msg] = music(x,p,varargin) | |
2 %MUSIC Implements the heart of the MUSIC algorithm of line spectra estimation. | |
3 % MUSIC is called by both PMUSIC and ROOTMUSIC. | |
4 % | |
5 % Inputs: | |
6 % | |
7 % x - vector or matrix. If vector it is a signal, if matrix it may be either a data | |
8 % matrix such that x'*x=R, or a correlation matrix R. | |
9 % p - scalar or two element vector. If scalar, it indicates the dimension of the | |
10 % signal subspace. If vector, p(2) is a threshold used to determine the | |
11 % aforementioned dimension. | |
12 % nfft - (optional) to be used only with PMUSIC. A scalar indicating the number of | |
13 % points used in the evaluation of the pseudospectrum. | |
14 % Fs - (optional) a scalar specifying the sampling frequency. If omitted, we work | |
15 % in rad/sample; if empty it defaults to 1 Hz. | |
16 % nw - (optional) a scalar or vector indicating either the order of the correlation | |
17 % matrix or (when a vector) a window whose length is the order of the matrix | |
18 % and whose values are used to window each column of the data matrix. | |
19 % noverlap - (optional) a integer indicating the number of samples to overlap from | |
20 % column to column. | |
21 % strings - Optional input strings are: 'corr', 'EV' and range ('half' or 'whole'). | |
22 % | |
23 % Outputs: | |
24 % | |
25 % msg - a possible error message. | |
26 % | |
27 % music_data - a structure with the following fields: | |
28 % | |
29 % noise_eigenvects - a matrix whose columns are the noise subspace eigenvectors. | |
30 % signal_eigenvects - a matrix whose columns are the signal subspace eigenvectors. | |
31 % eigenvals - the eigenvalues of the correlation matrix. | |
32 % p_eff - the effective dimension of the signal subspace. | |
33 % nfft - number of points used to evaluate the pseudospectrum (only used in PMUSIC). | |
34 % Fs - sampling freq. | |
35 % range - string indicating whether 'half' or the 'whole' pseudospectrum should be | |
36 % computed. (Only used in PMUSIC.) | |
37 % EVFlag - flag, 0 = MUSIC method; 1 = EigenVector method. | |
38 | |
39 % Author(s): R. Losada | |
40 % Copyright 1988-2006 The MathWorks, Inc. | |
41 % $Revision: 1.1 $ $Date: 2010/02/18 11:16:20 $ | |
42 | |
43 % References: | |
44 % [1] Petre Stoica and Randolph Moses, Introduction To Spectral | |
45 % Analysis, Prentice-Hall, 1997, pg. 15 | |
46 % [2] S. J. Orfanidis, Optimum Signal Processing. An Introduction. | |
47 % 2nd Ed., Macmillan, 1988. | |
48 | |
49 | |
50 xIsReal = isreal(x); | |
51 msg = ''; | |
52 music_data = []; | |
53 | |
54 if isempty(p), | |
55 msg = 'The signal subspace dimension cannot be empty.'; | |
56 return | |
57 end | |
58 | |
59 [opts,msg] = music_options(xIsReal,p,varargin{:}); | |
60 if ~isempty(msg), | |
61 return | |
62 end | |
63 | |
64 % Compute the eigenvalues and eigenvectors of the correlation matrix | |
65 [eigenvals,eigenvects] = computeeig(x,opts.CorrFlag,opts.CorrMatrOrd,opts.nw,opts.noverlap,opts.window,opts.EVFlag); | |
66 | |
67 % Determine the effective dimension of the signal subspace | |
68 p_eff = determine_signal_space(p,eigenvals); | |
69 | |
70 % Separate the signal and noise eigenvectors | |
71 signal_eigenvects = eigenvects(:,1:p_eff); | |
72 noise_eigenvects = eigenvects(:,p_eff+1:end); | |
73 | |
74 % Generate the output structure | |
75 music_data.noise_eigenvects = noise_eigenvects; | |
76 music_data.signal_eigenvects = signal_eigenvects; | |
77 music_data.eigenvals = eigenvals; | |
78 music_data.p_eff = p_eff; | |
79 music_data.nfft = opts.nfft; | |
80 music_data.Fs = opts.Fs; | |
81 music_data.EVFlag = opts.EVFlag; | |
82 music_data.range = opts.range; | |
83 | |
84 | |
85 %-------------------------------------------------------------------------------------- | |
86 function [options,msg] = music_options(xIsReal,p,varargin) | |
87 %MUSIC_OPTIONS Parse the optional inputs to the MUSIC function. | |
88 % MUSIC_OPTIONS returns a structure, OPTIONS, with the following fields: | |
89 % | |
90 % options.nfft - number of freq. points at which the psd is estimated | |
91 % options.Fs - sampling freq. if any | |
92 % options.range - 'onesided' or 'twosided' pseudospectrum (they correspond to | |
93 % 'half' and 'whole' respectively, but are returned as is by | |
94 % psdoptions.m | |
95 % options.nw - number of columns in the data matrix | |
96 % options.noverlap - number of samples to overlap | |
97 % options.window - a vector with window coefficients | |
98 % options.CorrFlag - a flag indicating whether the input is a correlation matrix | |
99 % options.EVFlag - flag, 0 = MUSIC method ; 1 = EigenVector method | |
100 % options.CorrMatrOrd - order of the correlation matrix to be used in computations | |
101 | |
102 | |
103 | |
104 % Assign Defaults | |
105 msg = ''; | |
106 options.nw = []; | |
107 options.noverlap = []; | |
108 options.window = []; | |
109 options.nfft = 256; | |
110 options.Fs = []; | |
111 options.CorrFlag = 0; | |
112 options.EVFlag = 0; | |
113 % Determine if frequency vector specified | |
114 freqVecSpec = false; | |
115 if (length(varargin) > 0 && isnumeric(varargin{1}) && length(varargin{1}) > 1) | |
116 freqVecSpec = true; | |
117 end | |
118 | |
119 if xIsReal && ~freqVecSpec, | |
120 options.range = 'onesided'; | |
121 else | |
122 options.range = 'twosided'; | |
123 end | |
124 | |
125 [options,msg] = psdoptions(xIsReal,options,varargin{:}); | |
126 | |
127 if length(options.nfft) > 1, | |
128 if strcmpi(options.range,'onesided') | |
129 warning(generatemsgid('InconsistentRangeOption'),... | |
130 'Ignoring the ''onesided'' option. When a frequency vector is specified, a ''twosided'' PSD is computed'); | |
131 end | |
132 options.range = 'twosided'; | |
133 end | |
134 | |
135 % psdoptions doesn't handle this field, assign it separetely | |
136 options.CorrMatrOrd = 2*p(1); | |
137 | |
138 %----------------------------------------------------------------------------------------- | |
139 function [eigenvals,eigenvects] = computeeig(x,CorrFlag,CorrMatrOrd,nw,noverlap,window,EVFlag) | |
140 %COMPUTEEIG Compute eigenvalues and eigenvectors of correlation matrix. | |
141 % | |
142 % Inputs: | |
143 % | |
144 % x - input vector or matrix | |
145 % CorrFlag - (flag) indicates whether x is a correlation matrix | |
146 % nw - (integer) length of the rows of the data matrix | |
147 % (only used if x is vector) | |
148 % noverlap - (integer) overlap between the rows of the data matrix | |
149 % (used in conjunction with nw) | |
150 % window - (vector) window to be applied to each column of data | |
151 % matrix (not used if x is a correlation matrix) | |
152 % EVFlag - True if eigenvector method, false if MUSIC. | |
153 % | |
154 % | |
155 % Outputs: | |
156 % | |
157 % eigenvals | |
158 % eigenvects | |
159 % | |
160 % If x is a matrix, | |
161 % If CorrFlag = 1, input x is a correlation matrix, we compute the | |
162 % eigendecomposition and order the eigenvalues and eigenvectors. | |
163 % | |
164 % If x is a vector, | |
165 % a data matrix is formed by calling corrmtx unless a custom nw | |
166 % and noverlap are specified. In that case, we use buffer to form | |
167 % the data matrix. | |
168 % | |
169 % If window is not empty, each row of the data matrix will be | |
170 % multiplied by the window. | |
171 | |
172 % Determine if the input is a matrix | |
173 xIsMatrix = ~any(size(x)==1); | |
174 | |
175 if xIsMatrix && CorrFlag, | |
176 % Input is Correlation matrix | |
177 | |
178 % Compute the eigenvectors and eigenvalues | |
179 [E,D] = eig((x+x')/2); % Ensure hermitian | |
180 [eigenvals,indx] = sort(diag(D),'descend'); | |
181 eigenvects = E(:,indx); | |
182 | |
183 else | |
184 if xIsMatrix | |
185 % Input is already a data matrix | |
186 [Mx,Nx] = size(x); % Determine size of data matrix | |
187 if EVFlag && (Nx > Mx), | |
188 errmsg = 'The number of columns in the data matrix cannot exceed the number of rows.'; | |
189 error(generatemsgid('invalidDataMatrix'),errmsg); | |
190 end | |
191 | |
192 else | |
193 % x is a vector | |
194 x = x(:); % Make it a column | |
195 if isempty(nw), | |
196 x = corrmtx(x,CorrMatrOrd-1,'cov'); | |
197 else | |
198 if EVFlag && nw > (ceil((length(x)-nw)/(nw-noverlap))+1), | |
199 errmsg = sprintf(['The segment length and overlap specified result in\n',... | |
200 'a data matrix with more columns than rows.']); | |
201 error(generatemsgid('invalidDataMatrix'),errmsg); | |
202 end | |
203 Lx = length(x); | |
204 x = buffer(x,nw,noverlap,'nodelay'); | |
205 if Lx <= nw, | |
206 error(generatemsgid('invalidSegmentLength'),'The segment length, NW, must be smaller than the signal length.'); | |
207 end | |
208 x = x'./sqrt(Lx-nw); % Scale appropriately such that X'*X is a scaled estimate of R | |
209 end | |
210 end | |
211 if ~isempty(window), | |
212 % Apply window to each row of data matrix | |
213 if length(window) ~= size(x,2), | |
214 error(generatemsgid('InvalidDimensions'),'Window length must equal the number of columns in the data matrix.'); | |
215 end | |
216 window = repmat(window(:).',size(x,1),1); | |
217 x = x.*window; | |
218 end | |
219 | |
220 % Compute the eigenvectors and eigenvalues via the SVD | |
221 [U,S,eigenvects] = svd(x,0); | |
222 eigenvals = diag(S).^2; % We need to square the singular values here | |
223 end | |
224 | |
225 | |
226 %-------------------------------------------------------------------------------------------- | |
227 function p_eff = determine_signal_space(p,eigenvals) | |
228 %DETERMINE_SIGNAL_SPACE Determines the effective dimension of the signal subspace. | |
229 % | |
230 % Inputs: | |
231 % | |
232 % p - (scalar or vector) signal subspace dimension | |
233 % (but may contain a desired threshold). | |
234 % eigenvals - (vector) contains the eigenvalues (sorted in decreasing order) | |
235 % of the correlation matrix | |
236 % | |
237 % Outputs: | |
238 % | |
239 % p_eff - The effective dimension of the signal subspace. If a threshold | |
240 % is given as p(2), the signal subspace will be equal to the number | |
241 % of eigenvalues, NEIG, greater than the threshold times the smallest | |
242 % eigenvalue. However, the dimension of the signal subspace is at most | |
243 % p(1), so that if NEIG is greater than p(1), p_eff will be equal to | |
244 % p(1). If the threshold criteria results in an empty signal subspace, | |
245 % once again we make p_eff = p(1). | |
246 | |
247 | |
248 % Use the signal space dimension or the threshold to separate the noise subspace eigenvectors | |
249 if length(p) == 2, | |
250 % The threshold will be the input threshold times the smallest eigenvalue | |
251 thresh = p(2)*eigenvals(end); | |
252 indx = find(eigenvals > thresh); | |
253 if ~isempty(indx) | |
254 p_eff = min( p(1), length(indx) ); | |
255 else | |
256 p_eff = p(1); | |
257 end | |
258 else | |
259 p_eff = p; | |
260 end | |
261 | |
262 % [EOF] - music.m |