Code covered by the BSD License  

Highlights from
Impulsive Noise Meter

image thumbnail
from Impulsive Noise Meter by Edward Zechmann
Calculates Impulsive noise metrics for hazardous acoustic noise assessent

[SP_local_max2, indices2, SP_peaka, index_peaka, t_SP, gp ]=localpeaks(SP, Fs, num_pts_per_pk_intrl, min_peak, ignore_threshold, Align_peaks, make_plot, peak_alignment_tol)
function [SP_local_max2, indices2, SP_peaka, index_peaka, t_SP, gp ]=localpeaks(SP, Fs, num_pts_per_pk_intrl, min_peak, ignore_threshold, Align_peaks, make_plot, peak_alignment_tol)      
% % localpeaks: Finds impulsive peaks and returns the amplitudes and indices 
% % 
% % Syntax:
% % 
% % [SP_local_max2 indices2, SP_peaka, index_peaka]=localpeaks(SP, Fs,...
% % num_pts_per_pk_intrl, min_peak, ignore_threshold, Align_peaks, make_plot, ...
% % peak_alignment_tol);
% % 
% % ********************************************************************
% % 
% % Description
% % 
% % This progam finds the impulsive peaks and determines whether the
% % impulsive peak criteria are satisfied.
% % 
% % The program can handle large data arrays with multiple channels.
% % 
% % ********************************************************************
% % 
% % Input Variables
% % 
% % SP=randn(4, 100000);  % (Pa) is the Sound pressure data in Pa.  
% %                       % default value is randn(4, 100000).
% % 
% % Fs=100000;      % (Hz) is the sampling rate.  
% %                 % default value is 100000 Hz.  
% % 
% % num_pts_per_pk_intrl=100000;
% %                 % is the number of data points used to idntify a single
% %                 % impulsive peak.  Usually 1 second to 1/2 a
% %                 % second of data points works well. 
% %                 % 
% %                 % default value is 1 second of data points or the 
% %                 % length of the SP whichever is shorter.  
% % 
% % min_peak=100;   % (dB) is the lowest amplitude for a peak to be considered
% %                 % impulsive. 
% %                 % The default value is min_peak=100; %(dB).
% % 
% % ignore_threshold=0; % 1 surpresses the threshold and other requirements
% %                     % for selecting peaks
% %                     % ignore_threshold=1; % generally will find more peaks.
% %                     % 
% %                     % 0 is the default.  Returns typical number of
% %                     % peaks. 
% %                     % 
% %                     % default is ignore_threshold=0;
% % 
% % Align_peaks=1;  % is the channel number for the impulsive peaks to be
% %                 % aligned to.  default value is [];
% %                 % Align_peaks=1;  peaks are aligned to channel 1.  
% %                 % Align_peaks=[]; peaks are not aligned.  
% %                 % 
% %                 % If Align_peaks > num_channels then 
% %                 % Align_peaks is set to [];
% %                 % 
% %                 % If Align_peaks < num_channels then 
% %                 % Align_peaks is set to [];
% %                 % The default value is [];
% % 
% % make_plot=1;    % 1 Plots the processing data of the peaks.  
% %                 % Otherwise no plots are made. 
% %                 % 
% %                 % default is make_plot=0;  
% % 
% % peak_alignment_tol=0.25; 
% %                 % This input sets the fraction of the datapoints 
% %                 % of num_pts_per_pk_intrl that a peak can be offset. 
% %                 % When aligning peaks, the channels are 
% %                 % synchronized, but temorally the peaks may be  
% %                 % misaligned by a few milliseconds.  The 
% %                 % alignment tolerance allows the program to find 
% %                 % the maximum peak within the alignment 
% %                 % tolerance. 
% %                 % 
% %                 % default is peak_alignment_tol=0.25; 
% %
% %
% %                 % Further explanation of peak_alignment_tol
% %
% %                 % One-half of the datapoints of num_pts_per_pk_intrl are 
% %                 % used for finding the index of the maximum sound 
% %                 % pressure amplitude.    
% %             
% %                 % The impulsive peak is found by selecting the highest 
% %                 % sound pressure amplitude starting at the center of 
% %                 % the bin and working toward the maximum radius which 
% %                 % is one-half of the data points for the impulse.  
% %                     
% % ********************************************************************
% % 
% % Output Variables
% %
% % SP_local_max2 is a cell array of peak pressures in Pa for each
% % impulsive peak and for each channel
% %
% % indices2 is the cell arrray of indices for each impulsive peak and for
% % each channel
% % 
% % SP_peaka is the cell array of the peak amplitudes that are greater 
% %     than the threshold and before implementing the min_peak and other 
% %     selection criterion.
% % 
% % index_peaka is the cell array of the indices corresponding to 
% %      SP_peaka. 
% % 
% % ********************************************************************
% %
%
% Example
%
% Fs=100000; fc=1000; td=1; tau=0.01; delay=0.1; A1=5; A2=20;
% [SP, t]=analytic_impulse(Fs, fc, td, tau, delay, A1, A2);
%                   % Pa sound pressure time record
%                   
% Fs=100000;        % Hz sampling rate
% 
% num_pts_per_pk_intrl=50000;    % number of data points used to identify
%                           % a single impulsive peak usually 1 second to 1/2 a
%                           % second of data points works well
% 
% min_peak=100;             % (dB) is the peak value that is the minimum
%                           % for being considered an impulsive noise.
% 
% ignore_threshold=0;       % 1 surpresses the threshold and other requirements
%                           % for selecting peaks
%                           % ignore_threshold=1; % generally will find more peaks.
%                           % 
%                           % 0 is the default.  Returns typical number of
%                           % peaks. 
%                           % 
%                           % default is ignore_threshold=0;
%                           
% Align_peaks=1;            % Specify the channel number to align peaks to
%                           % For the subordinate channels, the highest 
%                           % peak within a radius of 0.25*num_pts_per_pk_intrl
%                           % data points of the impulsive peak of the 
%                           % align_peaks channel is selected. 
%
% make_plot=1;              % 1 for make the plot
%                           % 0 for no plot
%                           % Default is to not make any plots.
%  
% [SP_local_max2 indices2]=localpeaks(SP, Fs, num_pts_per_pk_intrl, min_peak, ignore_threshold, Align_peaks, make_plot);
% 
% % ********************************************************************
% % 
% % 
% % Subprograms
% %
% % 
% % List of Dependent Subprograms for 
% % localpeaks
% % 
% % FEX ID# is the File ID on the Matlab Central File Exchange
% % 
% % 
% % Program Name   Author   FEX ID#
% %  1) convert_double		Edward L. Zechmann			
% %  2) dB_to_Pa		Edward L. Zechmann			
% %  3) estimatenoise		John D'Errico		16683	
% %  4) findjobj		Yair M. Altman		14317	
% %  5) fix_YTick		Edward L. Zechmann			
% %  6) func_threshold		Jing Tian		10462	
% %  7) LMSloc		Alexandros Leontitsis		801	
% %  8) maximize		Oliver Woodford		25471	
% %  9) moving		Aslak Grinsted		8251	
% % 10) Pa_to_dB		Edward L. Zechmann			
% % 11) parseArgs		Malcolm Wood		10670	
% % 12) peak_index		Edward L. Zechmann			
% % 13) peak_ix		Edward L. Zechmann			
% % 14) peak_threshhold_function2		Edward L. Zechmann			
% % 15) peakfinder		Nate Yoder		25500	
% % 16) psuedo_box		Edward L. Zechmann			
% % 17) resample_plot		Edward L. Zechmann			
% % 18) sub_mean		Edward L. Zechmann			
% % 19) subaxis		Aslak Grinsted		3696	
% % 20) wsmooth		Damien Garcia		NA	
% % 
% % 
% %
% % ********************************************************************
% %
% % localpeaks is written by Edward L. Zechmann
% % 
% %     date 10 August     2007
% % 
% % modified 18 December   2007     Improved signal processing methods
% %                                 Improved the empty array handling
% %                                 Added align peaks
% %                                 Added analytic_impulse example
% % 
% % modified 21 December    2007    Improved plotting the peak threshold 
% %                                 function
% %                                 Improved the zero crossing and slope 
% %                                 calculation for removing peaks at teh end
% %                                 of the file
% %                                 Added more comments
% % 
% % modified 27 December    2007    Changed the process of grouping peaks 
% %                                 from marchinig in time to selecting the 
% %                                 highest peak to the lowest peak
% %                                 Fixed pts_per_bin to number of points   
% %                                 in 0.01 seconds
% %                     
% % modified 20 February    2008    Updated comments
% %                              
% % 
% % modified 26 February    2008    Changed the peak_index for the align 
% %                                 peaks to use a radius of 
% %                                 0.25*num_pts_per_pk_intrl data points.  
% %                                 Now the peak circles of the protected 
% %                                 signals are located at the peaks.    
% % 
% % modified 27 February    2008     Made the threshold limit for finding
% %                                 a peak vary with time.  
% %  
% % modified 11 March       2008    The process of selecting detecting 
% %                                 impulsive peaks was greatly improved.  
% % 
% % modified 12 March       2008    Updated Comments
% %                     
% % modified 21 March       2008    Updated Comments
% %                     
% % modified 24 March       2008    Added radius option for
% %                                 selecting the size of the range
% %                                 of data points to find the peak 
% %                                 sound pressure amplitude.  
% % 
% % modified 22 July        2008    Modified Method of finding
% %                                 peaks now uses percentiles.
% %  
% % modified 19 August      2008    Added input variable percent1 
% %                                 to specify threshold for 
% %                                 identifying peaks
% %  
% % modified 10 September   2008    Added optional method for finding 
% %                                 impulsive Exhaust Noise 
% %  
% % modified 11 November    2008    Fixed a bug with the exhaust noise
% %                                 feature and with bin size.  
% % 
% % modified  6 October     2009    Updated comments
% % 
% % modified 11 October     2010    Changed peak finder to peak_ix
% %                                 Updated comments.
% % 
% % modified 11 February    2011    Updated to new method of finding peaks.
% %                                 Updated Comments.
% %
% %  
% % ********************************************************************
% %
% % Please feel free to modify this code.
% % 
% % See Also: Impulsive_Noise_Meter, snd_peak_metrics, plot_peaks
% % 
 

