Документация Engee
Notebook

Полосовой RC-фильтр для выделения частотного диапазона

В этом примере рассчитывается и проверяется пассивный полосовой RC-фильтр для диапазона примерно от 0.75 кГц до 16 кГц. В скрипте показаны расчет номиналов, построение ожидаемой амплитудно-частотной характеристики, запуск готовых моделей Engee и сравнение сигнальной модели с физической электрической цепью.

Введение

Этот пример описывает ход решения задачи

2W1.2 - Полоса пропускания

из книги

Томас К. Хейс, Пол Хоровиц
Искусство схемотехники: Теория и практика

путем компьютерного моделирования в Engee.

По задаче требуется получить фильтр, который ослабляет слишком низкие частоты, пропускает рабочий диапазон и снова ослабляет высокочастотную составляющую.

Практически такой фильтр можно собрать из двух простых RC-звеньев. Низкочастотную границу задает звено верхних частот, а высокочастотную границу задает звено нижних частот. Важно выбирать сопротивления так, чтобы следующий каскад не перегружал предыдущий.

Теоретическая справка

Для звена нижних частот первого порядка используется передаточная функция

Для звена верхних частот первого порядка:

Если считать каскады слабо связанными по нагрузке, полосовой фильтр описывает произведение:

Граничные частоты каждого RC-звена оцениваются как

В физической модели выходной резистор верхнечастотного звена имеет сопротивление 1 МОм. Поэтому для нижней границы полезно учитывать эквивалентное сопротивление:

Расчет параметров

В этой ячейке задайте сопротивления каскадов, целевые частоты и стандартные емкости. Затем сравните расчетные частоты границ с требуемым диапазоном.

In [ ]:
R_LP = 10_000.0
C_LP = 1e-9
R_HP = 100_000.0
C_HP = 2e-9
R_load = 1_000_000.0

f_low_target = 750.0
f_high_target = 16_000.0

parallel(R1, R2) = 1 / (1 / R1 + 1 / R2)
R_HP_loaded = parallel(R_HP, R_load)

f_lp = 1 / (2pi * R_LP * C_LP)
f_hp_ideal = 1 / (2pi * R_HP * C_HP)
f_hp_loaded = 1 / (2pi * R_HP_loaded * C_HP)

C_LP_exact = 1 / (2pi * f_high_target * R_LP)
C_HP_exact = 1 / (2pi * f_low_target * R_HP)

calculation_summary = (;
    R_LP,
    C_LP,
    f_lp,
    R_HP,
    C_HP,
    f_hp_ideal,
    R_HP_loaded,
    f_hp_loaded,
    C_LP_exact,
    C_HP_exact,
)

calculation_summary
Out[0]:
(R_LP = 10000.0, C_LP = 1.0e-9, f_lp = 15915.494309189533, R_HP = 100000.0, C_HP = 2.0e-9, f_hp_ideal = 795.7747154594767, R_HP_loaded = 90909.0909090909, f_hp_loaded = 875.3521870054245, C_LP_exact = 9.947183943243459e-10, C_HP_exact = 2.122065907891938e-9)

Номинал 1 нФ для звена нижних частот дает верхнюю границу около 15.9 кГц. Номинал 2 нФ для звена верхних частот дает нижнюю границу около 796 Гц без нагрузки и около 875 Гц при нагрузке 1 МОм. Для учебного RC-фильтра это близко к требуемой полосе.

Описание моделей

Для проверки подготовлены две модели Engee.

  • RCBandPass_2W_1_2_signal.engee — сигнальная модель с блоками Transfer Fcn. Она сравнивает идеальную каскадную передаточную функцию и приближение с нагрузкой 1 МОм.
  • RCBandPass_2W_1_2_phys.engee — физическая acausal-модель. В ней источник напряжения питает RC-цепь: сначала стоит звено нижних частот 10 кОм + 1 нФ, затем звено верхних частот 2 нФ + 100 кОм, а на выход подключена нагрузка 1 МОм.

На вход подается сумма трех синусоид: низкая частота 200 Гц, частота в полосе 3 кГц и высокая частота 30 кГц. Такой сигнал помогает увидеть, какие составляющие фильтр подавляет, а какую пропускает.

image.png
image.png

Подготовка окружения

В этой ячейке задайте пути к готовым моделям и папку для файлов результатов. Если вы запускаете пример из другой директории, измените переменную dir.

In [ ]:
using Plots

dir = @__DIR__
output_dir = dir
model_paths = Dict(
    :signal => joinpath(dir, "RCBandPass_2W_1_2_signal.engee"),
    :physical => joinpath(dir, "RCBandPass_2W_1_2_phys.engee"),
)
string("prepared; dir=", dir)
Out[0]:
"prepared; dir=/user/maxim-sidorov/ываропрл"

Окружение готово: модели лежат рядом со скриптом, а новые графики и таблицы будут сохраняться в ту же папку.

Аналитическая проверка

