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

[b, pp, sf, Lpt2, Lpt1, Baseline]=B_mil_1474D_duration(p, Fs, flag, make_plot)
function   [b, pp, sf, Lpt2, Lpt1, Baseline]=B_mil_1474D_duration(p, Fs, flag, make_plot)
% % B_mil_1474D_duration: Calculates the B-duration according to MIL-STD-1474D Requirement 4.
% %
% % Syntax:  
% % 
% % [b, pp, sf, Lpt2, Lpt1]=B_mil_1474D_duration(p, Fs, flag, make_plot);
% %
% % ********************************************************************
% %
% % Description
% %
% % This program calculates the B-duration for impulsive noise analysis
% %
% % Reference: mil standard 1474D pages 43-4712 February 1997
% %
% % ********************************************************************
% %
% % Input variables
% %
% % p=randn(1, 10000)   % Sound pressure time record in Pa for a single channel data array
% %                     % the default value is randn(1, 50000);
% %
% % Fs=100000;  % Sampling rate in Hz.  
% %             % default value is 100000 Hz.
% %
% % flag=1;     % Multiplies the time record p by -1 to correct for the 
% %             % voltage inversion of polarized microphones.  
% %             % 0 does not alter the time record, p. 
% %             % default value is flag=0;
% % 
% % make_plot=1;    % 1 Plots the processing data of the peaks.  
% %                 % Otherwise no plots are made. 
% %                 % 
% %                 % default is make_plot=0;  
% %
% %
% % ********************************************************************
% %
% % Output variables
% %
% % b is the estimated B-duration in seconds. 
% % 
% % pp is the primary portion of the durationin seconds.
% % 
% % sf is the duration secondary fluctuationsin seconds.
% % 
% % Lpt2 is the index of the first decent below Lplus after the global 
% %      positive peak.
% % 
% % Lpt1 is the index of the first rise above Lplus before the global 
% %      positive peak.
% % 
% % 
% % ********************************************************************
% 
% 
% 
% Example='1';
%
% % Example impulsive data with high background noise
% % The Impulse does not exceed the background noise enough to limit the
% % duration
% 
% Fs=50000; fc=200; td=1; tau=0.1; delay=0.1; A1=3; A2=20;
% [p, t]=analytic_impulse(Fs, fc, td, tau, delay, A1, A2);
%
% flag=0;           % do not invert the p time record
% make_plot=1;      % plot the simulation
%
% [b, pp, sf]=B_mil_1474D_duration(p, Fs, flag, make_plot);
%
% 
% 
% Example='2';
%
% % Example impulsive data with low background noise
% % The Impulse does not exceed the background noise enough to limit the
% % duration
% 
% Fs=50000; fc=200; td=1; tau=0.1; delay=0.1; A1=0.1; A2=20;
% [p, t]=analytic_impulse(Fs, fc, td, tau, delay, A1, A2);
%
% flag=0;           % do not invert the p time record
% make_plot=1;      % plot the simulation
%
% [b, pp, sf]=B_mil_1474D_duration(p, Fs, flag, make_plot);
%
% 
% Example='3';
%
% % Example impulsive data with low background noise
% % The impulse is shorter with subsequent flucuating random noise.
% 
% Fs=50000; fc=200; td=0.3; tau=0.01; delay=0.1; A1=0.1; A2=20;
% [p, t]=analytic_impulse(Fs, fc, td, tau, delay, A1, A2);
%
% flag=0;           % do not invert the p time record
% make_plot=1;      % plot the simulation
% p=[p randn(1, 100) 0.5*randn(1, 1000) 2*randn(1, 100) 0.5*randn(1, 1000) randn(1, 100) 0.1*randn(1, 20000)];
% [b, pp, sf]=B_mil_1474D_duration(p, Fs, flag, make_plot);
%
%
% 
% Example='4';
%
% % Example impulsive data with low background noise
% % The impulse is shorter with subsequent flucuating random noise.
% 
% Fs=50000; fc=2000; td=0.3; tau=0.01; delay=0.1; A1=0.1; A2=20;
% [p, t]=analytic_impulse(Fs, fc, td, tau, delay, A1, A2);
%
% flag=0;           % do not invert the p time record
% make_plot=1;      % plot the simulation
% p=[p randn(1, 10000) 0.5*randn(1, 1000) 2*randn(1, 100) 0.5*randn(1, 1000) randn(1, 100) 0.1*randn(1, 20000)];
% p(6500)=4;
% [b, pp, sf]=B_mil_1474D_duration(p, Fs, flag, make_plot);
% 
% 
% 
% Example='5';
%
% % Example single impulse data with low background noise
% % The impulse has a very long a-duration with no 
% % subsequent flucuating random noise.
% 
% Fs=50000; fc=200; td=0.3; tau=0.001; delay=0.1; A1=0.1; A2=20;
% [p, t]=analytic_impulse(Fs, fc, td, tau, delay, A1, A2);
%
% flag=0;           % do not invert the p time record
% make_plot=1;      % plot the simulation
%
% [b, pp, sf]=B_mil_1474D_duration(p, Fs, flag, make_plot);
% 
% 
% 
% % ********************************************************************
% % 
% % References: 
% %            
% %            Mil Standard 1474D, DEPARTMENT OF DEFENSE
% %            DESIGN CRITERIA STANDARDm, NOISE LIMITS, 12 February 1997
% %            www.silencertests.com/docs/mil-std-1474d.pdf 
% %            
% %            Guido F. Smoorenburg, "Damage Risk Criteria for Impulsive
% %            Noise," New Perspectives on Noise Induced Hearing Loss, 
% %            Raven Press, New York, pages(471-490) 1982
% % 
% % 
% % ********************************************************************
% %
% % Sub Programs
% % 
% % 
% % List of Dependent Subprograms for 
% % B_mil_1474D_duration
% % 
% % 
% % Program Name   Author   FEX ID#
% % 1) A_duration		
% % 2) B_Duration_second_flucts		
% % 3) convert_double		
% % 4) sub_mean	
% %
% %
% % ********************************************************************
% %
% %
% % B_mil_1474D_duration was written by Edward L. Zechmann
% %
% %     date 22 January     2009    Modified from code from William Murphy
% %
% % modified 31 January     2009    Added plotting of B-duration
% %
% % modified  2 February    2009    Debugged the A_duration
% %
% % modified  8 October     2010    Removed sub_mean2. sub_mean2 was 
% %                                 subtracting the running average.
% %                                 
% %
% % ********************************************************************
% %
% % Please feel free to modify this code.
% %
% % See also: A_Duration, B_Duration, B_mil_1474D_duration, C_Duration, D_Duration
% %

