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