if nargin < 1 || isempty(SP) || ~isnumeric(SP)
    SP=randn(4, 100000);
end

% make sure that input data is double precision.
[SP]=convert_double(SP);

% Make sure the data has the channels and data array in the
% correct order, transpose if necessary.
[m1 n1]=size(SP);

if m1 > n1
    SP=SP';
    [m1 n1]=size(SP);
end

if nargin < 2 || isempty(Fs) || ~isnumeric(Fs)
    Fs=100000;
end

[Fs]=convert_double(Fs);

% number of points in each peak interval
if nargin < 3 || isempty(num_pts_per_pk_intrl) || ~isnumeric(num_pts_per_pk_intrl)
    n1=length(SP);
    if Fs < n1
        num_pts_per_pk_intrl=Fs;
    else
        num_pts_per_pk_intrl=n1;
    end
end

% minimum peak preessure to be an impulsive noise dB
if nargin < 4 || isempty(min_peak) || ~isnumeric(min_peak)
    min_peak=100;
end

% ignore_threshold is suspend absolute peak requirement
% a value of zero will not supress any requirements
if nargin < 5 || isempty(ignore_threshold) || ~isnumeric(ignore_threshold)
    ignore_threshold=0;
end

% minimum peak preessure to be an impulsive noise
if nargin < 6 || isempty(Align_peaks) || ~isnumeric(Align_peaks)
    Align_peaks=[];