if (nargin < 1 || isempty(p)) || ~isnumeric(p)
    p=randn(1, 50000);
end

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

if (nargin < 3 || isempty(flag)) || ~isnumeric(flag)
    flag=0;
end

if (nargin < 4 || isempty(make_plot)) || ~isnumeric(make_plot)
    make_plot=0;
end

% Make sure that p is a positive pressure corrected for polarization
% effects
if ~isequal(flag, 0)
    p=-p;
end

[p]=convert_double(p);

[m1 n1]=size(p);

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

% make sure p has only one channel
p=p(1, :);


% Find the positive global peak value
[pmax pos_gl_pk_ix] = max(p);

% Find the negative global peak value
[pmin neg_ix] = min(p);


% Calculate the A-duration
[A, at2, at1]=A_duration(p, Fs, 0);

JA=floor(Fs*A);
Jat2=ceil(Fs*at2);
Jat1=floor(Fs*at1);





% ***********************************************************************
%
% Find the Baseline
%

% Bplus is 5 percent of the difference between the positive and negative
% global peak levels.
Bplus = 0.05*abs(pmax-pmin);

% Calculate number of points in 5 milliseconds of time record
num_pts_5ms = floor(0.005*Fs);

% Calculate number of points in 2 milliseconds of time record
num_pts_2ms = floor(0.002*Fs);

