bleeck@4: % function [pitchstrength, dominant_time] = find_pitches(profile, , a_priori, fqp_fq) bleeck@4: % bleeck@4: % To analyse the time interval profile of the auditory image bleeck@4: % bleeck@4: % INPUT VALUES: bleeck@4: % bleeck@4: % RETURN VALUE: bleeck@4: % bleeck@4: bleeck@4: % (c) 2011, University of Southampton bleeck@4: % Maintained by Stefan Bleeck (bleeck@gmail.com) bleeck@4: % download of current version is on the soundsoftware site: bleeck@4: % http://code.soundsoftware.ac.uk/projects/aimmat bleeck@4: % documentation and everything is on http://www.acousticscale.org bleeck@4: bleeck@4: function result = find_pitches(profile,options) bleeck@4: % different ways to define the pitch strength: bleeck@4: % 1: the absolute height of the highest peak bleeck@4: % 2: ratio between peak hight and width devided at base bleeck@4: % % % % 2: the ration of the highest peak divided by the width at a certain point (given bleeck@4: % % % % by the parameter height_to_width_ratio bleeck@4: % 3: the height of the highest peak divided by the hight of the peak just one to bleeck@4: % the right. This measurement is very successfull in the ramped/damped stimuli bleeck@4: % bleeck@4: % 4: Further we want to know all these values at a fixed point called target_frequency bleeck@4: % and in the range given by allowed_frequency_deviation in % bleeck@4: % bleeck@4: % 5: We are also interested in the frequency value of the highest peak, because bleeck@4: % we hope, that this is finally the pitch. bleeck@4: % bleeck@4: % 6: for the dual profile model, we also give back two more values concerning similar bleeck@4: % properties for the spectral profile. Here, the pitch strenght is defined as the bleeck@4: % height of the highest peak divided by the range that is given in two parameters bleeck@4: % (usually 20% to 80% of the maximum) bleeck@4: bleeck@4: bleeck@4: plot_switch =0; bleeck@4: bleeck@4: if nargin < 2 bleeck@4: options=[]; bleeck@4: end bleeck@4: % bleeck@4: bleeck@4: % peaks must be higher then this of the maximum to be recognised bleeck@4: ps_threshold=0.1; bleeck@4: height_width_ratio=options.ps_options.height_width_ratio; % height of peak, where the width is measured bleeck@4: bleeck@4: bleeck@4: % preliminary return values. bleeck@4: % height of the highest peak bleeck@4: % result.free.highest_peak_hight=0; bleeck@4: % result.free.highest_peak_frequency=0; bleeck@4: % hight to width ratio bleeck@4: % result.free.height_width_ratio=0; bleeck@4: % highest peak divided by next highest bleeck@4: % result.free.neigbouring_ratio=0; bleeck@4: bleeck@4: % now all these at a fixed frequency: bleeck@4: % % result.fixed.highest_peak_hight=0; bleeck@4: % result.fixed.highest_peak_frequency=0; bleeck@4: % result.fixed.height_width_ratio=0; bleeck@4: % result.fixed.neigbouring_ratio=0; bleeck@4: % bleeck@4: % % other things useful for plotting bleeck@4: % result.smoothed_signal=[]; bleeck@4: % result.peaks = []; bleeck@4: bleeck@4: bleeck@4: % now start the show bleeck@4: bleeck@4: % % change the scaling to logarithm, before doing anything else: bleeck@4: % log_profile=logsigx(profile,0.001,0.035); bleeck@4: % result.smoothed_signal=log_profile; bleeck@4: bleeck@4: % don't do this change bleeck@4: log_profile=profile; bleeck@4: bleeck@4: current_lowpass_frequency=options.ps_options.low_pass_frequency; bleeck@4: smooth_sig=lowpass(log_profile,current_lowpass_frequency); bleeck@4: envpeaks = PeakPicker(smooth_sig); bleeck@4: result.smoothed_signal=smooth_sig; bleeck@4: bleeck@4: if isempty(envpeaks) % only, when there is no signal bleeck@4: return bleeck@4: end bleeck@4: bleeck@4: % reject impossible peaks bleeck@4: ep=envpeaks;ep2=[];c=1; bleeck@4: for i=1:length(envpeaks); bleeck@4: if envpeaks{i}.t>0.002 && envpeaks{i}.t<0.03 && envpeaks{i}.y>0.01 bleeck@4: ep2{c}=ep{i}; bleeck@4: c=c+1; bleeck@4: end bleeck@4: end bleeck@4: envpeaks=ep2; % replace bleeck@4: if isempty(envpeaks) % only, when there is no signal bleeck@4: return bleeck@4: end bleeck@4: % bleeck@4: % % translate times back to times: bleeck@4: % for i=1:length(envpeaks) % construct all maxima bleeck@4: % envpeaks{i}.t=1/x2fre(smooth_sig,envpeaks{i}.x); bleeck@4: % end bleeck@4: bleeck@4: bleeck@4: % nr1: highest peak value bleeck@4: % find the highest peak and its frequency bleeck@4: % sort all for the highest first! bleeck@4: % envpeaks=sortstruct(envpeaks,'y'); bleeck@4: % result.free.highest_peak_frequency=1/envpeaks{1}.t; bleeck@4: % result.free.highest_peak_hight=envpeaks{1}.y; bleeck@4: bleeck@4: bleeck@4: bleeck@4: % SB 08.2012: adjusted the method to make it simpler for Daniels signals of bleeck@4: % IRN bleeck@4: % nr 2: height to width of each peak. Height=height of peak. Width = width bleeck@4: % of the two adjacent minima bleeck@4: for i=1:length(envpeaks) % construct all maxima bleeck@4: where=envpeaks{i}.t; bleeck@4: hp=envpeaks{i}.y; % height peak bleeck@4: hb=(envpeaks{i}.left.y+envpeaks{i}.right.y)/2;% base peak bleeck@4: diffheight=hp-hb; bleeck@4: w=log(envpeaks{i}.right.t)-log(envpeaks{i}.left.t); % width at base bleeck@4: if w>0 && diffheight>0.02; bleeck@4: envpeaks{i}.v2012_height_base_width_ratio=diffheight/w; bleeck@4: else bleeck@4: envpeaks{i}.v2012_height_base_width_ratio=0; bleeck@4: end bleeck@4: envpeaks{i}.v2012_base_width=w; bleeck@4: envpeaks{i}.v2012_base_where_widths=hb; %base height bleeck@4: end bleeck@4: bleeck@4: envpeaks=sortstruct(envpeaks,'v2012_height_base_width_ratio'); bleeck@4: bleeck@4: if plot_switch bleeck@4: figure(2134) bleeck@4: clf bleeck@4: hold on bleeck@4: plot(log_profile,'r'); bleeck@4: plot(smooth_sig,'b') bleeck@4: for i=1:min(5,length(envpeaks)) bleeck@4: % time=envpeaks{i}.t; bleeck@4: % x=envpeaks{i}.x; bleeck@4: % y=envpeaks{i}.y; bleeck@4: % plot(time,y,'Marker','o','Markerfacecolor','g','MarkeredgeColor','g','MarkerSize',2); bleeck@4: % time_left=envpeaks{i}.left.t; bleeck@4: % % x_left=envpeaks{i}.left.x; bleeck@4: % y_left=envpeaks{i}.left.y; bleeck@4: % time_right=envpeaks{i}.right.t; bleeck@4: % % x_right=envpeaks{i}.right.x; bleeck@4: % y_right=envpeaks{i}.right.y; bleeck@4: % plot(time_left,y_left,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2); bleeck@4: % plot(time_right,y_right,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2); bleeck@4: bleeck@4: t=envpeaks{i}.t; bleeck@4: ypeak=envpeaks{i}.y; bleeck@4: % ps=peaks{ii}.pitchstrength; bleeck@4: ps=envpeaks{i}.v2012_height_base_width_ratio; bleeck@4: bleeck@4: if i==1 bleeck@4: plot(t,ypeak,'Marker','o','Markerfacecolor','b','MarkeredgeColor','b','MarkerSize',10); bleeck@4: text(t,ypeak*1.05,sprintf('%3.0f Hz: %4.2f ',1/t,ps),'VerticalAlignment','bottom','HorizontalAlignment','center','color','b','Fontsize',12); bleeck@4: else bleeck@4: plot(t,ypeak,'Marker','o','Markerfacecolor','g','MarkeredgeColor','w','MarkerSize',5); bleeck@4: text(t,ypeak*1.05,sprintf('%3.0f Hz: %4.2f ',1/t,ps),'VerticalAlignment','bottom','HorizontalAlignment','center','color','g','Fontsize',12); bleeck@4: end bleeck@4: plot(envpeaks{i}.left.t,envpeaks{i}.left.y,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',5); bleeck@4: plot(envpeaks{i}.right.t,envpeaks{i}.right.y,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',5); bleeck@4: bleeck@4: bleeck@4: ybase=envpeaks{i}.v2012_base_where_widths; bleeck@4: line([t t],[ybase ypeak],'color','m'); bleeck@4: line([envpeaks{i}.left.t envpeaks{i}.right.t],[ybase ybase],'color','m'); bleeck@4: bleeck@4: end bleeck@4: bleeck@4: % set(gca,'xscale','log') bleeck@4: set(gca,'xlim',[0.001 0.03]) bleeck@4: bleeck@4: fres=[500 300 200 150 100 70 50 20]; bleeck@4: set(gca,'xtick',1./fres); bleeck@4: set(gca,'xticklabel',fres); bleeck@4: xlabel('Frequency (Hz)') bleeck@4: ylabel('arbitrary normalized units') bleeck@4: bleeck@4: % current_time=options.current_time*1000; bleeck@4: % y=get(gca,'ylim'); bleeck@4: % y=y(2); bleeck@4: % text(700,y,sprintf('%3.0f ms',current_time),'verticalalignment','top'); bleeck@4: bleeck@4: % for i=1:length(envpeaks) bleeck@4: % height_width_ratio=envpeaks{i}.height_width_ratio; bleeck@4: % if i <4 bleeck@4: % line([envpeaks{i}.t envpeaks{i}.x],[envpeaks{i}.y envpeaks{i}.y*(1-height_width_ratio)],'Color','r'); bleeck@4: % 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'); bleeck@4: % x=envpeaks{i}.t; bleeck@4: % fre=1/envpeaks{i}.t; bleeck@4: % y=envpeaks{i}.y; bleeck@4: % text(x,y*1.05,sprintf('%3.0fHz: %2.2f',fre,height_width_ratio),'HorizontalAlignment','center'); bleeck@4: % end bleeck@4: % end bleeck@4: end bleeck@4: bleeck@4: bleeck@4: % and return the final result, only highest peak bleeck@4: peaks2=sortstruct(envpeaks,'v2012_height_base_width_ratio'); bleeck@4: result.free.ps=peaks2{1}.v2012_height_base_width_ratio; bleeck@4: result.free.fre=1/peaks2{1}.t; bleeck@4: bleeck@4: bleeck@4: bleeck@4: % bleeck@4: % bleeck@4: % % nr 2: height to width of highest peak bleeck@4: % for i=1:length(envpeaks) % construct all maxima bleeck@4: % % where=bin2time(smooth_sig,envpeaks{i}.x); bleeck@4: % where=envpeaks{i}.t; bleeck@4: % [~,height,breit,where_widths]=qvalue(smooth_sig,where,height_width_ratio); bleeck@4: % width=time2bin(smooth_sig,breit); bleeck@4: % if width>0 bleeck@4: % envpeaks{i}.height_width_ratio=height/width; bleeck@4: % else bleeck@4: % envpeaks{i}.height_width_ratio=0; bleeck@4: % end bleeck@4: % envpeaks{i}.width=width; bleeck@4: % envpeaks{i}.where_widths=where_widths; bleeck@4: % envpeaks{i}.peak_base_height_y=height*(1-height_width_ratio); bleeck@4: % end bleeck@4: % % and return the results bleeck@4: % % result.free.height_width_ratio=envpeaks{1}.height_width_ratio; bleeck@4: bleeck@4: % bleeck@4: % % nr 3: height of highest / right neigbour (right when time is towards bleeck@4: % % left, sorry) bleeck@4: % for i=1:length(envpeaks) % construct all maxima bleeck@4: % left=envpeaks{i}.left; bleeck@4: % if isfield(left,'y') && left.y>0 bleeck@4: % envpeaks{i}.neigbouring_ratio=result.free.highest_peak_hight/left.y; bleeck@4: % else bleeck@4: % envpeaks{i}.neigbouring_ratio=0; bleeck@4: % end bleeck@4: % end bleeck@4: % result.free.neigbouring_ratio=envpeaks{1}.neigbouring_ratio; bleeck@4: bleeck@4: bleeck@4: target_frequency=options.ps_options.target_frequency; bleeck@4: % now find all values for the fixed pitch strengh in target_frequency bleeck@4: if target_frequency>0 % only, when wanted bleeck@4: min_fre=target_frequency/options.ps_options.allowed_frequency_deviation; bleeck@4: max_fre=target_frequency*options.ps_options.allowed_frequency_deviation; bleeck@4: bleeck@4: for i=1:length(envpeaks) % look through all peaks, which one we need bleeck@4: fre_peak=1/envpeaks{i}.t; bleeck@4: if fre_peak > min_fre && fre_peak < max_fre bleeck@4: % we assume for the moment, that we only have one allowed here bleeck@4: % nr 1: height bleeck@4: result.fixed.highest_peak_frequency=fre_peak; bleeck@4: result.fixed.highest_peak_hight=envpeaks{i}.y; bleeck@4: result.fixed.height_width_ratio=envpeaks{i}.height_width_ratio; bleeck@4: result.fixed.neigbouring_ratio=envpeaks{i}.neigbouring_ratio; bleeck@4: end bleeck@4: end bleeck@4: end bleeck@4: bleeck@4: result.peaks =envpeaks; bleeck@4: bleeck@4: bleeck@4: bleeck@4: return bleeck@4: bleeck@4: bleeck@4: bleeck@4: bleeck@4: bleeck@4: % kucke, ob sich das erste Maxima überlappt. Falls ja, nochmal bleeck@4: % berechnen mit niedriger Lowpass frequenz bleeck@4: % nr_peaks=length(envpeaks); bleeck@4: % if nr_peaks==1 bleeck@4: % peak_found=1; bleeck@4: % continue bleeck@4: % end bleeck@4: % xleft=envpeaks{1}.where_widths(1); bleeck@4: % xright=envpeaks{1}.where_widths(2); bleeck@4: % for i=2:nr_peaks % bleeck@4: % xnull=envpeaks{i}.x; bleeck@4: % if xnull < xleft && xnull > xright bleeck@4: % peak_found=0; bleeck@4: % current_lowpass_frequency=current_lowpass_frequency/2; bleeck@4: % if current_lowpass_frequency<62.5 bleeck@4: % return bleeck@4: % end bleeck@4: % break bleeck@4: % end bleeck@4: % % wenn noch hier, dann ist alles ok bleeck@4: % peak_found=1; bleeck@4: % end bleeck@4: % end bleeck@4: bleeck@4: bleeck@4: % reduce the peaks to the relevant ones: bleeck@4: % through out all with pitchstrength smaller then threshold bleeck@4: % count=1; bleeck@4: % min_ps=ps_threshold*envpeaks{1}.pitchstrength; bleeck@4: % for i=1:length(envpeaks) bleeck@4: % if envpeaks{i}.pitchstrength>min_ps bleeck@4: % rpeaks{count}=envpeaks{i}; bleeck@4: % count=count+1; bleeck@4: % end bleeck@4: % end bleeck@4: bleeck@4: bleeck@4: % % final result for the full set bleeck@4: % result.final_pitchstrength=rpeaks{1}.pitchstrength; bleeck@4: % result.final_dominant_frequency=rpeaks{1}.fre; bleeck@4: % result.final_dominant_time=rpeaks{1}.t; bleeck@4: % result.smoothed_signal=smooth_sig; bleeck@4: % result.peaks=rpeaks; bleeck@4: % % return bleeck@4: bleeck@4: % Neuberechnung der Pitchstrength für peaks, die das Kriterium der bleeck@4: % Höhe zu Breite nicht erfüllen bleeck@4: % for i=1:length(rpeaks) % construct all maxima bleeck@4: % where=bin2time(smooth_sig,rpeaks{i}.x); bleeck@4: % [dummy,height,breit,where_widths]=qvalue(smooth_sig,where,heighttowidthminimum); bleeck@4: % width=time2bin(smooth_sig,breit); bleeck@4: % bleeck@4: % xleft=where_widths(2); bleeck@4: % xright=where_widths(1); bleeck@4: % left_peak=rpeaks{i}.left; bleeck@4: % right_peak=rpeaks{i}.right; bleeck@4: % bleeck@4: % bleeck@4: % xnull=rpeaks{i}.x; bleeck@4: % if xleftright_peak.x bleeck@4: % t_xnull=bin2time(smooth_sig,xnull); bleeck@4: % [val,height,breit,widthvals,base_peak_y]=qvalue2(smooth_sig,t_xnull); bleeck@4: % width=time2bin(smooth_sig,breit); bleeck@4: % if width>0 bleeck@4: % rpeaks{i}.pitchstrength=height/width; bleeck@4: % else bleeck@4: % rpeaks{i}.pitchstrength=0; bleeck@4: % end bleeck@4: % rpeaks{i}.where_widths=time2bin(smooth_sig,widthvals); bleeck@4: % rpeaks{i}.width=width; bleeck@4: % rpeaks{i}.peak_base_height_y=base_peak_y; bleeck@4: % end bleeck@4: % end bleeck@4: bleeck@4: % sort again all for the highest first! bleeck@4: % rpeaks=sortstruct(rpeaks,'pitchstrength'); bleeck@4: bleeck@4: return bleeck@4: bleeck@4: bleeck@4: bleeck@4: bleeck@4: bleeck@4: bleeck@4: bleeck@4: bleeck@4: %%%%%% look for octave relationships bleeck@4: % bleeck@4: % bleeck@4: for i=1:length(rpeaks) % construct all maxima bleeck@4: % look, if the octave of the pitch is also present. bleeck@4: fre=rpeaks{i}.fre; bleeck@4: has_octave=0; bleeck@4: for j=1:length(rpeaks) bleeck@4: oct_fre=rpeaks{j}.fre; bleeck@4: % is the octave there? bleeck@4: if oct_fre > (2-octave_variability)*fre && oct_fre < (2+octave_variability)*fre bleeck@4: rpeaks{i}.has_octave=oct_fre; bleeck@4: rpeaks{i}.octave_peak_nr=j; bleeck@4: bleeck@4: % add the pss bleeck@4: % rpeaks{j}.pitchstrength=rpeaks{i}.pitchstrength+rpeaks{j}.pitchstrength; bleeck@4: bleeck@4: ps_real=rpeaks{j}.pitchstrength; bleeck@4: ps_oct=rpeaks{i}.pitchstrength; bleeck@4: hight_oct=rpeaks{j}.y; bleeck@4: hight_real=rpeaks{i}.y; bleeck@4: bleeck@4: % if ps_oct>ps_real && hight_oct > hight_real bleeck@4: % rpeaks{i}.pitchstrength=ps_real-1; % artificially drop down bleeck@4: % end bleeck@4: bleeck@4: has_octave=1; bleeck@4: break bleeck@4: end bleeck@4: if ~has_octave bleeck@4: rpeaks{i}.has_octave=0; bleeck@4: rpeaks{i}.octave_peak_nr=0; bleeck@4: end bleeck@4: end bleeck@4: end bleeck@4: bleeck@4: if plot_switch bleeck@4: figure(2134) bleeck@4: clf bleeck@4: hold on bleeck@4: plot(log_profile,'b') bleeck@4: plot(smooth_sig,'g') bleeck@4: for i=1:length(rpeaks) bleeck@4: time=rpeaks{i}.t; bleeck@4: x=rpeaks{i}.x; bleeck@4: y=rpeaks{i}.y; bleeck@4: plot(x,y,'Marker','o','Markerfacecolor','g','MarkeredgeColor','g','MarkerSize',2); bleeck@4: time_left=rpeaks{i}.left.t; bleeck@4: x_left=rpeaks{i}.left.x; bleeck@4: y_left=rpeaks{i}.left.y; bleeck@4: time_right=rpeaks{i}.right.t; bleeck@4: x_right=rpeaks{i}.right.x; bleeck@4: y_right=rpeaks{i}.right.y; bleeck@4: plot(x_left,y_left,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2); bleeck@4: plot(x_right,y_right,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2); bleeck@4: end bleeck@4: current_time=options.current_time*1000; bleeck@4: y=get(gca,'ylim'); bleeck@4: y=y(2); bleeck@4: text(700,y,sprintf('%3.0f ms',current_time),'verticalalignment','top'); bleeck@4: bleeck@4: for i=1:length(rpeaks) bleeck@4: pitchstrength=rpeaks{i}.pitchstrength; bleeck@4: if i <10 bleeck@4: line([rpeaks{i}.x rpeaks{i}.x],[rpeaks{i}.y rpeaks{i}.peak_base_height_y],'Color','m'); bleeck@4: 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'); bleeck@4: x=rpeaks{i}.x; bleeck@4: fre=rpeaks{i}.fre; bleeck@4: y=rpeaks{i}.y; bleeck@4: text(x,y*1.05,sprintf('%3.0fHz: %2.2f',fre,pitchstrength),'HorizontalAlignment','center'); bleeck@4: end bleeck@4: end bleeck@4: end bleeck@4: if plot_switch==1 bleeck@4: for i=1:length(rpeaks) bleeck@4: x=rpeaks{i}.x; bleeck@4: y=rpeaks{i}.y; bleeck@4: plot(x,y,'Marker','o','Markerfacecolor','g','MarkeredgeColor','g','MarkerSize',6); bleeck@4: bleeck@4: % plot the octaves as green lines bleeck@4: octave=rpeaks{i}.has_octave; bleeck@4: fre=rpeaks{i}.fre; bleeck@4: if octave>0 bleeck@4: oct_nr=rpeaks{i}.octave_peak_nr; bleeck@4: oct_fre=rpeaks{oct_nr}.fre; bleeck@4: bleeck@4: x=rpeaks{i}.x; bleeck@4: oct_x=rpeaks{oct_nr}.x; bleeck@4: y=rpeaks{i}.y; bleeck@4: oct_y=rpeaks{oct_nr}.y; bleeck@4: line([x oct_x],[y oct_y],'Color','g','LineStyle','--'); bleeck@4: end bleeck@4: end bleeck@4: end bleeck@4: bleeck@4: % rpeaks=sortstruct(rpeaks,'pitchstrength'); bleeck@4: rpeaks=sortstruct(rpeaks,'y'); bleeck@4: bleeck@4: % final result for the full set bleeck@4: result.final_pitchstrength=rpeaks{1}.pitchstrength; bleeck@4: result.final_dominant_frequency=rpeaks{1}.fre; bleeck@4: result.final_dominant_time=rpeaks{1}.t; bleeck@4: result.smoothed_signal=smooth_sig; bleeck@4: result.peaks=rpeaks; bleeck@4: bleeck@4: bleeck@4: bleeck@4: bleeck@4: function fre=x2fre(sig,x) bleeck@4: t_log = bin2time(sig,x); bleeck@4: t=f2f(t_log,0,0.035,0.001,0.035,'linlog'); bleeck@4: fre=1/t;