end

if ~isempty(Align_peaks)
    Align_peaks=round(Align_peaks);

    if Align_peaks < 1
        Align_peaks=[];
    end

    if Align_peaks > m1
        Align_peaks=[];
    end
end

% make a plot of the bin selection criterion
if nargin < 7 || isempty(make_plot) || ~isnumeric(make_plot)
    make_plot=0;
end
    
% set the peak alignment tolerance
if nargin < 8 || isempty(peak_alignment_tol) || ~isnumeric(peak_alignment_tol)
    peak_alignment_tol=0.25;
end


% Set no_smoothing to 1.
no_smoothing=1;

sh=0.0;
sv=0.0;
ml=0.14;
mr=0.1;
mt=0.08;
mb=0.12;


% pts_per_bin is the number of points in the sub bins for speedings up 
% the process of analyzing the data array.  
% The pts_per_bin is the number of pts in 0.01 seconds  
pts_per_bin=floor(Fs/1000);

if pts_per_bin < 1
    pts_per_bin=1;
end

if pts_per_bin > n1
    pts_per_bin=n1;
end

max_num_bin=floor(n1/pts_per_bin);

% Calculate the number of bins per peak interval 
% 
% Number of points per peak interval divided by
% the number of points in each bin.
bins_per_pk_intvl=floor(num_pts_per_pk_intrl/pts_per_bin);
if bins_per_pk_intvl < 1
    bins_per_pk_intvl=1;