Перед запуском моделей постройте расчетную амплитудно-частотную характеристику. Она показывает ожидаемую полосу пропускания и влияние нагрузки на нижнюю границу.

In [ ]:
freqs = exp10.(range(log10(10.0), log10(100_000.0), length = 800))

gain_bp(f, R_hp) = begin
    tau_lp = R_LP * C_LP
    tau_hp = R_hp * C_HP
    omega = 2pi * f
    (omega * tau_hp) / sqrt((1 + (omega * tau_hp)^2) * (1 + (omega * tau_lp)^2))
end

p_response = plot(
    freqs,
    20 .* log10.(gain_bp.(freqs, R_HP));
    xscale = :log10,
    label = "без нагрузки",
    xlabel = "Частота, Гц",
    ylabel = "Амплитуда, дБ",
    title = "Расчетная АЧХ полосового RC-фильтра",
)
plot!(p_response, freqs, 20 .* log10.(gain_bp.(freqs, R_HP_loaded)); label = "Rн = 1 МОм")
vline!(p_response, [750.0, 16_000.0]; label = "границы задания", linestyle = :dash)
hline!(p_response, [-3.0]; label = "-3 дБ", linestyle = :dot)

response_path = joinpath(output_dir, "rc_bandpass_response.png")
savefig(p_response, response_path)
p_response
Out[0]:

График показывает подъем характеристики после нижней границы и спад после верхней. Нагрузка 1 МОм немного смещает нижнюю границу вверх, потому что она параллельно уменьшает сопротивление выходного плеча верхнечастотного каскада.

Симуляция модели

Теперь загрузите сигнальную модель и запустите симуляцию. Код использует программное управление Engee: engee.load, engee.open, engee.run и engee.close.

In [ ]:
missing_models = [path for path in values(model_paths) if !isfile(path)]

if isempty(missing_models)
    signal_payload = Core.eval(Main, quote
        model = engee.load($(model_paths[:signal]); force = true)
        engee.open(model)
        results = engee.run(model)
        engee.close(model; force = true)
        (; results, result_text = repr(results))
    end)

    signal_results = signal_payload.results
    string("signal model simulated; results=", signal_payload.result_text)
else
    string("missing_models=", join(missing_models, ";"))
end
Out[0]:
"signal model simulated; results=SimulationResult(\n    run_id => 5,\n    \"bp_load_1M.1\" => WorkspaceArray{Float64}(\"RCBandPass_2W_1_2_signal/bp_load_1M.1\")\n,\n    \"input_sum.1\" => WorkspaceArray{Float64}(\"RCBandPass_2W_1_2_signal/input_sum.1\")\n,\n    \"bp_ideal.1\" => WorkspaceArray{Float64}(\"RCBandPass_2W_1_2_signal/bp_ideal.1\")\n\n)"

Сигнальная модель возвращает входной сигнал, выход идеального полосового фильтра и выход приближения с нагрузкой 1 МОм.

Проверка физической модели

Запустите физическую модель. Она проверяет ту же идею как электрическую цепь с источником напряжения, резисторами, конденсаторами, электрической землей, датчиком напряжения и блоком Solver Configuration.

In [ ]:
physical_payload = Core.eval(Main, quote
    model = engee.load($(model_paths[:physical]); force = true)
    engee.open(model)
    results = engee.run(model)
    engee.close(model; force = true)
    (; results, result_text = repr(results))
end)

physical_results = physical_payload.results
string("physical model simulated; results=", physical_payload.result_text)
Out[0]:
"physical model simulated; results=SimulationResult(\n    run_id => 7,\n    \"input_sum.1\" => WorkspaceArray{Float64}(\"RCBandPass_2W_1_2_phys/input_sum.1\")\n,\n    \"vout_sensor.V\" => WorkspaceArray{Float64}(\"RCBandPass_2W_1_2_phys/vout_sensor.V\")\n\n)"

Физическая модель выполнена успешно: выходное напряжение записывается датчиком.

Анализ результатов симуляции

Постройте временные графики сигнальной модели. Они показывают, как из суммы трех гармоник сигнала остается преимущественно составляющая в полосе пропускания.

In [ ]:
function series_from_result(results, key)
    df = results[key]
    return df.time, df.value
end

time, input_signal = series_from_result(signal_results, "input_sum.1")
_, y_ideal = series_from_result(signal_results, "bp_ideal.1")
_, y_load = series_from_result(signal_results, "bp_load_1M.1")

p_time = plot(
    time .* 1000,
    input_signal;
    label = "вход",
    xlabel = "Время, мс",
    ylabel = "Напряжение, отн. ед.",
    title = "Фильтрация суммы трех тонов",
)
plot!(p_time, time .* 1000, y_ideal; label = "идеальная каскадная модель")
plot!(p_time, time .* 1000, y_load; label = "с нагрузкой 1 МОм")

time_plot_path = joinpath(output_dir, "rc_bandpass_time_signals.png")
savefig(p_time, time_plot_path)
p_time
Out[0]:

