Mercurial > hg > aimmat
comparison aim-mat/modules/usermodule/pitchstrength/find_pitches.asv @ 4:537f939baef0 tip
various bug fixes and changed copyright message
author | Stefan Bleeck <bleeck@gmail.com> |
---|---|
date | Tue, 16 Aug 2011 14:37:17 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:20ada0af3d7d | 4:537f939baef0 |
---|---|
1 % function [pitchstrength, dominant_time] = find_pitches(profile, , a_priori, fqp_fq) | |
2 % | |
3 % To analyse the time interval profile of the auditory image | |
4 % | |
5 % INPUT VALUES: | |
6 % | |
7 % RETURN VALUE: | |
8 % | |
9 | |
10 % (c) 2003, University of Cambridge, Medical Research Council | |
11 % Stefan Bleeck (stefan@bleeck.de) | |
12 % http://www.mrc-cbu.cam.ac.uk/cnbh/aimmanual | |
13 % $Date: 2003/07/17 10:56:16 $ | |
14 % $Revision: 1.5 $ | |
15 function result = find_pitches(profile,options) | |
16 % different ways to define the pitch strength: | |
17 % 1: the absolute height of the highest peak | |
18 % 2: ratio between peak hight and width devided at base | |
19 % % % % 2: the ration of the highest peak divided by the width at a certain point (given | |
20 % % % % by the parameter height_to_width_ratio | |
21 % 3: the height of the highest peak divided by the hight of the peak just one to | |
22 % the right. This measurement is very successfull in the ramped/damped stimuli | |
23 % | |
24 % 4: Further we want to know all these values at a fixed point called target_frequency | |
25 % and in the range given by allowed_frequency_deviation in % | |
26 % | |
27 % 5: We are also interested in the frequency value of the highest peak, because | |
28 % we hope, that this is finally the pitch. | |
29 % | |
30 % 6: for the dual profile model, we also give back two more values concerning similar | |
31 % properties for the spectral profile. Here, the pitch strenght is defined as the | |
32 % height of the highest peak divided by the range that is given in two parameters | |
33 % (usually 20% to 80% of the maximum) | |
34 | |
35 | |
36 plot_switch =1; | |
37 | |
38 if nargin < 2 | |
39 options=[]; | |
40 end | |
41 % | |
42 | |
43 % peaks must be higher then this of the maximum to be recognised | |
44 ps_threshold=0.1; | |
45 height_width_ratio=options.ps_options.height_width_ratio; % height of peak, where the width is measured | |
46 | |
47 | |
48 % preliminary return values. | |
49 % height of the highest peak | |
50 % result.free.highest_peak_hight=0; | |
51 % result.free.highest_peak_frequency=0; | |
52 % hight to width ratio | |
53 % result.free.height_width_ratio=0; | |
54 % highest peak divided by next highest | |
55 % result.free.neigbouring_ratio=0; | |
56 | |
57 % now all these at a fixed frequency: | |
58 % % result.fixed.highest_peak_hight=0; | |
59 % result.fixed.highest_peak_frequency=0; | |
60 % result.fixed.height_width_ratio=0; | |
61 % result.fixed.neigbouring_ratio=0; | |
62 % | |
63 % % other things useful for plotting | |
64 % result.smoothed_signal=[]; | |
65 % result.peaks = []; | |
66 | |
67 | |
68 % now start the show | |
69 | |
70 % % change the scaling to logarithm, before doing anything else: | |
71 % log_profile=logsigx(profile,0.001,0.035); | |
72 % result.smoothed_signal=log_profile; | |
73 | |
74 % don't do this change | |
75 log_profile=profile; | |
76 | |
77 current_lowpass_frequency=options.ps_options.low_pass_frequency; | |
78 smooth_sig=lowpass(log_profile,current_lowpass_frequency); | |
79 envpeaks = PeakPicker(smooth_sig); | |
80 result.smoothed_signal=smooth_sig; | |
81 | |
82 if isempty(envpeaks) % only, when there is no signal | |
83 return | |
84 end | |
85 | |
86 % reject impossible peaks | |
87 ep=envpeaks;ep2=[];c=1; | |
88 for i=1:length(envpeaks); | |
89 if envpeaks{i}.t>0.002 && envpeaks{i}.t<0.03 && envpeaks{i}.y>0.01 | |
90 ep2{c}=ep{i}; | |
91 c=c+1; | |
92 end | |
93 end | |
94 envpeaks=ep2; % replace | |
95 if isempty(envpeaks) % only, when there is no signal | |
96 return | |
97 end | |
98 % | |
99 % % translate times back to times: | |
100 % for i=1:length(envpeaks) % construct all maxima | |
101 % envpeaks{i}.t=1/x2fre(smooth_sig,envpeaks{i}.x); | |
102 % end | |
103 | |
104 | |
105 % nr1: highest peak value | |
106 % find the highest peak and its frequency | |
107 % sort all for the highest first! | |
108 % envpeaks=sortstruct(envpeaks,'y'); | |
109 % result.free.highest_peak_frequency=1/envpeaks{1}.t; | |
110 % result.free.highest_peak_hight=envpeaks{1}.y; | |
111 | |
112 | |
113 | |
114 % SB 08.2012: adjusted the method to make it simpler for Daniels signals of | |
115 % IRN | |
116 % nr 2: height to width of each peak. Height=height of peak. Width = width | |
117 % of the two adjacent minima | |
118 for i=1:length(envpeaks) % construct all maxima | |
119 where=envpeaks{i}.t; | |
120 hp=envpeaks{i}.y; % height peak | |
121 hb=(envpeaks{i}.left.y+envpeaks{i}.right.y)/2;% base peak | |
122 diffheight=hp-hb; | |
123 w=log(envpeaks{i}.right.t)-log(envpeaks{i}.left.t); % width at base | |
124 if w>0 && diffheight>0. | |
125 envpeaks{i}.v2012_height_base_width_ratio=diffheight/w; | |
126 else | |
127 envpeaks{i}.v2012_height_base_width_ratio=0; | |
128 end | |
129 envpeaks{i}.v2012_base_width=w; | |
130 envpeaks{i}.v2012_base_where_widths=hb; %base height | |
131 end | |
132 | |
133 envpeaks=sortstruct(envpeaks,'v2012_height_base_width_ratio'); | |
134 | |
135 if plot_switch | |
136 figure(2134) | |
137 clf | |
138 hold on | |
139 plot(log_profile,'r'); | |
140 plot(smooth_sig,'b') | |
141 for i=1:min(5,length(envpeaks)) | |
142 % time=envpeaks{i}.t; | |
143 % x=envpeaks{i}.x; | |
144 % y=envpeaks{i}.y; | |
145 % plot(time,y,'Marker','o','Markerfacecolor','g','MarkeredgeColor','g','MarkerSize',2); | |
146 % time_left=envpeaks{i}.left.t; | |
147 % % x_left=envpeaks{i}.left.x; | |
148 % y_left=envpeaks{i}.left.y; | |
149 % time_right=envpeaks{i}.right.t; | |
150 % % x_right=envpeaks{i}.right.x; | |
151 % y_right=envpeaks{i}.right.y; | |
152 % plot(time_left,y_left,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2); | |
153 % plot(time_right,y_right,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2); | |
154 | |
155 t=envpeaks{i}.t; | |
156 ypeak=envpeaks{i}.y; | |
157 % ps=peaks{ii}.pitchstrength; | |
158 ps=envpeaks{i}.v2012_height_base_width_ratio; | |
159 | |
160 if i==1 | |
161 plot(t,ypeak,'Marker','o','Markerfacecolor','b','MarkeredgeColor','b','MarkerSize',10); | |
162 text(t,ypeak*1.05,sprintf('%3.0f Hz: %4.2f ',1/t,ps),'VerticalAlignment','bottom','HorizontalAlignment','center','color','b','Fontsize',12); | |
163 else | |
164 plot(t,ypeak,'Marker','o','Markerfacecolor','g','MarkeredgeColor','w','MarkerSize',5); | |
165 text(t,ypeak*1.05,sprintf('%3.0f Hz: %4.2f ',1/t,ps),'VerticalAlignment','bottom','HorizontalAlignment','center','color','g','Fontsize',12); | |
166 end | |
167 plot(envpeaks{i}.left.t,envpeaks{i}.left.y,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',5); | |
168 plot(envpeaks{i}.right.t,envpeaks{i}.right.y,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',5); | |
169 | |
170 | |
171 ybase=envpeaks{i}.v2012_base_where_widths; | |
172 line([t t],[ybase ypeak],'color','m'); | |
173 line([envpeaks{i}.left.t envpeaks{i}.right.t],[ybase ybase],'color','m'); | |
174 | |
175 end | |
176 | |
177 % set(gca,'xscale','log') | |
178 set(gca,'xlim',[0.001 0.03]) | |
179 | |
180 fres=[500 300 200 150 100 70 50 20]; | |
181 set(gca,'xtick',1./fres); | |
182 set(gca,'xticklabel',fres); | |
183 xlabel('Frequency (Hz)') | |
184 ylabel('arbitrary normalized units') | |
185 | |
186 % current_time=options.current_time*1000; | |
187 % y=get(gca,'ylim'); | |
188 % y=y(2); | |
189 % text(700,y,sprintf('%3.0f ms',current_time),'verticalalignment','top'); | |
190 | |
191 % for i=1:length(envpeaks) | |
192 % height_width_ratio=envpeaks{i}.height_width_ratio; | |
193 % if i <4 | |
194 % line([envpeaks{i}.t envpeaks{i}.x],[envpeaks{i}.y envpeaks{i}.y*(1-height_width_ratio)],'Color','r'); | |
195 % line([envpeaks{i}.where_widths(1) envpeaks{i}.where_widths(2)],[envpeaks{i}.y*(1-height_width_ratio) envpeaks{i}.y*(1-height_width_ratio)],'Color','r'); | |
196 % x=envpeaks{i}.t; | |
197 % fre=1/envpeaks{i}.t; | |
198 % y=envpeaks{i}.y; | |
199 % text(x,y*1.05,sprintf('%3.0fHz: %2.2f',fre,height_width_ratio),'HorizontalAlignment','center'); | |
200 % end | |
201 % end | |
202 end | |
203 | |
204 | |
205 % and return the final result, only highest peak | |
206 peaks2=sortstruct(envpeaks,'v2012_height_base_width_ratio'); | |
207 result.free.ps=peaks2{1}.v2012_height_base_width_ratio; | |
208 result.free.fre=1/peaks2{1}.t; | |
209 | |
210 | |
211 | |
212 % | |
213 % | |
214 % % nr 2: height to width of highest peak | |
215 % for i=1:length(envpeaks) % construct all maxima | |
216 % % where=bin2time(smooth_sig,envpeaks{i}.x); | |
217 % where=envpeaks{i}.t; | |
218 % [~,height,breit,where_widths]=qvalue(smooth_sig,where,height_width_ratio); | |
219 % width=time2bin(smooth_sig,breit); | |
220 % if width>0 | |
221 % envpeaks{i}.height_width_ratio=height/width; | |
222 % else | |
223 % envpeaks{i}.height_width_ratio=0; | |
224 % end | |
225 % envpeaks{i}.width=width; | |
226 % envpeaks{i}.where_widths=where_widths; | |
227 % envpeaks{i}.peak_base_height_y=height*(1-height_width_ratio); | |
228 % end | |
229 % % and return the results | |
230 % % result.free.height_width_ratio=envpeaks{1}.height_width_ratio; | |
231 | |
232 % | |
233 % % nr 3: height of highest / right neigbour (right when time is towards | |
234 % % left, sorry) | |
235 % for i=1:length(envpeaks) % construct all maxima | |
236 % left=envpeaks{i}.left; | |
237 % if isfield(left,'y') && left.y>0 | |
238 % envpeaks{i}.neigbouring_ratio=result.free.highest_peak_hight/left.y; | |
239 % else | |
240 % envpeaks{i}.neigbouring_ratio=0; | |
241 % end | |
242 % end | |
243 % result.free.neigbouring_ratio=envpeaks{1}.neigbouring_ratio; | |
244 | |
245 | |
246 target_frequency=options.ps_options.target_frequency; | |
247 % now find all values for the fixed pitch strengh in target_frequency | |
248 if target_frequency>0 % only, when wanted | |
249 min_fre=target_frequency/options.ps_options.allowed_frequency_deviation; | |
250 max_fre=target_frequency*options.ps_options.allowed_frequency_deviation; | |
251 | |
252 for i=1:length(envpeaks) % look through all peaks, which one we need | |
253 fre_peak=1/envpeaks{i}.t; | |
254 if fre_peak > min_fre && fre_peak < max_fre | |
255 % we assume for the moment, that we only have one allowed here | |
256 % nr 1: height | |
257 result.fixed.highest_peak_frequency=fre_peak; | |
258 result.fixed.highest_peak_hight=envpeaks{i}.y; | |
259 result.fixed.height_width_ratio=envpeaks{i}.height_width_ratio; | |
260 result.fixed.neigbouring_ratio=envpeaks{i}.neigbouring_ratio; | |
261 end | |
262 end | |
263 end | |
264 | |
265 result.peaks =envpeaks; | |
266 | |
267 | |
268 | |
269 return | |
270 | |
271 | |
272 | |
273 | |
274 | |
275 % kucke, ob sich das erste Maxima überlappt. Falls ja, nochmal | |
276 % berechnen mit niedriger Lowpass frequenz | |
277 % nr_peaks=length(envpeaks); | |
278 % if nr_peaks==1 | |
279 % peak_found=1; | |
280 % continue | |
281 % end | |
282 % xleft=envpeaks{1}.where_widths(1); | |
283 % xright=envpeaks{1}.where_widths(2); | |
284 % for i=2:nr_peaks % | |
285 % xnull=envpeaks{i}.x; | |
286 % if xnull < xleft && xnull > xright | |
287 % peak_found=0; | |
288 % current_lowpass_frequency=current_lowpass_frequency/2; | |
289 % if current_lowpass_frequency<62.5 | |
290 % return | |
291 % end | |
292 % break | |
293 % end | |
294 % % wenn noch hier, dann ist alles ok | |
295 % peak_found=1; | |
296 % end | |
297 % end | |
298 | |
299 | |
300 % reduce the peaks to the relevant ones: | |
301 % through out all with pitchstrength smaller then threshold | |
302 % count=1; | |
303 % min_ps=ps_threshold*envpeaks{1}.pitchstrength; | |
304 % for i=1:length(envpeaks) | |
305 % if envpeaks{i}.pitchstrength>min_ps | |
306 % rpeaks{count}=envpeaks{i}; | |
307 % count=count+1; | |
308 % end | |
309 % end | |
310 | |
311 | |
312 % % final result for the full set | |
313 % result.final_pitchstrength=rpeaks{1}.pitchstrength; | |
314 % result.final_dominant_frequency=rpeaks{1}.fre; | |
315 % result.final_dominant_time=rpeaks{1}.t; | |
316 % result.smoothed_signal=smooth_sig; | |
317 % result.peaks=rpeaks; | |
318 % % return | |
319 | |
320 % Neuberechnung der Pitchstrength für peaks, die das Kriterium der | |
321 % Höhe zu Breite nicht erfüllen | |
322 % for i=1:length(rpeaks) % construct all maxima | |
323 % where=bin2time(smooth_sig,rpeaks{i}.x); | |
324 % [dummy,height,breit,where_widths]=qvalue(smooth_sig,where,heighttowidthminimum); | |
325 % width=time2bin(smooth_sig,breit); | |
326 % | |
327 % xleft=where_widths(2); | |
328 % xright=where_widths(1); | |
329 % left_peak=rpeaks{i}.left; | |
330 % right_peak=rpeaks{i}.right; | |
331 % | |
332 % | |
333 % xnull=rpeaks{i}.x; | |
334 % if xleft<left_peak.x || xright>right_peak.x | |
335 % t_xnull=bin2time(smooth_sig,xnull); | |
336 % [val,height,breit,widthvals,base_peak_y]=qvalue2(smooth_sig,t_xnull); | |
337 % width=time2bin(smooth_sig,breit); | |
338 % if width>0 | |
339 % rpeaks{i}.pitchstrength=height/width; | |
340 % else | |
341 % rpeaks{i}.pitchstrength=0; | |
342 % end | |
343 % rpeaks{i}.where_widths=time2bin(smooth_sig,widthvals); | |
344 % rpeaks{i}.width=width; | |
345 % rpeaks{i}.peak_base_height_y=base_peak_y; | |
346 % end | |
347 % end | |
348 | |
349 % sort again all for the highest first! | |
350 % rpeaks=sortstruct(rpeaks,'pitchstrength'); | |
351 | |
352 return | |
353 | |
354 | |
355 | |
356 | |
357 | |
358 | |
359 | |
360 | |
361 %%%%%% look for octave relationships | |
362 % | |
363 % | |
364 for i=1:length(rpeaks) % construct all maxima | |
365 % look, if the octave of the pitch is also present. | |
366 fre=rpeaks{i}.fre; | |
367 has_octave=0; | |
368 for j=1:length(rpeaks) | |
369 oct_fre=rpeaks{j}.fre; | |
370 % is the octave there? | |
371 if oct_fre > (2-octave_variability)*fre && oct_fre < (2+octave_variability)*fre | |
372 rpeaks{i}.has_octave=oct_fre; | |
373 rpeaks{i}.octave_peak_nr=j; | |
374 | |
375 % add the pss | |
376 % rpeaks{j}.pitchstrength=rpeaks{i}.pitchstrength+rpeaks{j}.pitchstrength; | |
377 | |
378 ps_real=rpeaks{j}.pitchstrength; | |
379 ps_oct=rpeaks{i}.pitchstrength; | |
380 hight_oct=rpeaks{j}.y; | |
381 hight_real=rpeaks{i}.y; | |
382 | |
383 % if ps_oct>ps_real && hight_oct > hight_real | |
384 % rpeaks{i}.pitchstrength=ps_real-1; % artificially drop down | |
385 % end | |
386 | |
387 has_octave=1; | |
388 break | |
389 end | |
390 if ~has_octave | |
391 rpeaks{i}.has_octave=0; | |
392 rpeaks{i}.octave_peak_nr=0; | |
393 end | |
394 end | |
395 end | |
396 | |
397 if plot_switch | |
398 figure(2134) | |
399 clf | |
400 hold on | |
401 plot(log_profile,'b') | |
402 plot(smooth_sig,'g') | |
403 for i=1:length(rpeaks) | |
404 time=rpeaks{i}.t; | |
405 x=rpeaks{i}.x; | |
406 y=rpeaks{i}.y; | |
407 plot(x,y,'Marker','o','Markerfacecolor','g','MarkeredgeColor','g','MarkerSize',2); | |
408 time_left=rpeaks{i}.left.t; | |
409 x_left=rpeaks{i}.left.x; | |
410 y_left=rpeaks{i}.left.y; | |
411 time_right=rpeaks{i}.right.t; | |
412 x_right=rpeaks{i}.right.x; | |
413 y_right=rpeaks{i}.right.y; | |
414 plot(x_left,y_left,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2); | |
415 plot(x_right,y_right,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2); | |
416 end | |
417 current_time=options.current_time*1000; | |
418 y=get(gca,'ylim'); | |
419 y=y(2); | |
420 text(700,y,sprintf('%3.0f ms',current_time),'verticalalignment','top'); | |
421 | |
422 for i=1:length(rpeaks) | |
423 pitchstrength=rpeaks{i}.pitchstrength; | |
424 if i <10 | |
425 line([rpeaks{i}.x rpeaks{i}.x],[rpeaks{i}.y rpeaks{i}.peak_base_height_y],'Color','m'); | |
426 line([rpeaks{i}.where_widths(1) rpeaks{i}.where_widths(2)],[rpeaks{i}.peak_base_height_y rpeaks{i}.peak_base_height_y],'Color','m'); | |
427 x=rpeaks{i}.x; | |
428 fre=rpeaks{i}.fre; | |
429 y=rpeaks{i}.y; | |
430 text(x,y*1.05,sprintf('%3.0fHz: %2.2f',fre,pitchstrength),'HorizontalAlignment','center'); | |
431 end | |
432 end | |
433 end | |
434 if plot_switch==1 | |
435 for i=1:length(rpeaks) | |
436 x=rpeaks{i}.x; | |
437 y=rpeaks{i}.y; | |
438 plot(x,y,'Marker','o','Markerfacecolor','g','MarkeredgeColor','g','MarkerSize',6); | |
439 | |
440 % plot the octaves as green lines | |
441 octave=rpeaks{i}.has_octave; | |
442 fre=rpeaks{i}.fre; | |
443 if octave>0 | |
444 oct_nr=rpeaks{i}.octave_peak_nr; | |
445 oct_fre=rpeaks{oct_nr}.fre; | |
446 | |
447 x=rpeaks{i}.x; | |
448 oct_x=rpeaks{oct_nr}.x; | |
449 y=rpeaks{i}.y; | |
450 oct_y=rpeaks{oct_nr}.y; | |
451 line([x oct_x],[y oct_y],'Color','g','LineStyle','--'); | |
452 end | |
453 end | |
454 end | |
455 | |
456 % rpeaks=sortstruct(rpeaks,'pitchstrength'); | |
457 rpeaks=sortstruct(rpeaks,'y'); | |
458 | |
459 % final result for the full set | |
460 result.final_pitchstrength=rpeaks{1}.pitchstrength; | |
461 result.final_dominant_frequency=rpeaks{1}.fre; | |
462 result.final_dominant_time=rpeaks{1}.t; | |
463 result.smoothed_signal=smooth_sig; | |
464 result.peaks=rpeaks; | |
465 | |
466 | |
467 | |
468 | |
469 function fre=x2fre(sig,x) | |
470 t_log = bin2time(sig,x); | |
471 t=f2f(t_log,0,0.035,0.001,0.035,'linlog'); | |
472 fre=1/t; |