end


% Find the peaks using peak_ix
if isequal(ignore_threshold, 1)
    [indices, gp]=peak_ix(SP, Fs, -inf, 0, 1);
else
    [indices, gp]=peak_ix(SP, Fs, min_peak, 0, no_smoothing);
end

[mm1, num_bins]=size(gp);


% Calculate the number of bins per peak interval
if bins_per_pk_intvl > num_bins
    bins_per_pk_intvl=num_bins;
end

% Calculate the number of peak intervals
num_pk_intrl=max([1, floor(num_bins/bins_per_pk_intvl)]);


pts_per_pk_intrl=floor(n1/num_pk_intrl);

if isequal(make_plot,1)

    % initialize the figure
    figure(10000);
    delete(10000);
    figure(10000);
    ylim1=0.1*max(max(max(ceil(11*SP))));
    xlim1=n1/Fs;
    h2=[];

    tot_num_samples=mm1*num_bins;
    flag_rs=0;
    if tot_num_samples > 1000000
        flag_rs=1;
    end

    t_SP_rs=[];
    SP_rs=[];
    
    
    for e1=1:m1;

        subaxis(m1, 1, e1, 'sh', sh, 'sv', sv , 'pl', 0, 'pr', 0, 'pt', 0, 'pb', 0, 'ml', ml, 'mr', mr, 'mt', mt, 'mb', mb);
        t_SP=n1/num_bins/Fs*(0:(num_bins-1));
        
        if flag_rs == 1
            [t_SP_rs, SP_rs]=resample_plot(t_SP, SP(e1, :));
            plot(t_SP_rs, SP_rs);
        else
            t_SP=1/Fs*(-1+(1:length(SP)));
            plot(t_SP, SP(e1, :));
        end
        
        if isequal(e1, 1)
            title({'', 'Impulsive Noise Detection Routine', 'Processed Signal and Peak Threshold Line'}, 'Fontsize', 18);
            ylabel('Amplitude', 'Fontsize', 18);
        end
        
        h2=[h2 gca];
        set(gca, 'Fontsize', 12, 'box', 'off' );
        
        if e1 ~= m1
            set(gca, 'xtick', [], 'XTickLabel', '');
        end

        text( 'Position', [pts_per_pk_intrl*num_bins*0.95/Fs, 0.95*ylim1], 'String', ['Microphone ', num2str(e1)], 'Fontsize', 20, 'Color', [0 0 0], 'HorizontalAlignment', 'right', 'VerticalAlignment', 'top', 'BackgroundColor', [1 1 1] );

        hold on;
        
        
        % The peaks that are above the threshold are selected
        plot(indices{e1, 1}, SP(e1,indices{e1, 1}), 'linestyle', 'none', 'marker', 'o', 'markeredgecolor', 'k' );

    
        set(gca, 'Fontsize', 16);
        ylim([0 ylim1]);
        xlim([0 xlim1]);
        [ytick_m, YTickLabel1, ytick_good, ytick_new, yticklabel_new]=fix_YTick(0);
        
    end

    xlabel('Time seconds', 'Fontsize', 18);
    %legend('Processed Signal Amplitude', 'Peak Detection Threshold');

    if length(h2) >= 1
        psuedo_box(h2);
    end