На выходе меньше влияние медленной составляющей 200 Гц и высокочастотной составляющей 30 кГц. Сигнал в области 3 кГц проходит лучше остальных, поэтому форма становится ближе к среднечастотному гармонике.

Сравнение с физической цепью

Постройте вход и выход физической модели. Этот график нужен, чтобы убедиться, что физическая цепь ведет себя как рассчитанный полосовой фильтр.

In [ ]:
time_phys, input_phys = series_from_result(physical_results, "input_sum.1")
_, vout_phys = series_from_result(physical_results, "vout_sensor.V")

p_phys = plot(
    time_phys .* 1000,
    input_phys;
    label = "вход физической модели",
    xlabel = "Время, мс",
    ylabel = "Напряжение, В",
    title = "Проверка физической RC-цепи",
)
plot!(p_phys, time_phys .* 1000, vout_phys; label = "выход физической модели")

physical_plot_path = joinpath(output_dir, "rc_bandpass_physical_time.png")
savefig(p_phys, physical_plot_path)
p_phys
Out[0]:

Физическая цепь также подавляет низкую и высокую составляющие. Небольшое отличие от идеальной передаточной функции ожидаемо: реальные каскады взаимодействуют через импедансы, а выход дополнительно нагружен сопротивлением 1 МОм.

Сводная таблица

Соберите расчетные показатели в таблицу. Она фиксирует границы полосы и коэффициенты передачи на проверочных частотах.

In [ ]:
case_rows = [
    (case = "ideal", R_hp = R_HP),
    (case = "load_1M", R_hp = R_HP_loaded),
]

summary_rows = [
    (;
        case = row.case,
        f_hp_Hz = 1 / (2pi * row.R_hp * C_HP),
        f_lp_Hz = f_lp,
        gain_200Hz = gain_bp(200.0, row.R_hp),
        gain_750Hz = gain_bp(750.0, row.R_hp),
        gain_3kHz = gain_bp(3_000.0, row.R_hp),
        gain_16kHz = gain_bp(16_000.0, row.R_hp),
        gain_30kHz = gain_bp(30_000.0, row.R_hp),
    )
    for row in case_rows
]

summary_csv = joinpath(output_dir, "rc_bandpass_summary.csv")
open(summary_csv, "w") do io
    println(io, "case,f_hp_Hz,f_lp_Hz,gain_200Hz,gain_750Hz,gain_3kHz,gain_16kHz,gain_30kHz")
    for row in summary_rows
        println(io, join((row.case, row.f_hp_Hz, row.f_lp_Hz, row.gain_200Hz, row.gain_750Hz, row.gain_3kHz, row.gain_16kHz, row.gain_30kHz), ","))
    end
end

summary_rows
Out[0]:
2-element Vector{@NamedTuple{case::String, f_hp_Hz::Float64, f_lp_Hz::Float64, gain_200Hz::Float64, gain_750Hz::Float64, gain_3kHz::Float64, gain_16kHz::Float64, gain_30kHz::Float64}}:
 (case = "ideal", f_hp_Hz = 795.7747154594767, f_lp_Hz = 15915.494309189533, gain_200Hz = 0.2437278406404212, gain_750Hz = 0.6851064392173065, gain_3kHz = 0.9498460237713993, gain_16kHz = 0.704361397337135, gain_30kHz = 0.4684850032871685)
 (case = "load_1M", f_hp_Hz = 875.3521870054245, f_lp_Hz = 15915.494309189533, gain_200Hz = 0.22272201468675978, gain_750Hz = 0.6499191682006742, gain_3kHz = 0.9433569704186011, gain_16kHz = 0.7041789727228396, gain_30kHz = 0.46845041976732643)

Таблица подтверждает инженерную цель: коэффициент передачи около 3 кГц максимален среди выбранных проверочных частот, а частоты 200 Гц и 30 кГц заметно ослаблены.

Заключение

Мы рассчитали и проверили полосовой RC-фильтр для диапазона примерно от 0.75 кГц до 16 кГц. Номиналы 10 кОм + 1 нФ и 2 нФ + 100 кОм дают близкие границы полосы, а нагрузка 1 МОм умеренно смещает нижнюю границу. Сигнальная и физическая модели Engee согласованно показывают подавление низкой и высокой составляющих при прохождении среднечастотного сигнала.

Список литературы

  1. Хейс Т.К., Хоровиц П. Искусство схемотехники. Теория и практика. БХВ-Петербург, 2022. с.130-132
  2. Хоровиц П., Хилл У. Искусство схемотехники. Том 1. Мир, 1993.
  3. Бессонов Л. А. Теоретические основы электротехники. Электрические цепи. Гардарики, 2002.
  4. Седра А., Смит К. Микроэлектронные схемы. Вильямс.
  5. Engee Help Center. Документация блоков Transfer Fcn, Sine Wave, Add, Resistor, Capacitor, Electrical Reference, Controlled Voltage Source, Voltage Sensor, Solver Configuration.
  6. Engee Help Center. Программное управление моделями: engee.load, engee.open, engee.run, engee.close.