% Caculate the maximum number of steps marching backwards with a 5 ms
% time interval using a 2 ms step
max_iterations=floor((pos_gl_pk_ix-num_pts_5ms)/num_pts_2ms);



if max_iterations < 1
    % not enough pretrigger data to calculate a baseline
    Baseline=0;
else

    % initilize control variables
    e1=0;
    flag3=1;

    % March backward in time using 2 millisecond steps
    % until the baseline is found or the program runs
    % out of data points.
    %
    % This ensures that the 5 ms baseline interval does not precede the
    % first excursion above L+ or below L- by more than 2 ms.
    while (e1 < max_iterations) && isequal(flag3, 1)

        e1=e1+1;
        % ll is the lower limit
        ll=pos_gl_pk_ix-num_pts_5ms-(e1-1)*num_pts_2ms;

        % ul is the upper limit
        ul=pos_gl_pk_ix-(e1-1)*num_pts_2ms;

        if ll < 1
            ll=1;
            flag3=0;
        end

        % p5ms is the time record of the 5 ms baseline interval
        p5ms=p(1, ll:ul);

        % Find the positive local peak value
        [pmax_lo pos_lo_pk_ix] = max(p5ms);

        % Find the negative local peak value
        [pmin_lo neg_lo_pk_ix] = min(p5ms);

        Baseline=mean(p5ms);

        if ((abs(pmax_lo-Baseline) < Bplus) &&  (logical(abs(pmin_lo+Baseline) < Bplus))) || isequal(flag3, 0)
            flag3=0;
            Baseline=mean(p5ms);
        end

    end
end


% Lplus is 20 dB below the positive global peak level
Lplus = pmax*0.1;

% Lplus is 20 dB below the positive global peak level
Lminus = -Lplus + Baseline;



% Find the point before first excursion above L+ before the 
% positive global peak pressure

e1=find(p(1:pos_gl_pk_ix) > Lplus, 1)-1;

if e1 < 1
    e1=1;
end

% Interpolate to find better Lpt1 index.
%
% Lpt1 is the index of the last excursion above L+ before the positive
% global peak pressure.
if abs(p(e1)-p(e1+1)) >= 10^-12
    Lpt1 = (Lplus-p(e1))/(p(e1+1)-p(e1))+e1;
else
    Lpt1=e1;
end


% Find the first point after positive global peak pressure below L+ 
% 

bigend=max([Jat2, length(p)-pos_gl_pk_ix]);

if bigend > length(p)
    bigend=length(p);
end

if pos_gl_pk_ix > length(p)
    pos_gl_pk_ix=length(p);
    bigend=length(p);
end

e1=pos_gl_pk_ix-1+find(p(pos_gl_pk_ix:bigend) < Lplus, 1);

if e1 > n1-1
    e1=n1-1;
end

Lpt22=e1;

% Interpolate to find better Lpt2 index.
%
% Lpt2 is the index of the first excursion below L+ after the positive
% global peak pressure.
if abs(p(e1)-p(e1+1)) >= 10^-12
    Lpt2 = -(Lplus-p(e1))/(p(e1-1)-p(e1))+e1;
else
    Lpt2=e1;
end



% Calculate T1
N=5;
T1=N*A;

% Make sure that T1 is less than 30 ms
if T1 > 0.030
    T1=0.030;
end

% Update the number of data points
t1=floor(Fs*T1);

% **********************************************************************
% 
% Locate Point P
%

% Select all data points after the first crosing of Lplus after the 
% global maximum peak 

buf=p( (Lpt22+1):end);

% Find the points outside the inteval Lplus to Lminus
buf2=find( buf > Lplus);
buf22=find(buf < Lminus);
buf2=union(buf2, buf22);

% Determine if there are any intervals of duration T1 which remain with the 
% range Lplus to Lminus.

% Initialize the flag and Point P and the primary portion
flag4=0;
pp=0;