end
    


SP_peaka=cell(m1,1);
index_peaka=cell(m1,1);
% The cell array index_peaka contains all peaks above the threshold
% The cell array SP_peaka continas the amplitude of those peaks

% set the radius for finding a peak from the center of a bin.
radius=0.5;

for e1=1:m1;
    [SP_peak, index_peak]=peak_index(abs(SP(e1, :)), floor(indices{e1,1}./pts_per_bin), pts_per_bin, radius*num_pts_per_pk_intrl);
    SP_peaka{e1, 1}=SP_peak;
    index_peaka{e1, 1}=index_peak;
end

min_peak_Pa=dB_to_Pa(min_peak);

% Enforce the min_peak requirement
% index_peaka now only includes peaks above the min_peak amplitude (Pa)
if ~isequal(ignore_threshold, 1)
    for e1=1:m1;
        index1=find(abs(SP_peaka{e1, 1}) > min_peak_Pa);
        SP_peaka{e1, 1}=SP_peaka{e1, 1}(index1);
        index_peaka{e1, 1}=index_peaka{e1, 1}(index1);
    end
end

%SP_local_max=[];
%SP_local_max2={};

low_bin=floor(0.25*num_pts_per_pk_intrl);
high_bin=floor(num_pts_per_pk_intrl-low_bin);

index1=0;
index2=0;

% Align_peaks is a channel number that the peaks are aligned to.  
% 
% align_chans is an array of channels to be aligned to the channel 
% designated by Align_peaks.
% 
if ~isempty(Align_peaks)
    align_chans=setdiff(1:m1, Align_peaks);
else
    align_chans=[];
end

indices2=cell(m1,1);
SP_local_max=[];
SP_local_max2=cell(m1,1);


