view 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
line wrap: on
line source
% function [pitchstrength, dominant_time] = find_pitches(profile, , a_priori, fqp_fq)
%
%   To analyse the time interval profile of the auditory image
%
%   INPUT VALUES:
%  
%   RETURN VALUE:
%

% (c) 2011, University of Southampton
% Maintained by Stefan Bleeck (bleeck@gmail.com)
% download of current version is on the soundsoftware site: 
% http://code.soundsoftware.ac.uk/projects/aimmat
% documentation and everything is on http://www.acousticscale.org

function result = find_pitches(profile,options)
% different ways to define the pitch strength:
% 1: the absolute height of the highest peak
% 2: ratio between peak hight and width devided at base
% % % % 2: the ration of the highest peak divided by the width at a certain point (given
% % % %     by the parameter height_to_width_ratio
% 3: the height of the highest peak divided by the hight of the peak just one to 
%     the right. This measurement is very successfull in the ramped/damped stimuli
% 
% 4: Further we want to know all these values at a fixed point called target_frequency
%     and in the range given by allowed_frequency_deviation in %
%     
% 5: We are also interested in the frequency value of the highest peak, because
%     we hope, that this is finally the pitch.
%     
% 6: for the dual profile model, we also give back two more values concerning similar
%     properties for the spectral profile. Here, the pitch strenght is defined as the 
%     height of the highest peak divided by the range that is given in two parameters 
%     (usually 20% to 80% of the maximum)


plot_switch =0;

if nargin < 2
    options=[];
end
% 

% peaks must be higher then this of the maximum to be recognised
ps_threshold=0.1;   
height_width_ratio=options.ps_options.height_width_ratio;	% height of peak, where the width is measured


% preliminary return values.
% height of the highest peak
% result.free.highest_peak_hight=0;
% result.free.highest_peak_frequency=0;
% hight to width ratio
% result.free.height_width_ratio=0;
% highest peak divided by next highest
% result.free.neigbouring_ratio=0;

% now all these at a fixed frequency:
% % result.fixed.highest_peak_hight=0;
% result.fixed.highest_peak_frequency=0;
% result.fixed.height_width_ratio=0;
% result.fixed.neigbouring_ratio=0;
% 
% % other things useful for plotting
% result.smoothed_signal=[];
% result.peaks = [];


% now start the show

% % change the scaling to logarithm, before doing anything else:
% log_profile=logsigx(profile,0.001,0.035);
% result.smoothed_signal=log_profile;

% don't do this change
log_profile=profile;

current_lowpass_frequency=options.ps_options.low_pass_frequency;
smooth_sig=lowpass(log_profile,current_lowpass_frequency);
envpeaks = PeakPicker(smooth_sig);
result.smoothed_signal=smooth_sig;

if isempty(envpeaks) % only, when there is no signal
    return
end

% reject impossible peaks
ep=envpeaks;ep2=[];c=1;
for i=1:length(envpeaks);
    if envpeaks{i}.t>0.002 && envpeaks{i}.t<0.03 && envpeaks{i}.y>0.01
        ep2{c}=ep{i};
        c=c+1;
    end
end
envpeaks=ep2; % replace
if isempty(envpeaks) % only, when there is no signal
    return
end
%
% % translate times back to times:
% for i=1:length(envpeaks) % construct all maxima
%     envpeaks{i}.t=1/x2fre(smooth_sig,envpeaks{i}.x);
% end


% nr1: highest peak value
% find the highest peak and its frequency
% sort all for the highest first!
% envpeaks=sortstruct(envpeaks,'y');
% result.free.highest_peak_frequency=1/envpeaks{1}.t;
% result.free.highest_peak_hight=envpeaks{1}.y;



% SB 08.2012: adjusted the method to make it simpler for Daniels signals of
% IRN
% nr 2: height to width of each peak. Height=height of peak. Width = width
% of the two adjacent minima
for i=1:length(envpeaks) % construct all maxima
    where=envpeaks{i}.t;
    hp=envpeaks{i}.y; % height peak
    hb=(envpeaks{i}.left.y+envpeaks{i}.right.y)/2;% base peak
    diffheight=hp-hb;
    w=log(envpeaks{i}.right.t)-log(envpeaks{i}.left.t); % width at base
    if w>0 && diffheight>0.02;
        envpeaks{i}.v2012_height_base_width_ratio=diffheight/w;
    else
        envpeaks{i}.v2012_height_base_width_ratio=0;
    end
    envpeaks{i}.v2012_base_width=w;
    envpeaks{i}.v2012_base_where_widths=hb; %base height
end

envpeaks=sortstruct(envpeaks,'v2012_height_base_width_ratio');

if plot_switch
    figure(2134)
    clf
    hold on
    plot(log_profile,'r');
    plot(smooth_sig,'b')
    for i=1:min(5,length(envpeaks))
%         time=envpeaks{i}.t;
%         x=envpeaks{i}.x;
%         y=envpeaks{i}.y;
%         plot(time,y,'Marker','o','Markerfacecolor','g','MarkeredgeColor','g','MarkerSize',2);
%         time_left=envpeaks{i}.left.t;
% %         x_left=envpeaks{i}.left.x;
%         y_left=envpeaks{i}.left.y;
%         time_right=envpeaks{i}.right.t;
% %         x_right=envpeaks{i}.right.x;
%         y_right=envpeaks{i}.right.y;
%         plot(time_left,y_left,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2);
%         plot(time_right,y_right,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2);
        
		t=envpeaks{i}.t;
		ypeak=envpeaks{i}.y;
% 		ps=peaks{ii}.pitchstrength;
		ps=envpeaks{i}.v2012_height_base_width_ratio;
        
		if i==1
			plot(t,ypeak,'Marker','o','Markerfacecolor','b','MarkeredgeColor','b','MarkerSize',10);
 			text(t,ypeak*1.05,sprintf('%3.0f Hz: %4.2f ',1/t,ps),'VerticalAlignment','bottom','HorizontalAlignment','center','color','b','Fontsize',12);
		else
			plot(t,ypeak,'Marker','o','Markerfacecolor','g','MarkeredgeColor','w','MarkerSize',5);
			text(t,ypeak*1.05,sprintf('%3.0f Hz: %4.2f ',1/t,ps),'VerticalAlignment','bottom','HorizontalAlignment','center','color','g','Fontsize',12);
        end
        plot(envpeaks{i}.left.t,envpeaks{i}.left.y,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',5);
        plot(envpeaks{i}.right.t,envpeaks{i}.right.y,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',5);
        
        
        ybase=envpeaks{i}.v2012_base_where_widths;
		line([t t],[ybase ypeak],'color','m');
		line([envpeaks{i}.left.t envpeaks{i}.right.t],[ybase ybase],'color','m');
        
    end
    
%          set(gca,'xscale','log')
    set(gca,'xlim',[0.001 0.03])
    
    fres=[500 300 200 150 100 70 50 20];
    set(gca,'xtick',1./fres);
    set(gca,'xticklabel',fres);
    xlabel('Frequency (Hz)')
    ylabel('arbitrary normalized units')
    
%     current_time=options.current_time*1000;
%     y=get(gca,'ylim');
%     y=y(2);
%     text(700,y,sprintf('%3.0f ms',current_time),'verticalalignment','top');
    
%     for i=1:length(envpeaks)
%         height_width_ratio=envpeaks{i}.height_width_ratio;
%         if i <4
%             line([envpeaks{i}.t envpeaks{i}.x],[envpeaks{i}.y envpeaks{i}.y*(1-height_width_ratio)],'Color','r');
%             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');
%             x=envpeaks{i}.t;
%             fre=1/envpeaks{i}.t;
%             y=envpeaks{i}.y;
%             text(x,y*1.05,sprintf('%3.0fHz: %2.2f',fre,height_width_ratio),'HorizontalAlignment','center');
%         end
%     end
end


% and return the final result, only highest peak
peaks2=sortstruct(envpeaks,'v2012_height_base_width_ratio');
result.free.ps=peaks2{1}.v2012_height_base_width_ratio;
result.free.fre=1/peaks2{1}.t;



% 
% 
% % nr 2: height to width of highest peak
% for i=1:length(envpeaks) % construct all maxima
% %     where=bin2time(smooth_sig,envpeaks{i}.x);
%     where=envpeaks{i}.t;
%     [~,height,breit,where_widths]=qvalue(smooth_sig,where,height_width_ratio);
%     width=time2bin(smooth_sig,breit);
%     if width>0
%         envpeaks{i}.height_width_ratio=height/width;
%     else
%         envpeaks{i}.height_width_ratio=0;
%     end
%     envpeaks{i}.width=width;
%     envpeaks{i}.where_widths=where_widths;
%     envpeaks{i}.peak_base_height_y=height*(1-height_width_ratio);
% end
% % and return the results
% % result.free.height_width_ratio=envpeaks{1}.height_width_ratio;

% 
% % nr 3: height of highest / right neigbour (right when time is towards
% % left, sorry)
% for i=1:length(envpeaks) % construct all maxima
%     left=envpeaks{i}.left;
%     if isfield(left,'y') && left.y>0
%         envpeaks{i}.neigbouring_ratio=result.free.highest_peak_hight/left.y;
%     else
%         envpeaks{i}.neigbouring_ratio=0;
%     end
% end
% result.free.neigbouring_ratio=envpeaks{1}.neigbouring_ratio;


target_frequency=options.ps_options.target_frequency;
% now find all values for the fixed pitch strengh in target_frequency
if target_frequency>0 % only, when wanted
    min_fre=target_frequency/options.ps_options.allowed_frequency_deviation;
    max_fre=target_frequency*options.ps_options.allowed_frequency_deviation;
    
    for i=1:length(envpeaks) % look through all peaks, which one we need
        fre_peak=1/envpeaks{i}.t;
        if fre_peak > min_fre && fre_peak < max_fre
            % we assume for the moment, that we only have one allowed here
            % nr 1: height
            result.fixed.highest_peak_frequency=fre_peak;
            result.fixed.highest_peak_hight=envpeaks{i}.y;
            result.fixed.height_width_ratio=envpeaks{i}.height_width_ratio;
            result.fixed.neigbouring_ratio=envpeaks{i}.neigbouring_ratio;
        end
    end
end

result.peaks =envpeaks;



return





% kucke, ob sich das erste Maxima überlappt. Falls ja, nochmal
% berechnen mit niedriger Lowpass frequenz
% nr_peaks=length(envpeaks);
% 	if 	nr_peaks==1
% 		peak_found=1;
% 		continue
% 	end
% 	xleft=envpeaks{1}.where_widths(1);
% 	xright=envpeaks{1}.where_widths(2);
% 	for i=2:nr_peaks %
% 		xnull=envpeaks{i}.x;
% 		if xnull < xleft  && xnull > xright
% 			peak_found=0;
% 			current_lowpass_frequency=current_lowpass_frequency/2;
% 			if current_lowpass_frequency<62.5
% 				return
% 			end
% 			break
% 		end
% 		% wenn noch hier, dann ist alles ok
% 		peak_found=1;
% 	end
% end


% reduce the peaks to the relevant ones:
% through out all with pitchstrength smaller then threshold
% count=1;
% min_ps=ps_threshold*envpeaks{1}.pitchstrength;
% for i=1:length(envpeaks)
%     if envpeaks{i}.pitchstrength>min_ps
%         rpeaks{count}=envpeaks{i};
%         count=count+1;
%     end
% end


% % final result for the full set
% result.final_pitchstrength=rpeaks{1}.pitchstrength;
% result.final_dominant_frequency=rpeaks{1}.fre;
% result.final_dominant_time=rpeaks{1}.t;
% result.smoothed_signal=smooth_sig;
% result.peaks=rpeaks;
% % return

% Neuberechnung der Pitchstrength für peaks, die das Kriterium der 
% Höhe zu Breite nicht erfüllen
% for i=1:length(rpeaks) % construct all maxima
%     where=bin2time(smooth_sig,rpeaks{i}.x);
%     [dummy,height,breit,where_widths]=qvalue(smooth_sig,where,heighttowidthminimum);
%     width=time2bin(smooth_sig,breit);
%     
%     xleft=where_widths(2);
%     xright=where_widths(1);
%     left_peak=rpeaks{i}.left;
%     right_peak=rpeaks{i}.right;
%     
%     
%     xnull=rpeaks{i}.x;
%     if xleft<left_peak.x || xright>right_peak.x
%         t_xnull=bin2time(smooth_sig,xnull);
%         [val,height,breit,widthvals,base_peak_y]=qvalue2(smooth_sig,t_xnull);
%         width=time2bin(smooth_sig,breit);
%         if width>0
%             rpeaks{i}.pitchstrength=height/width;
%         else
%             rpeaks{i}.pitchstrength=0;
%         end
%         rpeaks{i}.where_widths=time2bin(smooth_sig,widthvals);
%         rpeaks{i}.width=width;
%         rpeaks{i}.peak_base_height_y=base_peak_y;
%     end
% end

% sort again all for the highest first!
% rpeaks=sortstruct(rpeaks,'pitchstrength');

return








%%%%%%  look for octave relationships
% 
% 
for i=1:length(rpeaks) % construct all maxima
    % look, if the octave of the pitch is also present.
    fre=rpeaks{i}.fre;
    has_octave=0;
    for j=1:length(rpeaks)
        oct_fre=rpeaks{j}.fre;
        % is the octave there?
        if oct_fre > (2-octave_variability)*fre && oct_fre < (2+octave_variability)*fre
            rpeaks{i}.has_octave=oct_fre;
            rpeaks{i}.octave_peak_nr=j;
            
            % add the pss
            % 			rpeaks{j}.pitchstrength=rpeaks{i}.pitchstrength+rpeaks{j}.pitchstrength;
            
            ps_real=rpeaks{j}.pitchstrength;
            ps_oct=rpeaks{i}.pitchstrength;
            hight_oct=rpeaks{j}.y;
            hight_real=rpeaks{i}.y;
            
            % 			if ps_oct>ps_real && hight_oct > hight_real
            % 				rpeaks{i}.pitchstrength=ps_real-1;	% artificially drop down
            % 			end
            
            has_octave=1;
            break
        end
        if ~has_octave
            rpeaks{i}.has_octave=0;
            rpeaks{i}.octave_peak_nr=0;
        end
    end
end

if plot_switch
    figure(2134)
    clf
    hold on
    plot(log_profile,'b')
    plot(smooth_sig,'g')
    for i=1:length(rpeaks)
        time=rpeaks{i}.t;
        x=rpeaks{i}.x;
        y=rpeaks{i}.y;
        plot(x,y,'Marker','o','Markerfacecolor','g','MarkeredgeColor','g','MarkerSize',2);
        time_left=rpeaks{i}.left.t;
        x_left=rpeaks{i}.left.x;
        y_left=rpeaks{i}.left.y;
        time_right=rpeaks{i}.right.t;
        x_right=rpeaks{i}.right.x;
        y_right=rpeaks{i}.right.y;
        plot(x_left,y_left,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2);
        plot(x_right,y_right,'Marker','o','Markerfacecolor','r','MarkeredgeColor','r','MarkerSize',2);
    end
    current_time=options.current_time*1000;
    y=get(gca,'ylim');
    y=y(2);
    text(700,y,sprintf('%3.0f ms',current_time),'verticalalignment','top');
    
    for i=1:length(rpeaks)
        pitchstrength=rpeaks{i}.pitchstrength;
        if i <10
            line([rpeaks{i}.x rpeaks{i}.x],[rpeaks{i}.y rpeaks{i}.peak_base_height_y],'Color','m');
            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');
            x=rpeaks{i}.x;
            fre=rpeaks{i}.fre;
            y=rpeaks{i}.y;
            text(x,y*1.05,sprintf('%3.0fHz: %2.2f',fre,pitchstrength),'HorizontalAlignment','center');
        end
    end
end
if plot_switch==1
    for i=1:length(rpeaks)
        x=rpeaks{i}.x;
        y=rpeaks{i}.y;
        plot(x,y,'Marker','o','Markerfacecolor','g','MarkeredgeColor','g','MarkerSize',6);
        
        % plot the octaves as green lines
        octave=rpeaks{i}.has_octave;
        fre=rpeaks{i}.fre;
        if octave>0
            oct_nr=rpeaks{i}.octave_peak_nr;
            oct_fre=rpeaks{oct_nr}.fre;
            
            x=rpeaks{i}.x;
            oct_x=rpeaks{oct_nr}.x;
            y=rpeaks{i}.y;
            oct_y=rpeaks{oct_nr}.y;
            line([x oct_x],[y oct_y],'Color','g','LineStyle','--');
        end
    end
end

% rpeaks=sortstruct(rpeaks,'pitchstrength');
rpeaks=sortstruct(rpeaks,'y');

% final result for the full set
result.final_pitchstrength=rpeaks{1}.pitchstrength;
result.final_dominant_frequency=rpeaks{1}.fre;
result.final_dominant_time=rpeaks{1}.t;
result.smoothed_signal=smooth_sig;
result.peaks=rpeaks;




function fre=x2fre(sig,x)
t_log = bin2time(sig,x);
t=f2f(t_log,0,0.035,0.001,0.035,'linlog');
fre=1/t;