| [rta, Lya, rtpa]=reverb_time(SP, Fs, fc, t_high, t_low, num_x_filter, pbs, pab, method)
|
function [rta, Lya, rtpa]=reverb_time(SP, Fs, fc, t_high, t_low, num_x_filter, pbs, pab, method)
% % Syntax:
% % [rta, Lya, rtpa]=reverb_time(SP, Fs, fc, t_high, t_low, num_x_filter,pbs, pab, method);
% %
% % This program supports two methods of calculating the reverberation
% % time: the speaker on speaker off method and the balloon pop method.
% % The speaker on speaker off method is considered to be much more
% % accurate. It is highly recommended to use the speaker on speaker off
% % method if possible.
% %
% % This program calculates reverberation times for 1/3 octave broad
% % band noise for multiple microphones. See the description of the
% % variable fc.
% %
% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% % Description of the Input Variables
% %
% % SP is the time record in units Pa and has size (num_mics,
% % num_samples). SP is automatically rearranged so that the number
% % of elements in the second dimension are greater than the first
% % dimension.
% %
% % Fs (Hz) is the samping rate.
% %
% % fc (Hz) is the third octave band center frequency.
% %
% % Filters have anomalies and program returns meaningless data
% % for fc > Fs/3.
% %
% % It is difficult to excite source below 31 Hz with enough energy
% % for a meaningful reverberation time.
% %
% % For the balloon pop method, the impulsive reverberant decay must
% % reach the background level.
% %
% % For the Balloon pop method measurement times of 10 seconds or
% % longer are recommended for fc < 200 Hz.
% %
% %
% % t_high (s) is used in the speaker on spekaer off method.
% % t_high is the duration of signal on at the beginning of the time
% % record. This is used to calculate the average signal level.
% %
% % t_low (s) is used by both methods. t_low is the duration of quiet
% % time at the end of the time record. t_low is used to calculate the
% % average background level.
% %
% % num_x_filter is the number of times to filter the time record.
% % The minimum value of num_x_filter is 1.
% % Typically a value of 2 is sufficient to remove the contributions
% % from other third octave bands.
% %
% % If there is spurious background noise, espcially in the low
% % frequencies fc < 100 Hz, then additional filtering may be
% % beneficial. num_x_filter=10 can remove up to 120 dB of noise.
% % Unfortunately the third octave band filter changes the calculated
% % reverberation times, so be careful.
% %
% % Increasing num_x_filter does not necessarily improve accuracy.
% % Increasing the input signal speaker level or balloon pop level
% % may improve the accuracy for both methods.
% %
% % pbs is an acronym for the percentage of the total range in dB below
% % the average signal level. pbs is used to discard spurious
% % high level sound data at the speaker cutoff. pbs=20 usually works.
% %
% % pab is an acronym for the percentage of the range above the average
% % background level. pab is used to discard spurious background
% % noise where the reveberant decay approaches the background level.
% % This is more of a problem in environments with very low background
% % For example, measuring reverberation time in a hemi-anechoic
% % chamber.
% %
% % method selects the speaker on speaker off method or the balloon pop
% % method. 1 for speaker, otherwise balloon pop.
% %
% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% % Description of the Output Variables
% %
% % rta % The array of the reverberation times
% %
% % Lya % The array of processed time records
% %
% % rtpa % The array of time records of the solution of the
% % % reverberation time calculation
% %
% % SP2 % Resampled and filtered time record
% %
% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% Example=''; % Simulated reverberation data
% % For the Speaker on Speaker off method
%
% % This example is for a four microphone with each microphone recording at
% % a different level. The reverberation time is set to a different for each
% % microphone to illustrate the decay line fitting.
%
% tau=[2, 2.3, 3.0, 2.4]; % time constants for exponential decay
%
% tb=5; % seconds, duration of decay signal
%
% Fs=50000; % sampling frequency rate
%
% t=1/Fs*(1:(tb*Fs)); % seconds time array for calculating
% % decay signal
%
% A=[100, 110, 115, 130];
% decay1=A(1).*exp(-1./tau(1).*t).*randn(1,length(t));
% decay2=A(2).*exp(-1./tau(2).*t).*randn(1,length(t));
% decay3=A(3).*exp(-1./tau(3).*t).*randn(1,length(t));
% decay4=A(4).*exp(-1./tau(4).*t).*randn(1,length(t));
%
% % The test signal has
% % 1) nominal one second of signal high
% % 2) reverberant decay
% % 3) nominal one second of background noise
% %
% SP=zeros(4, 2*Fs+length(t));
% SP(1, :)=[A(1)*randn(1,Fs) decay1 A(1).*exp(-1./tau(1).*tb)*randn(1, Fs);];
% SP(2, :)=[A(2)*randn(1,1.5*Fs) decay2 A(2).*exp(-1./tau(2).*tb)*randn(1, 0.5*Fs);];
% SP(3, :)=[A(3)*randn(1,1.2*Fs) decay2 A(3).*exp(-1./tau(3).*tb)*randn(1, 0.8*Fs);];
% SP(4, :)=[A(4)*randn(1,0.8*Fs) decay2 A(4).*exp(-1./tau(4).*tb)*randn(1, 1.2*Fs);];
%
% figure(1); for e1=1:4; subplot(4, 1, e1); plot(SP(e1, :)); hold on; end;
%
% Fs=50000; % (Hz) Sampling rate
%
% fc=400; % (Hz) Center frequency of the third-octave band
%
% t_high=0.5; % (s) duration of loud time at the beginning of the time record
% % used to calculate the average signal level,
% % which is usead to estimate the speaker cutoff time
% % A longer t_high time is better when there is filter phase delay
% % especially at low frequencies (Fc < 100) or
% % if the speaker turns onslowly
%
% t_low=0.5; % (s) duration of quiet time at the end of the time record
% % used to calculate the average background level for
% % calculating the time when the background noise level is reached
% % a longer time gets the background level above
% % the dips and peaks in the background level from
% % sudden quiet and background dog barks etc...
%
% num_x_filter=2; % Number of times to filter the data. Minimum value is 1
% % typically a value of 2 is sufficient to remove noise.
% % num_x_filter=10 can remove 120 dB of noise.
% % Increasing num_x_filter changes the cacualted
% % reverberation time.
%
% pbs=15; % Percentage of the total range in dB below the average signal
% % level to discard from fitting to a line. This avoids
% % spurious high level sound data at the speaker cutoff.
%
% pab=40; % Percentage of the range above the average background level
% % to discard. Increases the background cutoff level above
% % spurious background noise where the reveberation decay
% % approaches the background level. A value of 40 worked in
% % a laboratory hemi-anechoic chamber and may work for
% % acoustical environments with very low background noise levels.
%
% pab=15; % A value of 15 worked for an animal shelter with dogs barking
% % in the surrounding rooms.
%
% method=1; % 1 is the speaker on speaker off method.
% % otherwise is the balloon pop method
%
% [rta, Lya, rtpa]=reverb_time(SP, Fs, fc, t_high, t_low,num_x_filter,pbs,pab, method);
%
% % Exact reverberation times are
% t_60=log(1000).*tau;
%
% % The percent error is
% Percent_error=100.*(1-(t_60./rta'));
% %
% %
%
% % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% Example=''; % Simulated reverberation data
% % For the Balloon Pop Method
%
% % This example is for a four microphone with each microphone recording at
% % a different level. The reverberation time is set to a different for each
% % microphone to illustrate the decay line fitting.
%
% tau=[2, 2.3, 3.0, 2.4]; % time constants for exponential decay
%
% tb=5; % seconds, duration of decay signal
%
% Fs=50000; % sampling frequency rate
%
% t=1/Fs*(1:(tb*Fs)); % seconds time array for calculating
% % decay signal
%
% A=[100, 110, 115, 130];
% decay1=A(1).*exp(-1./tau(1).*t).*randn(1,length(t));
% decay2=A(2).*exp(-1./tau(2).*t).*randn(1,length(t));
% decay3=A(3).*exp(-1./tau(3).*t).*randn(1,length(t));
% decay4=A(4).*exp(-1./tau(4).*t).*randn(1,length(t));
%
% % The test signal has
% % 1) nominal one-tenth of a second of background noise
% % 2) reverberant decay
% % 3) nominal one second of background noise
%
% SP=zeros(4, 2*Fs+length(t));
% SP(1, :)=[0.01*A(1)*randn(1,0.1*Fs) decay1 A(1).*exp(-1./tau(1).*tb)*randn(1, Fs);];
% SP(2, :)=[0.01*A(2)*randn(1,0.1*Fs) decay2 A(2).*exp(-1./tau(2).*tb)*randn(1, Fs);];
% SP(3, :)=[0.01*A(3)*randn(1,0.1*Fs) decay2 A(3).*exp(-1./tau(3).*tb)*randn(1, Fs);];
% SP(4, :)=[0.01*A(4)*randn(1,0.1*Fs) decay2 A(4).*exp(-1./tau(4).*tb)*randn(1, Fs);];
%
% Fs=50000;
% fc=400;
% t_high=0.5;
% t_low=0.5;
% num_x_filter=2;
% pbs=15;
% pab=15;
% method=2;
%
% [rta, Lya, rtpa]=reverb_time(SP, Fs, fc, t_high, t_low,num_x_filter,pbs,pab, method);
%
% % Exact reverberation times are
% t_60=log(1000).*tau;
%
% % The percent error is
% Percent_error=100.*(1-(t_60./rta'));
%
% %
% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% % Uses the Signal Processing Toolbox
% % Uses the following progrmas which can be found on matlab central
% % Uses the octave program set from Christophe Couvreur
% % Uses programs from Alexandros Leontitsis
% % Uses the modified programs from Alexandros Leontitsis
% %
% % List of Subprograms
% % findextrema From Schuberth Schuberth found on matlab central
% % oct3dsgn From Christophe Couvreur found on matlab central
% % sub_mean
% % LMTSreg A modified program original from Alexandros Leontitsis
% % found on matlab central
% % LMSloc From Alexandros Leontitsis found on matlab central
% % LMS_trim
% % rand_int
% % LMTSregor A modified program original from Alexandros Leontitsis
% % found on matlab central
% %
% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% % Program was written by Edward L. Zechmann
% %
% % date 16 October 2007
% %
% % modified 13 January 2008 updated comments
% % changed from filter.m to filtfilt.m
% % Added impulsive nosie method
% %
% % modified 14 January 2008 Reduced number of points allowed for
% % the robust line fit
% % updated comments
% %
% % modified 13 February 2008 Added the balloon pop method and
% % example
% % Made the fit adaptive for both methods
% % Added a leverage point to the
% % Speaker on speaker off method when the
% % decay line fit does not properly
% % intersect the signal high time record
% %
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% % Please feel free to modify this code.
% %
if nargin < 9
method=1;
end
fc=round(fc);
[SP]=convert_double(SP);
[m1, n1]=size(SP);
if m1 > n1
SP=SP';
[m1 n1]=size(SP);
end
if nargin < 6
num_x_filter=1;
else
if num_x_filter < 1
num_x_filter=1;
end
end
dt=1/Fs;
%Resample timeseries so that filter has better performance
p=1;
q=1;
flag1=0;
Fsn=Fs;
if fc < Fs/50
Fsn=40*fc;
flag1=1;
elseif fc > Fs/10
Fsn=10*fc;
flag1=1;
end
if flag1 == 1
dtn=1/Fsn;
[p,q] = rat(dt/dtn);
buf=resample(SP(1, :), p, q);
n2=length(buf);
SP2=zeros(m1,n2);
SP2(1, :)=buf;
clear('buf');
if m1 > 1
for e1=2:m1;
SP2(e1, :)=resample(SP(e1, :), p, q);
end
end
Fs2=Fs*p/q;
else
Fs2=Fs;
SP2=SP;
end
% Calculate the filter coefficients for the third octave filter
[Bc,Ac] = oct3dsgn(fc,Fs2,3);
clear('SP');
for e1=1:m1;
for e2=1:num_x_filter;
SP2(e1, :)=filtfilt(Bc,Ac,SP2(e1, :)); %Process data with a 1/3 octave bandpass filter
end
end
if flag1 == 1
buf=resample(SP2(1, :), q, p);
SP=zeros(m1,length(buf));
SP(1, :)=buf;
clear('buf');
if m1 > 1
for e1=2:m1;
SP(e1, :)=resample(SP2(e1, :), q, p);
end
end
else
SP=SP2;
Fs=Fs2;
end
clear('SP2');
% return SP to size [m1, n1]
% check size of SP zero pad if necessary
[m2 n2]=size(SP);
if n1 ~= n2
if n2 > n1
SP=SP(1:m1, 1:n1);
else
a=min(min(abs(SP)));
for e1=1:m1;
for e2=1:n1;
if e2 <= n2
SP(e1, e2)=SP(e1, e2);
else
SP(e1, e2)=a;
end
end
end
end
end
[m1 n1]=size(SP);
SP=SP-mean(SP, 2)*ones(1, n1);
a=1:m1;
SP = abs(hilbert(SP')');
I_high2=floor(t_high/dt);
I_low2=floor(t_low/dt);
rta=zeros(m1,1);
Lya=zeros(m1,n1);
rtpa=zeros(m1,n1);
for e1=1:m1;
if isequal(method, 1)
% Process data for the speaker on speaker off method
[buf1, y22 ]=sub_mean(SP(e1, 1:n1), Fs, 25);
else
% Process data for the balloon pop method
[buf1, y22 ]=sub_mean(SP(e1, 1:n1), Fs, 100);
end
Ly=20*log10(y22(1, :)./(20*10^(-6)));
% reset the values for I_high and I_low adn the other quantities
I_high=I_high2;
I_low=I_low2;
IX_est=0;
IX3=n1;
count=0;
t1=0;
t2=n1-I_low;
IX=1;
flag=0;
while (logical(abs(IX3-IX_est)/IX3 > 0.1) || logical(abs(I_high-t1)/I_high > 0.1) || logical(abs(I_low-(n1-t2))/I_low > 0.1)) && logical(count < 3)
if isequal(count, 0)
IX3=n1-I_low;
end
count=count+1;
I_high=max([I_high, IX]);
buf1=[n1-t2, n1-IX3];
buf1=buf1(buf1>0);
I_low=min(buf1);
if I_low > n1
I_low=n1-1;
end
if I_low < 1
I_low=1;
end
if I_high > n1
I_high=n1-1;
end
if I_high < 1
I_high=1;
end
if isequal(method, 1)
% Level at beginning
Lb=sqrt(sum(y22(1, 1:I_high)'.^2)./I_high);
else
% Level of the balloon pop
Lb=max(y22(1, :));
end
SPLb=20*log10(Lb./(20*10^(-6)));
% Level at the end
Le=sqrt(sum(y22(1, (n1-I_low):n1)'.^2)./I_low);
SPLe=20*log10(Le./(20*10^(-6)));
% Find the beginning and ending of the decay
% Set cutoff level pbs percent of dB range below the signal level
% Set cutoff level pab percent of dB range above the background level
% Find last data points where the level is below the signal level or
% below the balloon pop level
if isequal(method, 1)
IX=find( Ly > SPLb-pbs/100*(SPLb-SPLe), 1, 'last' );
% find data points where Ly is below the background level
IX2=find( Ly < SPLe+pab/100*(SPLb-SPLe) );
% find the first point below the balloon pop level, but above the
% background level
IX3=IX2(find(IX2 > IX, 1 ));
else
[max_LY IX]=max(Ly);
IX2=find( Ly < SPLe+pab/100*(SPLb-SPLe) );
IX3=IX2(find(IX2 > IX, 1 ));
end
% Make sure there are plenty of data points between IX and IX3
if IX3 - IX < 1000;
if IX3+1000 > n1
IX=IX-1000;
else
IX3=IX3+1000;
end
end
if length(IX:IX3) > 5
if isequal(method, 1)
% SPeaker On Speaker Off Method
IX3=min([max([IX3, IX_est]), n1]);
if IX3 > n1
IX3=n1-1;
end
if IX3 < 1
IX3=1;
end
rtd=Ly(1, IX:IX3);
tt=dt*(IX:IX3);
[LMSout,blms,Rsq]=LMTSreg(rtd',tt', 1000, 100000);
p=[blms(2) blms(1)];
t2=floor(Fs*(SPLe-p(2))/p(1));
IX_est=t2;
else
% Balloon Pop Method
IX3=max(IX3, IX_est);
if IX3 > n1
IX3=n1-1;
end
if IX3 < 1
IX3=1;
end
rtd=Ly(1, IX:IX3);
tt=dt*(IX:IX3);
num_pts=length(rtd);
num_bins=min([num_pts/5, 1000]);
rbp=floor(num_pts/num_bins);
bins=(1:rbp:num_pts);
epts=zeros((length(bins)-1), 1);
for e2=1:(length(bins)-1);
[buf, eptsix]=max(rtd(bins(e2):bins(e2+1)));
epts(e2)=bins(e2)-1+eptsix;
end
[ma,mi]=findextrema(rtd);
rtd_n1=length(rtd);
ma=unique(round(ma));
ma=intersect(ma, epts);
if length(ma) > 10
if ma(1) < 1
ma(1)=1;
end
if ma(end) > rtd_n1
ma(end)=rtd_n1;
end
ma=unique(ma);
[LMSout,blms,Rsq]=LMTSregor(-max_LY+rtd(ma)',-tt(1)+tt(ma)', 1000, 100000);
p=[blms(1) max_LY];
else
[LMSout,blms,Rsq]=LMTSregor(-max_LY+rtd',-tt(1)+tt', 1000, 100000);
p=[blms(1) max_LY];
end
t2=floor(Fs*(SPLe-p(2))/p(1));
IX_est=IX+t2;
end
else
count=1000000;
p(1)=60;
p(2)=SPLb;
rtp=SPLb*ones(1, n1);
end
t1=ceil(Fs*(SPLb-p(2))/p(1)); % first intersection point
t2=floor(Fs*(SPLe-p(2))/p(1)); % second intersection point
if ((-t1+IX)/IX > 0.3 || logical(p(1) > 0)) && isequal(method, 1)
% Method failed
% a leverage point is necessary to ensure a good fit
% The intesection point of the signal high cutoff limit and
% the instantaneous sound level data will be the leverage point
flag=1;
count=4;
[LMSout,blms,Rsq]=LMTSregor(-Ly(IX)+rtd',-dt*(IX)+tt', 1000, 100000);
p=[blms(1) Ly(IX)];
t1=ceil(Fs*(SPLb-p(2))/p(1)); % first intersection point
t2=floor(Fs*(SPLe-p(2))/p(1)); % second intersection point
end
rty = polyval(p,dt*(t1:t2));
if isequal(method, 1) && ~isequal(flag, 1)
rtp=[ SPLb*ones(1, t1-1) rty SPLe*ones(1, (n1-t2))];
else
rtp=[ SPLb*ones(1, IX+t1-1) rty SPLe*ones(1, (n1-IX-t2))];
end
end
rt=-60/p(1); % Estimated Reveberation Time
rta(e1)=rt; % Array of estimated reverberation time measurements
Lya(e1, :)=Ly; % Time record of processed time record
rtpa(e1, :)=rtp(1, 1:n1); % Time record of reverberation time solution
end
|
|