for e1=1:m1;

    if isempty(Align_peaks)
        e2=e1;
    else
        if isequal(e1,1)
            e2=Align_peaks;
        else
            e2=align_chans(e1-1);
        end
    end
    
    % whether or not to find all of the peaks
    if isempty(Align_peaks) || isequal(e1,1)
        
        % Get the index of the maximum peak 
        % first get teh indices of all of the peaks for the alignment
        % channel or channel 1 
        ix_peak=index_peaka{e2, 1};
        SP_peak=abs(SP_peaka{e2, 1});
        
        % initialize the vector of major peak indices
        major_peak_ix=[];
        
        % Starting with the highest amplitude peak, one by one identify  
        % each peak and discard all other peaks within the radius
        % of the peak.  
        %
        % Each peak has a set number of points before and 
        % after the peak which belong to that peak and only that peak.   
        % 
        while length(ix_peak) >= 1
            
            % get the index of the peak with the greatest amplitude.
            [val, ix]=max(SP_peak);
            cix=ix_peak(ix);

            % Get all of the indices within the umbrella of the maximum peak
            index1=cix-low_bin;
            index2=cix+high_bin;

            if index1 < 1
                index1=1;
                index2=index1+low_bin+high_bin;
            end

            if index2 > n1
                index2=n1;
            end

            % minor_peaks_ix are the indices within the umbrella of the
            % minor local peaks 
            gti1=find(ix_peak >= index1);
            lti2=find(ix_peak <= index2);
            minor_peaks_ix=intersect( gti1, lti2);
            not_m_peaks=setdiff(1:length(ix_peak), minor_peaks_ix);
            ix_peak=ix_peak(not_m_peaks);
            SP_peak=SP_peak(not_m_peaks);

            % Make sure each peak has a zero crossing after the peak
            % find the zero crossing after the peak
            flag1=0;
            e4=cix;
            if SP(cix) < 0
                SP2=-SP;
            else
                SP2=SP;
            end
            
            while (flag1 == 0) && (e4 < n1)
                e4 = e4+1;
                if SP2(e4) <= 0
                    flag1=1;
                end
            end

            % check for zero crossing after max peak
            % interpolate the zero crossing
            % calculate the slope
            %if abs(SP2(e4)-SP2(e4-1)) >= 10^(-12)
            %    at2 = (0-SP2(e4-1))/(SP2(e4)-SP2(e4-1))+e4-1;
            %    m=SP2(e4)-SP2(e4-1);
            %else
            %    m=0;
            %    at2=e4;
            %end
            %
            % There must be a zero crossing with a negative
            % slope for the peak to be accepted.
            %if (at2 <= n1) && m <= 0
                major_peak_ix=[major_peak_ix cix];
            %end
        end
        
        % sort the indices 
        [sorted_mp_ix]=sort(major_peak_ix);
        
        % sorted_mp_ix is the sorted major peak indices
        % sorted_mp_ix will be apended to the cell array (indices2)
        % located after the conclusion of this conditional statemnet 
        
        % Prepare to append the peak amplitudes to the peak amplitude
        % cell array 
        SP_local_max=SP(e2, sorted_mp_ix);
        
    else
        % This code is for the case where the peaks in channel e2 must
        % be aligned to the peaks in channel Align_peaks.  
        % 
        % Determine the best Alignment of peak indices for the
        % microphone channel (e2) using the peak indices that 
        % were found for the Align_peaks channel.  
        % 
        % All of the impulsive peak indices for channel e2 were
        % previously found.  
        % 
        % Starting with the highest peak from channel Align_peaks the 
        % corresponding peak in channel e2 will be determined.  
        % 
        % The radius of points in channel e2 will be determined by pts_per_bin
        % then the the number of points will be reduced to 
        % PNTS=peak_alignment_tol*num_pts_per_pk_intrl.  The highest peak within the
        % PNTS of the Align_peaks index.  
        % 
        % points of the indices from the aling peaks channel.  
        % 
        % for this bin for this microphone channel
        % using the bins for the Align_peaks microphone
        % 
        indices1=ceil(indices2{Align_peaks}/pts_per_bin);
        indices1(indices1 < 1)=1;
        indices1(indices1 > max_num_bin)=max_num_bin;
        
        % Choose data points for the center of each local peak impulse
        % The peak_index program uses indices rounded to the pts_per_bin,
        % determines the appropriate bin, then finds the peak index.
        
        [SP_maxa, index_maxa]=peak_index(SP(e2, :), indices1, pts_per_bin, peak_alignment_tol*num_pts_per_pk_intrl);
        
        % sort the indices 
        if ~isempty(index_maxa) 
            [sorted_mp_ix]=sort(index_maxa);
            SP_local_max=SP(e2, sorted_mp_ix);
        else
            SP_local_max=[];
        end
        
    end

    SP_local_max2{e2, 1}=SP_local_max;
    indices2{e2, 1}=shiftdim(sorted_mp_ix);

end

Contact us at files@mathworks.com