Engee documentation
Notebook

The AGC model using the Engee Function

AGC (Automatic Gain Control, automatic gain control)
is a method of controlling the signal level in communication systems, the main purpose of which
is to maintain a stable level.
output signal when the amplitude of the input signal changes.

AGC Usage Examples

  1. In radios, it helps to stabilize the sound volume
    regardless of the strength of the received signal.
  2. Maintains a constant recording level in audio systems
    even with sudden changes in the volume of the sound source.

Thus, AGC provides comfortable and high-quality
reception/reproduction of signals in various conditions.
The model we implemented is shown below.

image.png

The model has an Engee Function block, which implements the algorithm for
calculating the gain in this function. The envelope variable is an analog of the MATLAB constant variable( persistent ). It is local
to the function in which it is created, but it is not reset at each
calculation step, but stores the previous value, that is, it is stored
in memory between function calls.

Let's take a closer look at the implementation of this feature.

  1. Block Structure

A block is a structure that inherits
from AbstractCausalComponent. It contains a field
A Float64 envelope, which is used
to store the value of the envelope of the signal.
The Block() constructor itself initializes
a new Block object with an initial
envelope value of 0.

image.png
  1. Call function

This is the main function of our algorithm. It
takes three arguments: t (time), level (level) and loudness (volume).

If the value of the envelope is less than 0.08, then the envelope_gain is set to 0.08.
Otherwise, the current value of the envelope is used.

The function returns the loudness value divided by envelope_gain,
which is the final gain value
at a specific calculation step.
image.png

  1. Update function!

This function updates the value of the envelope in the object.
Block. It calculates the difference between the level and the current value of the envelope.
If the difference is positive, the envelope increases by 80% of this
difference. Otherwise, it is reduced by 1% of this difference. As a result
, the function returns the updated Block object, which allows
us to store and redefine this value at each of the calculation steps.
image_2.png

Now that we have decided on the organization of the model, let's move on to launching it and analyzing the results.

Auxiliary functions

In [ ]:
using WAV;
using .EngeeDSP;

function audioplayer(patch, Samples_per_audio_channel);
    s, fs = wavread(patch); 
    buf = IOBuffer();
    wavwrite(s, buf; Fs=fs);
    data = base64encode(unsafe_string(pointer(buf.data), buf.size));
    display("text/html", """<audio controls="controls" {autoplay}>
    <source src="data:audio/wav;base64,$data" type="audio/wav" />
    Your browser does not support the audio element.
    </audio>""");
    return s
end

# Подключение вспомогательной функции запуска модели.
function run_model( name_model)
    
    Path = (@__DIR__) * "/" * name_model * ".engee"
    
    if name_model in [m.name for m in engee.get_all_models()] # Проверка условия загрузки модели в ядро
        model = engee.open( name_model ) # Открыть модель
        model_output = engee.run( model, verbose=true ); # Запустить модель
    else
        model = engee.load( Path, force=true ) # Загрузить модель
        model_output = engee.run( model, verbose=true ); # Запустить модель
        engee.close( name_model, force=true ); # Закрыть модель
    end
    sleep(5)
    return model_output
end
Out[0]:
run_model (generic function with 1 method)

Launching and analyzing the model

In [ ]:
run_model("agc_code") # Запуск модели.
Building...
Progress 0%
Progress 0%
Progress 6%
Progress 6%
Progress 13%
Progress 13%
Progress 18%
Progress 18%
Progress 23%
Progress 23%
Progress 29%
Progress 29%
Progress 34%
Progress 34%
Progress 40%
Progress 40%
Progress 45%
Progress 45%
Progress 50%
Progress 50%
Progress 56%
Progress 56%
Progress 61%
Progress 61%
Progress 66%
Progress 66%
Progress 72%
Progress 72%
Progress 77%
Progress 77%
Progress 83%
Progress 83%
Progress 88%
Progress 88%
Progress 94%
Progress 94%
Progress 99%
Progress 99%
Progress 100%
Progress 100%
Progress 100%
Progress 100%
Out[0]:
SimulationResult(
    "Out" => WorkspaceArray("agc_code/Out"),
    "inp" => WorkspaceArray("agc_code/inp")
)

Let's compare one of the frames of the first channel at the input and output of the model.

In [ ]:
inp = collect(simout["agc_code/inp"])
inp = inp.value[10,1]
out = collect(simout["agc_code/Out"])
out = out.value[10,1]

plot([inp[:,1],out[:,1]], label=["input data" "output data"])
Out[0]:

As we can see, the amplitude of the output signal in this
frame is significantly lower than the amplitude of the input signal.,
which shows us the correct operation of our function.

Now let's listen to both audio tracks.

In [ ]:
audioplayer("$(@__DIR__)/speech_fade_48kHz.wav", 256);
In [ ]:
audioplayer("$(@__DIR__)/out_48kHz.wav", 256);

Conclusion

As we can see from this example, our algorithm for automatically adjusting the signal gain is working correctly.