Reproducing your attack time.
Analyzing your graph: You have probably used an attack time constant of exactly 1 second to produce this graph (see analysis at bottom of this post).
This is a very long attack time constant and not suitable for normal hearing aids, but openMHA is very flexible and can simulate an attack time of 1 second in its dc compressor, e.g. using the following configuration:
Code: Select all
# store in file tau_attack_test.cfg
srate=48000
nchannels_in=1
fragsize=32
iolib=MHAIOParser
mhalib=mhachain
mha.algos=[sine overlapadd]
mha.overlapadd.wnd.len=64
mha.overlapadd.fftlen=128
mha.overlapadd.plugin_name=dc
mha.overlapadd.dc.gtmin=0
mha.overlapadd.dc.gtstep=1
mha.overlapadd.dc.gtdata=[0 0]
mha.overlapadd.dc.tau_attack = [1.0]
mha.overlapadd.dc.tau_decay = [0]
mha.sine.f = 3000
mha.sine.lev=0
mha.sine.channels=[0]
mha.sine.mode = replace
cmd=start
The compressor configured above has only a single band, and does not compress at all for simplicity, because we are only interested in the effect of the attack time constant on the measured input level.
The input signal of the compressor is generated artificially in the MHA configuration itself by the sinusoid generator placed before the STFT overlapadd operation. This way, we do not have to worry about calibration and computing exact input samples to simulate your step response.
The first thing that we want to do is to start the MHA with this configuration and process a signal of level 0dB long enough so that the attack filter of the dc plugin has completely adapted to this input level. Remember that an input level of 0dB is not the same as silence. I am using the MHA io library MHAIOParser in this configuration to be able to read the estimated input level of the dc filter exactly after every 32 input samples.
We can shorten the initial adaptation time of the input level filter by altering tau_attack during this initial adaptation: Appending the following lines to the configuration file
Code: Select all
mha.overlapadd.dc.tau_attack=[0]
io.input=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
io.input=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
io.input=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
mha.overlapadd.dc.tau_attack=[1.0]
mha.overlapadd.dc.level_in_filtered?
mha.sine.lev=100
will set the attack time constant to 0, then process two audio blocks of 32 samples (the zeros here are replaced by the sine plugin before the dc plugin sees the signal), then changing tau_attack back to the desired attack time constant. I need to process more than one audio block of 32 samples here to fill the complete overlapadd-STFT analysis window with the sinusoid, and I want the window to be completely filled with the sinusoid of level 0dB before changing the attack time constant back to the 1.0 seconds whose effect I want to measure. I can see that the filtered input level is not exactly 0dB but 0.00000026dB which is due to numerical floating-point rounding errors. The error is small enough to be neglected. Finally, I change the level of the sinusoid generator to 100dB, which will be in effect starting with the next incoming audio block.
After the MHA has been initialized with the extended configuration file (mha "?read":tau_attack_test.cfg), I want to process audio blocks and read the filtered level after each block for 1 second of audio signal. 1 second at 48kHz sampling rate means 48000 samples or 1500 blocks of 32 samples each. After that, I expect the filtered input level of the compressor to read 63.21dB.
Therefore, after MHA has been started as above, I need to send it 1500 commands io.input=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], interleaved with 1500 commands mha.overlapadd.dc.level_in_filtered?val. On a unix system with netcat installed, I can do this by entering in another terminal the following command: (Users of other systems can e.g. write a suitable loop in Matlab or Octave, or install a unix shell and netcat.)
Code: Select all
yes "io.input=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
mha.overlapadd.dc.level_in_filtered?val" | head -3000 | nc -w 1 localhost 33337 | grep -v : | tr -d '][' | tee filtered_levels.txt
Because I enter a newline inside a double-quoted string, my shell will print a continuation prompt before the second line which I have not included here. The grep command removes the (MHA:success) lines from the output and tr command removes the square brackets from the output vector of filtered levels.
The last filtered level printed and stored to file filtered_levels.txt is 63.21 dB as expected. Plotting the filtered levels with gnuplot:
shows the same slow level rising as in your graph.
Appendix: Analysis of your graph (see first post in this thread)
1) Horizontal scale: t=20s is at pixel column
\(x_{20}=1581\), t=0s is at pixel column
\(x_0=94\), therefore your horizontal scale is
\(s_x=\frac{x_{20}-x_0}{20}=74.35\frac{pixel}{second}\). ((1581-94)/20).
2) Your first level change is at
\(x=129, t_{up}=\frac{x-x_0}{s_x}=0.47s\).
3) At this time the difference between input level (100dB) and filtered input level (0dB) is 100dB. This difference is reduced by a factor
\(1/e=0.3679\), i.e. when the filtered level reaches
\((100-36.79)dB = 63.21dB\)
4) Vertical scale: L=0dB is at pixel row
\(y_0=-924\), L=100dB is at pixel row
\(y_{100}=-45\), therefore your vertical scale is
\( s_y=\frac{y_{100}-y_0}{100}=8.79\frac{pixel}{dB}\)
5) The 63.21dB filtered level is therefore reached when the filtered level line crosses pixel row
\(y_{63.21}=63.21dB \cdot s_y + L0 = -368.4\). This is the case at pixel column 203, which corresponds to time
\(t_{up}+tau_{attack}=\frac{203-x_0}{s_x}=1.47s\), therefore
\(tau_{attack}=1.0s\).