Выбор полосы фильтра приёмника
Выбор полосы фильтра приёмника
В этом примере сравним две настройки полосы приёмника в Engee. Модель формирует полезный сигнал и добавляет шум. Объект VariableBandwidthIIRFilter библиотеки EngeeDSP фильтрует запись с полосой 75 или 190 Гц. По графикам и среднеквадратичной ошибке определим, какая настройка подходит для узкого и широкого сигнала.
Уменьшение полосы пропускания снижает мощность принятого шума. Но если фильтр становится уже полезного спектра, он искажает сам сигнал. Поэтому оптимальная полоса зависит от задачи.
Сначала передадим тон 40 Гц. Затем добавим компоненту 140 Гц и посмотрим, как изменится выбор фильтра.
Ошибка восстановления оценивается величиной RMSE — корнем из средней квадратичной ошибки:
БИХ-фильтр имеет частотно зависимую задержку. Перед сравнением подберём целочисленный сдвиг от 0 до 20 отсчётов по минимальной RMSE; первые 40 отсчётов не учитываем. Это наилучшее выравнивание относительно известной опоры, а не самостоятельный алгоритм синхронизации приёмника.

В модели VariableBandwidth.engee блоки Tone40 и Tone140 создают полезные компоненты. BandSignal складывает их, ReceiverNoise добавляет белый гауссовский шум. Записываются чистый сигнал tx и зашумлённый rx.
Частота дискретизации 1000 Гц. Скрипт меняет амплитуду тона 140 Гц между 0 и 0.55 и обрабатывает результат двух запусков.
Подключим библиотеки и зададим путь к модели относительно папки скрипта. Вспомогательная функция загрузит и откроет модель, применит параметры и закроет её после запуска. Данные To Workspace читаются из общей рабочей области Engee, поэтому программный запуск этого примера выполняем с isolate = false.
using Statistics, DataFrames, Plots
gr()
name = "VariableBandwidth"
path = joinpath(@__DIR__, name * ".engee")
@assert isfile(path) "Не найден файл модели: $path"
function load_and_run(path, name; settings=Pair{String,String}[])
try engee.close(name; force=true) catch end
model = engee.load(path; force=true)
engee.open(name)
for (block, keyvalue) in settings
engee.set_param!("$name/$block", keyvalue)
end
try
engee.run(model)
finally
engee.close(name; force=true)
end
end
wa(name) = Core.eval(Main, :(collect($(Symbol(name)))))
Зададим оба фильтра и проведём два опыта. Для каждого результата найдём задержку относительно исходного сигнала и рассчитаем RMSE.
using EngeeDSP
rmse(x,y) = sqrt(mean(abs2.(x .- y)))
function aligned_error(y, reference)
scores = [rmse(y[41+lag:end],reference[41:end-lag]) for lag in 0:20]
lag = argmin(scores)-1
lag, scores[lag+1]
end
labels = ["Узкий сигнал","Широкий сигнал"]
err_n = Float64[]; err_w = Float64[]
last_t = Float64[]; last_ref = Float64[]; last_n = Float64[]; last_w = Float64[]
last_lag_n = 0; last_lag_w = 0
for amplitude in ("0","0.55")
load_and_run(path,name;settings=["Tone140"=>("Amplitude"=>amplitude)])
rx_df = wa("rx"); ref_df = wa("tx")
n = min(nrow(rx_df),nrow(ref_df))
t = Float64.(rx_df.time[1:n]); rx = Float64.(rx_df.value[1:n]); ref = Float64.(ref_df.value[1:n])
narrow = EngeeDSP.VariableBandwidthIIRFilter(PassbandFrequency=75.0,SampleRate=1000.0)
wide = EngeeDSP.VariableBandwidthIIRFilter(PassbandFrequency=190.0,SampleRate=1000.0)
yn = narrow(rx); yw = wide(rx)
lag_n,en = aligned_error(yn,ref); lag_w,ew = aligned_error(yw,ref)
push!(err_n,en); push!(err_w,ew)
last_t,last_ref,last_n,last_w = t,ref,yn,yw
last_lag_n,last_lag_w = lag_n,lag_w
end
Построим сигналы широкого режима с учётом найденной задержки и сравним RMSE для обоих режимов.
p1 = plot(last_t,last_ref,label="Передано",xlabel="Время, с",ylabel="Амплитуда",title="Широкий режим")
plot!(p1,last_t[1:end-last_lag_n],last_n[1+last_lag_n:end],label="Узкий фильтр")
plot!(p1,last_t[1:end-last_lag_w],last_w[1+last_lag_w:end],label="Широкий фильтр")
p2 = bar(labels,hcat(err_n,err_w),label=["Полоса 75 Гц" "Полоса 190 Гц"],ylabel="RMSE",title="Ошибка восстановления")
display(plot(p1,p2,layout=(2,1),size=(850,650)))
println("RMSE узкая полоса=",err_n,"; широкая=",err_w)
Для одного низкочастотного тона узкая полоса лучше отсекает шум. После добавления тона 140 Гц она одновременно подавляет полезную компоненту. Широкий фильтр сохраняет обе компоненты, хотя пропускает больше шума.
Это видно по форме сигналов и по сравнительной диаграмме RMSE. При изменении спектра или уровня шума преимущество одного фильтра может исчезнуть.
Вывод
В данном примере мы рассмотрели компромисс между подавлением шума и сохранением полезного спектра. Engee позволяет менять источник в модели и сравнивать настройки фильтра на одинаковых данных. Полосу нужно выбирать по спектру полезного сигнала и допустимой ошибке восстановления.