if length(buf2) > 1
    
    % Determine the lengths of the intervals between data points that 
    % are outside the range Lplus to Lminus
    buf3=diff(buf2);

    % Find the intervals greater than length t1.
    ints_gt_t1=find(buf3 > t1, 1);

    % Determine the first point of the interval.
    if ~isempty(ints_gt_t1)
        P=Lpt22+buf2(ints_gt_t1(1));
    else
        % no intervals can be found
        % Return the last point above Lplus or below Lminus as the B-duration
        
        P=Lpt22+buf2(end);
        pp=1/Fs*(P-Lpt1);
        flag4=1;
    end
    
    while (P-Lpt22 < t1) && ~isempty(ints_gt_t1) && logical(ints_gt_t1(1) < t1) && logical(N > 1)

        % Calculate T1
        N=N-1;
        T1=N*A;

        % Make sure that T1 is less than 30 ms
        if T1 > 0.030
            T1=0.030;
        end

        % Update the number of data points
        t1=floor(Fs*T1);
        
        % Find the first interval larger than t1
        ints_gt_t1=find(buf3 > t1, 1);
        
        % Determine the first point of the interval.
        if ~isempty(ints_gt_t1)
            P=Lpt22+buf2(ints_gt_t1);
        end
        
    end
    
else
    % no intervals can be found
    % Return the end of array p as the B-duration
    P=Lpt22;
    pp=1/Fs*(P-Lpt1);
    
end


flag5=0;
flag6=0;
Q=P;
sf=0;


if isequal(flag4, 0)

    % Quantity, T is defined as
    T=1/Fs*(P-Lpt1);

    R=0.3*T;
    tr1=Fs*R;

    % The primary portion, pp is defined as
    if R <= T1
        pp=T;
    else
        
        % Select all data points after the point P.   
        buf=p( P:end);
        if ~isempty(buf)
            
            % Find the points outside the inteval Lplus to Lminus
            buf2=find( buf > Lplus);
            buf22=find(buf < Lminus );
            buf2=union(buf2, buf22);
            
            
            % Determine the lengths of the intervals between data points 
            % that are outside the range Lplus to Lminus.  
            buf3=diff(buf2);
            
            % Find the intervals greater than length tr1.
            ints_gt_tr1=find(buf3 > tr1, 1);
    
            % Find point Q
            if buf2(ints_gt_tr1) > t1
                Q=P+buf2(ints_gt_tr1);
                flag5=1;
            else
                Q=P;
            end
            
        
        else
            Q=n1;
        end
        
        pp=1/Fs*(Q-Lpt1);

    end


    if Q < n1 && logical(length(p) > 10)
        
        flag6=1;
        % Find durations of the secondary fluctuations
        make_plot2=0;
        [sf, sf2, ctime, spa, mpa, error_cond]=B_Duration_second_flucts(p, Fs, Q, Lplus, Lminus, make_plot2);
        
    end
    

end


if P > n1
    P=n1;
end

if P < 1
    P=1;
end

if sf > 0.1*pp
    b=pp+sf;
else
    b=pp;
end

if isempty(b)
    b=-1;
end


