Engee documentation
Notebook

AGC model using Engee Function

AGC (Automatic Gain Control) is a method of controlling the signal strength in communication systems. is a signal level control technique in communication systems whose main purpose is to maintain a stable level of the output signal as the amplitude of the input signal changes.

Examples of AGC applications

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

Thus, AGC provides comfortable and high quality signal reception/playback in various conditions. reception/playback of signals in various conditions. The model we have realised is presented below.

image.png

The model has an Engee Function block, which implements the algorim for calculating the gain in this function. The envelope variable is an analogue of MATLAB constant variable ( persistent ). It is local for the function in which it is created, but at the same time it is not reset at each step of the calculations, but stores the previous value in itself, i.e. they are stored in memory between function calls. in memory between function calls.

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

  1. Block structure

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

image.png

  1. Call function

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

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

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

  1. Function update!

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

Now that we have decided how to organise the model, let's move on to running it and analysing 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)

Running and analysing 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 on this frame is significantly lower than the amplitude of the input signal. is much lower than the amplitude of the input signal, which shows us that our function is working correctly.

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 could see from this example, our algorithm of automatic signal gain control works correctly.