Engee documentation
Notebook

Parametric audio equalizer

In this demo, we will analyze a parametric audio equalizer that supports three configurable bands. Each band is implemented using a different biquadrate filter structure.
image.png

An equalizer is an electronic device or computer program that allows you to selectively adjust the amplitude of a signal depending on the frequency characteristics.

Also in this demo, we will compare the operation of the Engee and MATLAB models.
To do this, connect the necessary libraries and consider the device of the implemented model.

In [ ]:
Pkg.add(["Statistics", "CSV"])
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`
In [ ]:
using Plots
using MATLAB
using CSV
using DataFrames
using Statistics
In [ ]:
plotlyjs();
In [ ]:
mat"start_simulink"
mat"p = genpath('/user/start/examples'); addpath(p);"

The model consists of two main blocks: the equalizer itself, which includes 3 filtering units with filter coefficients at the upper level, and the discrete transfer function estimator. The figures below show the appraiser's model and settings.

image.png image_2.png

If we consider each of the filters, they are implemented in the same way and include a discrete filter, a coefficient sampling unit, and a biquad filter.

image_3.png

Now let's move on to the launch and comparison of the implementation of this model in Engee and Simulink.

Launching and analyzing the Engee model

Let's look at the simulation results in Engee:

In [ ]:
function rum_model(NemeModel,Path_to_folder)
Path = Path_to_folder * "/" * NemeModel * ".engee"
   if NemeModel in [m.name for m in engee.get_all_models()] # Проверка условия загрузки модели в ядро
      model = engee.open(NemeModel) # Открыть модель
      engee.run(model, verbose=true); # Запустить модель
   else
      model = engee.load(Path, force=true) # Загрузить модель
      engee.run(model, verbose=true); # Запустить модель
      engee.close(NemeModel, force=true); # Закрыть модель
   end
end
Out[0]:
rum_model (generic function with 1 method)
In [ ]:
# Запуск модели
rum_model("Equalizer","/user/start/examples/dsp/equalizer")
Building...
Progress 0%
Progress 1%
Progress 32%
Progress 100%
Progress 100%
In [ ]:
function parse_csv_engee(filename :: String)
    file = open(filename)
    line = readline(file)
    name_idx = vcat(0,findall(',', line), length(line)+1)
    names = collect([line[(name_idx[it-1]+1):(name_idx[it]-1)] for it  2:length(name_idx)])
    data = collect([it for it  (line -> eval(Meta.parse(line)))(readline(file))])
    while !eof(file)
        data = ((a, b) -> [a;;;b]).(data, collect([it for it  (line -> eval(Meta.parse(line)))(readline(file))]))
    end
    close(file)
    return Dict(names .=> data)
end
Out[0]:
parse_csv_engee (generic function with 1 method)
In [ ]:
# Чтение CSV
out = parse_csv_engee("/user/start/examples/dsp/equalizer/out.csv");
out_t = out["time"];
out_data = out["1"];
In [ ]:
# Построение графиков
Eng_data = reshape(out_data,808)
plot(Eng_data[1:8:end])
plot!(Eng_data[2:8:end])
plot!(Eng_data[3:8:end])
plot!(Eng_data[4:8:end])
plot!(Eng_data[5:8:end])
plot!(Eng_data[6:8:end])
plot!(Eng_data[7:8:end])
plot!(Eng_data[8:8:end])
plot!(title = "Результаты моделирования в Engee", ylabel = "Данные", xlabel="Время, c")
Out[0]:

Launching and analyzing the Simulink model

Let's compare the simulation results in Engee and Simulink. To do this, we will first run a simulation of the model.

In [ ]:
mat"run_test_model('Equalizer')";

Let's look at the results in Simulink:

In [ ]:
mat"whos" # Вывести все переменные, хранящиеся в рабочей области
>> >> >>   Name                     Size                  Bytes  Class                             Attributes

  SimulationSteps        101x1                     808  double                                      
  SysOutput                1x1                    6800  timeseries                                  
  a                        1x6                      48  double                                      
  b                        1x6                      48  double                                      
  matlab_jl_has_ans        1x1                       8  double                                      
  n                        1x32                    256  double                                      
  out                      1x1                  847601  Simulink.SimulationOutput                   
  p                        1x585978            1171956  char                                        
  sig                      1x1                    7018  Simulink.SimulationData.Signal              

In [ ]:
# Чтение выхода модели
sim = mat"SysOutput.Data";
In [ ]:
# Построение графиков
Sim_data = reshape(sim,808)
plot(Sim_data[1:8:end])
plot!(Sim_data[2:8:end])
plot!(Sim_data[3:8:end])
plot!(Sim_data[4:8:end])
plot!(Sim_data[5:8:end])
plot!(Sim_data[6:8:end])
plot!(Sim_data[7:8:end])
plot!(Sim_data[8:8:end])
plot!(title = "Результаты моделирования в Simulink", ylabel = "Отклик", xlabel="Время, c")
Out[0]:

Now let's plot the difference between the output data Simulink and Engee, and also calculate the average error value.

In [ ]:
plot(Sim_data-Eng_data)
Out[0]:
In [ ]:
print("Погрешность: " * string((sum(abs.(Sim_data-Eng_data)))/length(Eng_data)))
Погрешность: 2.3758486926991814e-12

As we can see from the graphs presented above and the result of calculating the average error, the models work almost identically.

Conclusion

In this example, we implemented an equalizer, and also compared the capabilities of Engee regarding modeling in Simulink and showed the options for connecting the MATLAB core to solve problems inside the Engee development environment.