Negative time constant for single pole lowpass filter means no time-weighting at all.

This commit is contained in:
Anne de Jong 2020-01-21 21:06:17 +01:00
parent 29dc70fad3
commit bd88882f25

View File

@ -20,10 +20,7 @@ Slm *Slm_create(Sosfilterbank *prefilter, Sosfilterbank *bandpass, const d fs,
assertvalidptr(downsampling_fac); assertvalidptr(downsampling_fac);
Slm *slm = NULL; Slm *slm = NULL;
if (tau <= 0) { if (ref_level <= 0) {
WARN("Invalid time constant");
return NULL;
} else if (ref_level <= 0) {
WARN("Invalid reference level"); WARN("Invalid reference level");
return NULL; return NULL;
} else if (fs <= 0) { } else if (fs <= 0) {
@ -41,10 +38,15 @@ Slm *Slm_create(Sosfilterbank *prefilter, Sosfilterbank *bandpass, const d fs,
/// documentation for the computation of its minus 20 dB point. We set the /// documentation for the computation of its minus 20 dB point. We set the
/// reduction in its 'sampling frequency' such that its noise is at a level /// reduction in its 'sampling frequency' such that its noise is at a level
/// of 20 dB less than its 'signal'. /// of 20 dB less than its 'signal'.
if (tau > 0) {
const d fs_slm = 1 / (2 * number_pi * tau) * (1 - 0.01) / 0.01; const d fs_slm = 1 / (2 * number_pi * tau) * (1 - 0.01) / 0.01;
slm->downsampling_fac = (us)(fs / fs_slm); slm->downsampling_fac = (us)(fs / fs_slm);
slm->cur_offset = 0; slm->cur_offset = 0;
*downsampling_fac = slm->downsampling_fac; *downsampling_fac = slm->downsampling_fac;
} else {
*downsampling_fac = 1;
slm->downsampling_fac = 1;
}
/// Create the single pole lowpass /// Create the single pole lowpass
us filterbank_size; us filterbank_size;
@ -54,6 +56,8 @@ Slm *Slm_create(Sosfilterbank *prefilter, Sosfilterbank *bandpass, const d fs,
filterbank_size = 1; filterbank_size = 1;
} }
if (tau > 0) {
vd lowpass_sos = vd_alloc(6); vd lowpass_sos = vd_alloc(6);
d b0 = 1.0 / (1 + 2 * tau * fs); d b0 = 1.0 / (1 + 2 * tau * fs);
*getvdval(&lowpass_sos, 0) = b0; *getvdval(&lowpass_sos, 0) = b0;
@ -70,6 +74,10 @@ Slm *Slm_create(Sosfilterbank *prefilter, Sosfilterbank *bandpass, const d fs,
Sosfilterbank_setFilter(slm->splowpass[ch], 0, lowpass_sos); Sosfilterbank_setFilter(slm->splowpass[ch], 0, lowpass_sos);
} }
vd_free(&lowpass_sos); vd_free(&lowpass_sos);
} else {
/// No low-pass filtering. Tau set to zero
slm->splowpass = NULL;
}
feTRACE(15); feTRACE(15);
return slm; return slm;
@ -106,19 +114,26 @@ dmat Slm_run(Slm *slm, vd *input_data) {
iVARTRACE(15, samples_bandpassed); iVARTRACE(15, samples_bandpassed);
us cur_offset = slm->cur_offset; us cur_offset = slm->cur_offset;
/// Compute the number of samples output
int nsamples_output = (samples_bandpassed - cur_offset) / downsampling_fac; int nsamples_output = (samples_bandpassed - cur_offset) / downsampling_fac;
while (nsamples_output * downsampling_fac + cur_offset < samples_bandpassed) while (nsamples_output * downsampling_fac + cur_offset < samples_bandpassed)
nsamples_output++; nsamples_output++;
if(nsamples_output < 0) nsamples_output = 0; if (nsamples_output < 0)
nsamples_output = 0;
iVARTRACE(15, nsamples_output); iVARTRACE(15, nsamples_output);
iVARTRACE(15, cur_offset); iVARTRACE(15, cur_offset);
dmat levels = dmat_alloc(nsamples_output, filterbank_size); dmat levels;
if (slm->splowpass) {
levels = dmat_alloc(nsamples_output, filterbank_size);
} else {
levels = dmat_alloc(samples_bandpassed, filterbank_size);
}
for (us ch = 0; ch < bandpassed.n_cols; ch++) { for (us ch = 0; ch < bandpassed.n_cols; ch++) {
iVARTRACE(15, ch); iVARTRACE(15, ch);
cur_offset = slm->cur_offset; vd chan = dmat_column(&bandpassed, ch);
/// Inplace squaring of the signal /// Inplace squaring of the signal
for (us sample = 0; sample < bandpassed.n_rows; sample++) { for (us sample = 0; sample < bandpassed.n_rows; sample++) {
tmp = getdmatval(&bandpassed, sample, ch); tmp = getdmatval(&bandpassed, sample, ch);
@ -127,7 +142,8 @@ dmat Slm_run(Slm *slm, vd *input_data) {
// Now that all data for the channel is squared, we can run it through // Now that all data for the channel is squared, we can run it through
// the low-pass filter // the low-pass filter
vd chan = dmat_column(&bandpassed, ch); if (slm->splowpass) {
cur_offset = slm->cur_offset;
/// Apply single-pole lowpass filter for current filterbank channel /// Apply single-pole lowpass filter for current filterbank channel
vd power_filtered = Sosfilterbank_filter(slm->splowpass[ch], &chan); vd power_filtered = Sosfilterbank_filter(slm->splowpass[ch], &chan);
@ -135,25 +151,32 @@ dmat Slm_run(Slm *slm, vd *input_data) {
/// Output resulting levels at a lower interval /// Output resulting levels at a lower interval
us i = 0; us i = 0;
d level;
while (cur_offset < samples_bandpassed) { while (cur_offset < samples_bandpassed) {
iVARTRACE(10, i); iVARTRACE(10, i);
iVARTRACE(10, cur_offset); iVARTRACE(10, cur_offset);
level = 10 * d_log10(*getvdval(&power_filtered, cur_offset) / ref_level / /// Compute level
ref_level); d level = 10 * d_log10(*getvdval(&power_filtered, cur_offset) /
ref_level / ref_level);
*getdmatval(&levels, i++, ch) = level; *getdmatval(&levels, i++, ch) = level;
cur_offset = cur_offset + downsampling_fac; cur_offset = cur_offset + downsampling_fac;
} }
iVARTRACE(15, cur_offset); iVARTRACE(15, cur_offset);
iVARTRACE(15, i); iVARTRACE(15, i);
dbgassert(i == nsamples_output, "BUG"); dbgassert(i == (int) nsamples_output, "BUG");
vd_free(&chan); vd_free(&chan);
vd_free(&power_filtered); vd_free(&power_filtered);
} }
}
slm->cur_offset = cur_offset - samples_bandpassed; slm->cur_offset = cur_offset - samples_bandpassed;
if (!slm->splowpass) {
/// Raw copy of to levels. Happens only when the low-pass filter does not
/// have to come into action.
dmat_copy(&levels, &bandpassed);
}
vd_free(&prefiltered); vd_free(&prefiltered);
dmat_free(&bandpassed); dmat_free(&bandpassed);
feTRACE(15); feTRACE(15);
@ -166,7 +189,6 @@ void Slm_free(Slm *slm) {
if (slm->prefilter) { if (slm->prefilter) {
Sosfilterbank_free(slm->prefilter); Sosfilterbank_free(slm->prefilter);
} }
assertvalidptr(slm->splowpass);
us filterbank_size; us filterbank_size;
if (slm->bandpass) { if (slm->bandpass) {
@ -175,11 +197,12 @@ void Slm_free(Slm *slm) {
} else { } else {
filterbank_size = 1; filterbank_size = 1;
} }
if (slm->splowpass) {
for (us ch = 0; ch < filterbank_size; ch++) { for (us ch = 0; ch < filterbank_size; ch++) {
Sosfilterbank_free(slm->splowpass[ch]); Sosfilterbank_free(slm->splowpass[ch]);
} }
a_free(slm->splowpass); a_free(slm->splowpass);
}
a_free(slm); a_free(slm);
feTRACE(15); feTRACE(15);