Применение системных объектов в обработке сигналов¶
Библиотека EngeeDSP содержит мощные инструменты для обработки сигналов с использованием системных объектов, которые представляют собой специализированные компоненты для потоковой обработки данных. В представленном ниже коде демонстрируется комплексный подход к обработке сигналов, сочетающий системные объекты EngeeDSP с традиционными функциями обработки сигналов.
Перечислим ключевые особенности реализации.
- Использование системного объекта
SineWaveDSP
для генерации сигнала с конфигурируемыми параметрами (амплитуда, частота, метод вычисления). - Применение
DescretFIRFilter
для фильтрации сигнала в потоковом режиме. - Интеграция с обычными функциями обработки (скользящее среднее через свертку).
- Сочетание объектно-ориентированного подхода EngeeDSP с процедурными методами Julia.
Начнём с подключения библиотек, применяемых в данном проекте.
# Pkg.add("DSP")
# Pkg.add("Statistics")
using DSP
using EngeeDSP
using Statistics
Теперь выполним инициализацию. Код, представленный ниже, создает системный объект SineWaveDSP
из библиотеки EngeeDSP для генерации синусоидального сигнала с заданными параметрами: амплитудой A = 0.8
, частотой f = 100 Гц
, частотой дискретизации fs = 1000 Гц
, размером кадра framesize = 796
отсчетов.
Объект настраивается на табличный метод вычисления (Table lookup
), вещественный выход (Real
) и непрерывный режим генерации (Continuous
).
A = 0.8
f = 100
fs = 1000
framesize = 796
H = EngeeDSP.SineWaveDSP(
Amplitude = A,
Frequency = f,
SampleTime = 1//fs,
SamplesPerFrame = framesize,
ComputationMethod = "Table lookup",
OutputComplexity = "Real",
SampleMode = "Continuous"
)
Код ниже создает системный объект DescretFIRFilter
, представляющий собой КИХ-фильтр с базовой конфигурацией по умолчанию, и имеет следующие характеристики:
CoefSource=Dialog parameters
— коэффициенты, в данном случае это массив [0.5 0.5], что соответствует простейшему усредняющему фильтру.FilterStructure=Direct form
— используется стандартная прямая структура реализации фильтра.InputProcessing=Elements as channels
— каждый входной отсчет обрабатывается как отдельный канал.InitialStates=0
— начальное состояние фильтра нулевое.ShowEnablePort=false
иExternalReset=None
— фильтр работает в непрерывном режиме без внешнего управления сбросом.
Этот объект предназначен для потоковой обработки сигналов и сохраняет внутреннее состояние (PreEmphasis_states=[0.0]
) между вызовами.
fir_filter = EngeeDSP.DescretFIRFilter()
Ниже показано создание конфидентов усредняющего фильтра с окном из 10 отсчетов. Массив averaging_filter
заполняется значениями 1/window_size
(т.е. 0.1
), что означает равномерное взвешивание всех 10 предыдущих значений сигнала. Такой фильтр подавляет высокочастотные шумы, сглаживая сигнал за счет усреднения по заданному окну. В отличие от системных объектов EngeeDSP, это статическая свёртка, которая не сохраняет состояние между вызовами.
window_size = 10
averaging_filter = ones(window_size) / window_size
Теперь соберём модель из наших объектов. Код ниже выполняет циклическую генерацию и обработку сигнала в 100 шагов:
- Генерация сигнала:
- На каждом шаге
H()
генерирует новый фрейм синусоиды (длинойframesize=796
отсчетов) через системный объектSineWaveDSP
.
- На каждом шаге
- Фильтрация:
y_fir = fir_filter(x)
— применяет потоковый FIR-фильтр (с коэффициентами[0.5, 0.5]
) к сигналу, сохраняя состояние между вызовами.y_avg = conv(y_fir, averaging_filter)[1:length(y_fir)]
— дополнительно сглаживает сигнал скользящим средним (окно 10 отсчетов), обрезая результат свертки до исходной длины.
- Сохранение результатов:
- Исходный (
s
), отфильтрованный (fir_filtered
) и сглаженный (avg_filtered
) сигналы накапливаются в массивах для последующего анализа.
- Исходный (
# Генерируем и обрабатываем сигнал
s = Float64[] # Исходный сигнал
fir_filtered = Float64[] # После FIR фильтра
avg_filtered = Float64[] # После усреднения
for n in 1:100
x = H()
y_fir = fir_filter(x)
y_avg = conv(y_fir, averaging_filter)[1:length(y_fir)] # Усекаем до исходной длины
append!(s, x)
append!(fir_filtered, y_fir)
append!(avg_filtered, y_avg)
end
Теперь по сохранённым данным выполним построение графиков.
gr()
n_show = 100
t = (0:n_show-1)/fs
p_signals = plot(t, s[1:n_show], label="Исходный сигнал", linewidth=2)
plot!(t, fir_filtered[1:n_show], label="После FIR", linewidth=2, linestyle=:dash)
plot!(t, avg_filtered[1:n_show], label="После усреднения", linewidth=2, linestyle=:dot)
title!("Сигналы на разных этапах обработки")
xlabel!("Время (с)")
ylabel!("Амплитуда")
Результаты графиков:
- Исходный сигнал (сплошная линия) — чистый синус с амплитудой 0.8.
- После FIR (пунктир) — сглаженный сигнал с уменьшенными резкими перепадами (эффект окна 2 отсчёта).
- После усреднения (точки) — первые 10 точек демонстрируют нарастание averaged signal (фильтр «наполняется»), а далее обнуление, так как
conv
обрезается до длины входного сигнала без заполнения краёв.
Почему нули?
Скользящее среднее требует window_size-1
дополнительных отсчётов для полного перекрытия. В коде conv
обрезается строго до длины y_fir
, отбрасывая «неполные» участки свертки — отсюда нули после 10-й точки, нулевые значения после усреднения — артефакт обработки, а не реальное поведение системы. Для потокового усреднения лучше применить DSP.filt(averaging_filter, y_fir)
с сохранением состояния.
s = Float64[]
fir_filtered = Float64[]
avg_filtered = Float64[]
for n in 1:100
x = H()
y_fir = fir_filter(x)
y_avg, filt_state = DSP.filt(averaging_filter, y_fir)
append!(s, x)
append!(fir_filtered, y_fir)
append!(avg_filtered, y_avg)
end
p_signals = plot(t, s[1:n_show], label="Исходный сигнал", linewidth=2)
plot!(t, fir_filtered[1:n_show], label="После FIR", linewidth=2, linestyle=:dash)
plot!(t, avg_filtered[1:n_show], label="После усреднения", linewidth=2, linestyle=:dot)
title!("Сигналы на разных этапах обработки")
xlabel!("Время (с)")
ylabel!("Амплитуда")
Переход на filt
устранил артефакты обрезания, и график теперь отражает истинное поведение системы, а также это позволило создать полностью потоковую систему обработки, где:
- FIR-фильтр (окно 2 отсчёта) плавно сглаживает сигнал (пунктирная линия);
- скользящее среднее (окно 10 отсчётов) теперь корректно обрабатывает весь сигнал без нулей;
- фазовый сдвиг между фильтрами стал предсказуемым, так как оба фильтра работают в потоковом режиме с сохранением состояния.
Вывод¶
Пример наглядно демонстрирует преимущества комбинированного подхода, где системные объекты EngeeDSP используются для потоковой обработки, а традиционные функции – для дополнительных преобразований. Особенно показателен итоговый график, который позволяет отследить изменения сигнала на каждом из этапов модели. Использование системных объектов Engee в сочетании с традиционными методами Julia открывает широкие возможности для создания эффективных и гибких систем обработки сигналов.