if isequal(make_plot, 1)

    Lt=1;
    
    t=1/Fs*(0:(n1-1));
    figure;
    plot(t, p);
    uno=ones(1,2);
    t2=[t(1) t(end)];
    
    
    % Plot Lplus 
    hold on;
    plot(t2, Lplus*uno,    'k', 'LineWidth', Lt);
    text( 0.9*t(end), 1.1*Lplus,'L_{plus}', 'HorizontalAlignment', 'Left', 'VerticalAlignment', 'Bottom');
    
    % Plot Lminus
    plot(t2, Lminus*uno,   'k', 'LineWidth', Lt);
    text( 0.9*t(end), 1.1*Lminus,'L_{minus}', 'HorizontalAlignment', 'Left', 'VerticalAlignment', 'Top');
    
    % Plot Baseline
    plot(t2, Baseline*uno, 'r', 'LineWidth', Lt);
    text( 0.9*t(end), Baseline,'Baseline', 'HorizontalAlignment', 'Left', 'VerticalAlignment', 'Middle', 'BackgroundColor', [1 1 1]);
    
    % Plot Global Max Peak
    plot( (pos_gl_pk_ix-1)/Fs, p(pos_gl_pk_ix), '^k', 'linestyle', 'none', 'markersize', 7, 'LineWidth', Lt);
    text( (pos_gl_pk_ix-1)/Fs, p(pos_gl_pk_ix),'  Global Maximum', 'HorizontalAlignment', 'Left', 'VerticalAlignment', 'Bottom');
    
    % Plot Global Min Peak
    plot( (neg_ix-1)/Fs, p(neg_ix), 'vk', 'linestyle', 'none', 'markersize', 7, 'LineWidth', Lt);
    text( (neg_ix-1)/Fs, p(neg_ix),'  Global Minimum', 'HorizontalAlignment', 'Left', 'VerticalAlignment', 'Bottom');

    % Plot point Lpt1, (Last Point Before excursion above Lplus    
    plot( (Lpt1-1)/Fs, Lplus,  'xk', 'linestyle', 'none', 'markersize', 11, 'LineWidth', Lt);
    text( (Lpt1-1)/Fs-0.001, 1.1*Lplus, 'Point S', 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'Bottom');
    
    % Plot point P
    plot( (P-1)/Fs, p(P), 'ok', 'linestyle', 'none', 'markersize', 7, 'LineWidth', Lt);
    if p(P) > 0
        vertical_align='Bottom';
    else
        vertical_align='Top';
    end
    text((P-1)/Fs, 1.1*p(P),'  Point P', 'HorizontalAlignment', 'Left', 'VerticalAlignment', vertical_align);
    
    % Plot point Q
    if isequal(flag5, 1)
        plot( (Q-2)/Fs, p(Q-1), 'sc', 'linestyle', 'none', 'markersize', 7, 'LineWidth', Lt);
        text( (Q-2)/Fs, p(Q-1),'  Point Q', 'HorizontalAlignment', 'Left', 'VerticalAlignment', 'Bottom');
    end
    
    % Plot subsequent fluctuations
    if isequal(flag6, 1)
        
        % put a green circle for each point above the threshold
        for e1=1:length(ctime); 
            plot( (Q-1+ctime(e1))/Fs, p(Q+ctime(e1)), 'og', 'linestyle', 'none', 'markersize', 7);
        end
        
        % put a red circle for each single point above the threshold
        for e1=1:length(spa); 
            plot( (Q-1+spa(e1))/Fs, p(Q+spa(e1)), 'or', 'linestyle', 'none', 'markersize', 7);
        end
        
        % put a black circle for the beginning and end point of each series of multiple points above the threshold
        for e1=1:length(mpa); 
            plot( (Q-1+mpa(e1))/Fs, p(Q+mpa(e1)), 'ok', 'linestyle', 'none', 'markersize', 7);
        end
    end
    
    
    title({'Calculation of B-duration'}, 'Fontsize', 24);
    ylabel('Amplitude (Pa)', 'Fontsize', 18);
    xlabel('Time seconds', 'Fontsize', 18);
    legend_str=cell(8,1);
    legend_str(1:8, 1)={'Signal', 'L_{plus}', 'L_{minus}', 'Baseline', 'Global Max Peak', 'Global Min Peak', 'Point S', 'Point P'};
    if isequal(flag5, 1)
        legend_str{9, 1}='Point Q';
    end
    
    legend(legend_str, 'Location', 'NorthEast'); 
    
    
    rr=(pmax-pmin);
    ylim([0.1*round(10*(pmin-0.1*rr)) 0.1*round(10*(pmax+0.1*rr))]);
    xlim([t(1) t(end)]);
    set(gca, 'Fontsize', 16);
   
   
end

Contact us at files@mathworks.com