comparison toolboxes/MIRtoolbox1.3.2/MIRToolbox/@mirautocor/mirautocor.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:e9a9cd732c1e
1 function varargout = mirautocor(orig,varargin)
2 % a = mirautocor(x) computes the autocorrelation function related to x.
3 % Optional parameters:
4 % mirautocor(...,'Min',mi) indicates the lowest delay taken into
5 % consideration. The unit can be precised:
6 % mirautocor(...,'Min',mi,'s') (default unit)
7 % mirautocor(...,'Min',mi,'Hz')
8 % Default value: 0 s.
9 % mirautocor(...,'Max',ma) indicates the highest delay taken into
10 % consideration. The unit can be specified as for 'Min'.
11 % Default value:
12 % if x is a signal, the highest delay is 0.05 s
13 % (corresponding to a minimum frequency of 20 Hz).
14 % if x is an envelope, the highest delay is 2 s.
15 % mirautocor(...,'Resonance',r) multiplies the autocorrelation function
16 % with a resonance curve:
17 % Possible values:
18 % 'Toiviainen' from (Toiviainen & Snyder, 2003)
19 % 'vanNoorden' from (van Noorden & Moelants, 2001)
20 % mirautocor(...,'Center',c) assigns the center value of the
21 % resonance curve, in seconds.
22 % Works mainly with 'Toiviainen' option.
23 % Default value: c = 0.5
24 % mirautocor(...,'Enhanced',a) reduces the effect of subharmonics.
25 % The original autocorrelation function is half-wave rectified,
26 % time-scaled by the factor a (which can be a factor list as
27 % well), and substracted from the original clipped function.
28 % (Tolonen & Karjalainen)
29 % If the 'Enhanced' option is not followed by any value,
30 % default value is a = 2:10
31 % mirautocor(...,'Halfwave') performs a half-wave rectification on the
32 % result.
33 % mirautocor(...,'Freq') represents the autocorrelation function in the
34 % frequency domain.
35 % mirautocor(...,'NormalWindow',w): applies a window to the input
36 % signal and divides the autocorrelation by the autocorrelation of
37 % that window (Boersma 1993).
38 % Possible values: any windowing function proposed in the Signal
39 % Processing Toolbox (help window) plus 'rectangle' (no
40 % windowing)
41 % Default value: w = 'hanning'
42 % mirautocor(...,'NormalWindow',0): toggles off this normalization
43 % (which is on by default).
44 % All the parameters described previously can be applied to an
45 % autocorrelation function itself, in order to arrange the results
46 % after the actual computation of the autocorrelation computations.
47 % For instance: a = mirautocor(a,'Resonance','Enhanced')
48 % Other optional parameter:
49 % mirautocor(...,'Compres',k) computes the autocorrelation in the
50 % frequency domain and includes a magnitude compression of the
51 % spectral representation. A normal autocorrelation corresponds
52 % to the value k=2, but values lower than 2 are suggested by
53 % (Tolonen & Karjalainen, 2000).
54 % Default value: k = 0.67
55 % mirautocor(...,'Normal',n) or simply mirautocor(...,n) specifies
56 % the normalization strategy. Accepted values are 'biased',
57 % 'unbiased', 'coeff' (default value) and 'none'.
58 % See help xcorr for an explanation.
59
60 min.key = 'Min';
61 min.type = 'Integer';
62 min.unit = {'s','Hz'};
63 if isamir(orig,'mirspectrum')
64 min.defaultunit = 'Hz';
65 else
66 min.defaultunit = 's';
67 end
68 min.default = 0;
69 min.opposite = 'max';
70 option.min = min;
71
72 max.key = 'Max';
73 max.type = 'Integer';
74 max.unit = {'s','Hz'};
75 if isamir(orig,'mirspectrum')
76 max.defaultunit = 'Hz';
77 else
78 max.defaultunit = 's';
79 end
80 if isamir(orig,'mirenvelope') || isamir(orig,'mirdiffenvelope')
81 max.default = 2; % for envelopes, longest period: 2 seconds.
82 elseif isamir(orig,'miraudio') || ischar(orig) % for audio signal,lowest frequency: 20 Hz.
83 max.default = 1/20;
84 else
85 max.default = Inf;
86 end
87 max.opposite = 'min';
88 option.max = max;
89
90 scaleoptbw.key = 'Normal'; %'Normal' keyword optional
91 scaleoptbw.key = 'Boolean';
92 option.scaleoptbw = scaleoptbw;
93 scaleopt.type = 'String';
94 scaleopt.choice = {'biased','unbiased','coeff','none'};
95 scaleopt.default = 'coeff';
96 option.scaleopt = scaleopt;
97
98 gener.key = {'Generalized','Compres'};
99 gener.type = 'Integer';
100 gener.default = 2;
101 gener.keydefault = .67;
102 option.gener = gener;
103
104 ni.key = 'NormalInput'; %% Normalize before frame or chunk??
105 ni.type = 'Boolean';
106 ni.default = 0;
107 option.ni = ni;
108
109 reso.key = 'Resonance';
110 reso.type = 'String';
111 reso.choice = {'ToiviainenSnyder','Toiviainen','vanNoorden','no','off',0};
112 reso.keydefault = 'Toiviainen';
113 reso.when = 'After';
114 reso.default = 0;
115 option.reso = reso;
116
117 resocenter.key = {'Center','Centre'};
118 resocenter.type = 'Integer';
119 resocenter.when = 'After';
120 option.resocenter = resocenter;
121
122 h.key = 'Halfwave';
123 h.type = 'Boolean';
124 h.when = 'After';
125 h.default = 0;
126 option.h = h;
127
128 e.key = 'Enhanced';
129 e.type = 'Integers';
130 e.default = [];
131 e.keydefault = 2:10;
132 e.when = 'After';
133 option.e = e;
134
135 fr.key = 'Freq';
136 fr.type = 'Boolean';
137 fr.default = 0;
138 fr.when = 'After';
139 option.fr = fr;
140
141 nw.key = 'NormalWindow';
142 nw.when = 'Both';
143 if isamir(orig,'mirspectrum')
144 nw.default = 0;
145 elseif isamir(orig,'mirenvelope')
146 nw.default = 'rectangular';
147 else
148 nw.default = 'hanning';
149 end
150 option.nw = nw;
151
152 win.key = 'Window';
153 win.type = 'String';
154 win.default = NaN;
155 option.win = win;
156
157 specif.option = option;
158
159 specif.defaultframelength = 0.05;
160 specif.defaultframehop = 0.5;
161 specif.eachchunk = @eachchunk;
162 specif.combinechunk = @combinechunk;
163
164 if isamir(orig,'mirscalar') || isamir(orig,'mirenvelope')
165 specif.nochunk = 1;
166 end
167
168 varargout = mirfunction(@mirautocor,orig,varargin,nargout,specif,@init,@main);
169
170
171 function [x type] = init(x,option)
172 type = 'mirautocor';
173
174
175 function a = main(orig,option,postoption)
176 if iscell(orig)
177 orig = orig{1};
178 end
179 if isa(orig,'mirautocor')
180 a = orig;
181 if not(isempty(option)) && ...
182 (option.min || iscell(option.max) || option.max < Inf)
183 coeff = get(a,'Coeff');
184 delay = get(a,'Delay');
185 for h = 1:length(coeff)
186 if a.freq
187 mi = 1/option.max;
188 ma = 1/option.min;
189 else
190 mi = option.min;
191 ma = option.max;
192 end
193 for k = 1:length(coeff{h})
194 range = find(and(delay{h}{k}(:,1,1) >= mi,...
195 delay{h}{k}(:,1,1) <= ma));
196 coeff{h}{k} = coeff{h}{k}(range,:,:);
197 delay{h}{k} = delay{h}{k}(range,:,:);
198 end
199 end
200 a = set(a,'Coeff',coeff,'Delay',delay);
201 end
202 if not(isempty(postoption)) && not(isequal(postoption,0))
203 a = post(a,postoption);
204 end
205 elseif ischar(orig)
206 a = mirautocor(miraudio(orig),option,postoption);
207 else
208 if nargin == 0
209 orig = [];
210 end
211 a.freq = 0;
212 a.ofspectrum = 0;
213 a.window = {};
214 a.normalwindow = 0;
215 a = class(a,'mirautocor',mirdata(orig));
216 a = purgedata(a);
217 a = set(a,'Ord','coefficients');
218 sig = get(orig,'Data');
219 if isa(orig,'mirspectrum')
220 a = set(a,'Title','Spectrum autocorrelation','OfSpectrum',1,...
221 'Abs','frequency (Hz)');
222 pos = get(orig,'Pos');
223 else
224 if isa(orig,'mirscalar')
225 a = set(a,'Title',[get(orig,'Title') ' autocorrelation']);
226 pos = get(orig,'FramePos');
227 for k = 1:length(sig)
228 for l = 1:length(sig{k})
229 sig{k}{l} = sig{k}{l}';
230 pos{k}{l} = pos{k}{l}(1,:,:)';
231 end
232 end
233 else
234 if isa(orig,'mirenvelope')
235 a = set(a,'Title','Envelope autocorrelation');
236 elseif not(isa(orig,'mirautocor'))
237 a = set(a,'Title','Waveform autocorrelation');
238 end
239 pos = get(orig,'Pos');
240 end
241 a = set(a,'Abs','lag (s)');
242 end
243 f = get(orig,'Sampling');
244
245 if isnan(option.win)
246 if isequal(option.nw,0) || ...
247 strcmpi(option.nw,'Off') || strcmpi(option.nw,'No')
248 option.win = 0;
249 elseif isequal(option.nw,1) || strcmpi(option.nw,'On') || ...
250 strcmpi(option.nw,'Yes')
251 option.win = 'hanning';
252 else
253 option.win = postoption.nw;
254 end
255 end
256
257 coeff = cell(1,length(sig));
258 lags = cell(1,length(sig));
259 wind = cell(1,length(sig));
260 for k = 1:length(sig)
261 s = sig{k};
262 p = pos{k};
263 fk = f{k};
264 if iscell(option.max)
265 mi = option.min{k};
266 ma = option.max{k};
267 else
268 mi = option.min;
269 ma = option.max;
270 end
271 coeffk = cell(1,length(s));
272 lagsk = cell(1,length(s));
273 windk = cell(1,length(s));
274 for l = 1:length(s)
275 sl = s{l};
276 sl(isnan(sl)) = 0;
277 if option.ni
278 mxsl = repmat(max(sl),[size(sl,1),1,1]);
279 mnsl = repmat(min(sl),[size(sl,1),1,1]);
280 sl = (sl-mnsl)./(mxsl-mnsl);
281 end
282 pl = p{l};
283 pl = pl-repmat(pl(1,:,:),[size(pl,1),1,1]);
284 ls = size(sl,1);
285 if mi
286 misp = find(pl(:,1,1)>=mi);
287 if isempty(misp)
288 warning('WARNING IN MIRAUTOCOR: The specified range of delays exceeds the temporal length of the signal.');
289 disp('Minimum delay set to zero.')
290 misp = 1; % misp is the lowest index of the lag range
291 mi = 0;
292 else
293 misp = misp(1);
294 end
295 else
296 misp = 1;
297 end
298 if ma
299 masp = find(pl(:,1,1)>=ma);
300 if isempty(masp)
301 masp = Inf;
302 else
303 masp = masp(1);
304 end
305 else
306 masp = Inf;
307 end
308 masp = min(masp,ceil(ls/2));
309 if masp <= misp
310 if size(sl,2) > 1
311 warning('WARNING IN MIRAUTOCOR: Frame length is too small.');
312 else
313 warning('WARNING IN MIRAUTOCOR: The audio sequence is too small.');
314 end
315 display('The autocorrelation is not defined for this range of delays.');
316 end
317 sl = center(sl);
318 if not(ischar(option.win)) || strcmpi(option.win,'Rectangular')
319 kw = ones(size(sl));
320 else
321 N = size(sl,1);
322 winf = str2func(option.win);
323 try
324 w = window(winf,N);
325 catch
326 if strcmpi(option.win,'hamming')
327 disp('Signal Processing Toolbox does not seem to be installed. Recompute the hamming window manually.');
328 w = 0.54 - 0.46 * cos(2*pi*(0:N-1)'/(N-1));
329 else
330 warning(['WARNING in MIRAUTOCOR: Unknown windowing function ',option.win,' (maybe Signal Processing Toolbox is not installed).']);
331 disp('No windowing performed.')
332 w = ones(size(sl,1),1);
333 end
334 end
335 kw = repmat(w,[1,size(sl,2),size(sl,3)]);
336 sl = sl.* kw;
337 end
338
339 if strcmpi(option.scaleopt,'coeff')
340 scaleopt = 'none';
341 else
342 scaleopt = option.scaleopt;
343 end
344 c = zeros(masp,size(sl,2),size(sl,3));
345 for i = 1:size(sl,2)
346 for j = 1:size(sl,3)
347 if option.gener == 2
348 cc = xcorr(sl(:,i,j),masp-1,scaleopt);
349 c(:,i,j) = cc(masp:end);
350 else
351 ss = abs(fft(sl(:,i,j)));
352 ss = ss.^option.gener;
353 cc = ifft(ss);
354 ll = (0:masp-1);
355 c(:,i,j) = cc(ll+1);
356 end
357 end
358 if strcmpi(option.scaleopt,'coeff') && option.gener == 2
359 % to be adapted to generalized autocor
360 c(:,i,:) = c(:,i,:)/xcorr(sum(sl(:,i,:),3),0);
361 % This is a kind of generalization of the 'coeff'
362 % normalization for multi-channels signals. In the
363 % original 'coeff' option, the autocorrelation at zero
364 % lag is identically 1.0. In this multi-channels
365 % version, the autocorrelation at zero lag is such that
366 % the sum over channels becomes identically 1.0.
367 end
368 end
369 coeffk{l} = c(misp:end,:,:);
370 pl = pl(find(pl(:,1,1) >=mi),:,:);
371 lagsk{l} = pl(1:min(size(coeffk{l},1),size(pl,1)),:,:);
372 windk{l} = kw;
373 end
374 coeff{k} = coeffk;
375 lags{k} = lagsk;
376 wind{k} = windk;
377 end
378 a = set(a,'Coeff',coeff,'Delay',lags,'Window',wind);
379 if not(isempty(postoption))
380 a = post(a,postoption);
381 end
382 end
383
384
385 function a = post(a,option)
386 debug = 0;
387 coeff = get(a,'Coeff');
388 lags = get(a,'Delay');
389 wind = get(a,'Window');
390 freq = option.fr && not(get(a,'FreqDomain'));
391 if isequal(option.e,1)
392 option.e = 2:10;
393 end
394 if max(option.e) > 1
395 pa = mirpeaks(a,'NoBegin','NoEnd','Contrast',.01);
396 va = mirpeaks(a,'Valleys','Contrast',.01);
397 pv = get(pa,'PeakVal');
398 vv = get(va,'PeakVal');
399 end
400 for k = 1:length(coeff)
401 for l = 1:length(coeff{k})
402 c = coeff{k}{l}; % Coefficients of autocorrelation
403 t = lags{k}{l}; % Delays of autocorrelation
404 if not(isempty(c))
405 if not(isequal(option.nw,0) || strcmpi(option.nw,'No') || ...
406 strcmpi(option.nw,'Off') || a.normalwindow) % 'NormalWindow' option
407 xw = zeros(size(c));
408 lc = size(c,1);
409 for j = 1:size(c,3)
410 for i = 1:size(c,2)
411 xwij = xcorr(wind{k}{l}(:,i,j),lc,'coeff');
412 xw(:,i,j) = xwij(lc+2:end);
413 end
414 end
415 c = c./ xw;
416 a.normalwindow = 1;
417 end
418 if ischar(option.reso) && ...
419 (strcmpi(option.reso,'ToiviainenSnyder') || ...
420 strcmpi(option.reso,'Toiviainen') || ...
421 strcmpi(option.reso,'vanNoorden'))
422 if isa(a,'mirautocor') && get(a,'FreqDomain')
423 ll = 1./t;
424 else
425 ll = t;
426 end
427 if not(option.resocenter)
428 option.resocenter = .5;
429 end
430 if strcmpi(option.reso,'ToiviainenSnyder') || ...
431 strcmpi(option.reso,'Toiviainen')
432 w = max(1 - 0.25*(log2(max(ll,1e-12)/option.resocenter)).^2, 0);
433 elseif strcmpi(option.reso,'vanNoorden')
434 f0=2.193; b=option.resocenter;
435 f=1./ll; a1=(f0*f0-f.*f).^2+b*f.^2; a2=f0^4+f.^4;
436 w=(1./sqrt(a1))-(1./sqrt(a2));
437 end
438 if max(w) == 0
439 warning('The resonance curve, not defined for this range of delays, will not be applied.')
440 else
441 w = w/max(w);
442 c = c.* repmat(w,[1,size(c,2),size(c,3)]);
443 end
444 end
445 if option.h
446 c = hwr(c);
447 end
448 if max(option.e) > 1
449 if a.freq
450 freq = 1;
451 for i = 1:size(c,3)
452 c(:,:,i) = flipud(c(:,:,i));
453 end
454 t = flipud(1./t);
455 end
456
457 for g = 1:size(c,2)
458 for h = 1:size(c,3)
459 cgh = c(:,g,h);
460 if length(cgh)>1
461 pvk = pv{k}{l}{1,g,h};
462 mv = [];
463 if not(isempty(pvk))
464 mp = min(pv{k}{l}{1,g,h}); %Lowest peak
465 vvv = vv{k}{l}{1,g,h}; %Valleys
466 mv = vvv(find(vvv<mp,1,'last'));
467 %Highest valley below the lowest peak
468
469 if not(isempty(mv))
470 cgh = cgh-mv;
471 end
472 end
473 cgh2 = cgh;
474 tgh2 = t(:,g,1);
475 coef = cgh(2)-cgh(1); % initial slope of the autocor curve
476 tcoef = tgh2(2)-tgh2(1);
477 deter = 0;
478 inter = 0;
479
480 repet = find(not(diff(tgh2))); % Avoid bug if repeated x-values
481 if repet
482 warning('WARNING in MIRAUTOCOR: Two successive samples have exactly same temporal position.');
483 tgh2(repet+1) = tgh2(repet)+1e-12;
484 end
485
486 if coef < 0
487 % initial descending slope removed
488 deter = find(diff(cgh2)>0,1)-1;
489 % number of removed points
490 if isempty(deter)
491 deter = 0;
492 end
493 cgh2(1:deter) = [];
494 tgh2(1:deter) = [];
495 coef = cgh2(2)-cgh2(1);
496 end
497
498 if coef > 0
499 % initial ascending slope prolonged to the left
500 % until it reaches the x-axis
501 while cgh2(1) > 0
502 coef = coef*1.1;
503 % the further to the left, ...
504 % the more ascending is the slope
505 % (not sure it always works, though...)
506 inter = inter+1;
507 % number of added points
508 cgh2 = [cgh2(1)-coef; cgh2];
509 tgh2 = [tgh2(1)-tcoef; tgh2];
510 end
511 cgh2(1) = 0;
512 end
513
514 for i = option.e % Enhancing procedure
515 % option.e is the list of scaling factors
516 % i is the scaling factor
517 if i
518 be = find(tgh2 & tgh2/i >= tgh2(1),1);
519 % starting point of the substraction
520 % on the X-axis
521
522 if not(isempty(be))
523 ic = interp1(tgh2,cgh2,tgh2/i);
524 % The scaled autocorrelation
525 ic(1:be-1) = 0;
526 ic(find(isnan(ic))) = Inf;
527 % All the NaN values are changed
528 % into 0 in the resulting curve
529 ic = max(ic,0);
530
531 if debug
532 hold off,plot(tgh2,cgh2)
533 end
534
535 cgh2 = cgh2 - ic;
536 % The scaled autocorrelation
537 % is substracted to the initial one
538
539 cgh2 = max(cgh2,0);
540 % Half-wave rectification
541
542 if debug
543 hold on,plot(tgh2,ic,'r')
544 hold on,plot(tgh2,cgh2,'g')
545 drawnow
546 figure
547 end
548 end
549 end
550 end
551
552 % The temporary modifications are
553 % removed from the final curve
554 if inter>=deter
555 c(:,g,h) = cgh2(inter-deter+1:end);
556 if not(isempty(mv))
557 c(:,g,h) = c(:,g,h) + mv;
558 end
559 else
560 c(:,g,h) = [zeros(deter-inter,1);cgh2];
561 end
562 end
563 end
564 end
565 end
566 if freq
567 if t(1,1) == 0
568 c = c(2:end,:,:);
569 t = t(2:end,:,:);
570 end
571 for i = 1:size(c,3)
572 c(:,:,i) = flipud(c(:,:,i));
573 end
574 t = flipud(1./t);
575 end
576 coeff{k}{l} = c;
577 lags{k}{l} = t;
578 end
579 end
580 end
581 a = set(a,'Coeff',coeff,'Delay',lags,'Freq');
582 if freq
583 a = set(a,'FreqDomain',1,'Abs','frequency (Hz)');
584 end
585
586
587 function [y orig] = eachchunk(orig,option,missing,postchunk)
588 option.scaleopt = 'none';
589 y = mirautocor(orig,option);
590
591
592 function y = combinechunk(old,new)
593 do = get(old,'Data');
594 do = do{1}{1};
595 dn = get(new,'Data');
596 dn = dn{1}{1};
597 if abs(size(dn,1)-size(do,1)) <= 2 % Probleme of border fluctuation
598 mi = min(size(dn,1),size(do,1));
599 dn = dn(1:mi,:,:);
600 do = do(1:mi,:,:);
601 elseif length(dn) < length(do)
602 dn(length(do),:,:) = 0; % Zero-padding
603 end
604 y = set(old,'ChunkData',do+dn);