Канал цифровой связи
В этом примере мы демонстрируем цепочку блоков для создания канала цифровой связи. В модели реализованы модулятор, приемный и передающий фильтры для манчестерского кодирования, канал с белым шумом, расшифровка сигнала и подсчет ошибок.
Пример использует возможность Engee работать с моделями, в которых, для отдельных подсистем, задан разный темп симуляции. В этой модели есть подсистемы, работающие с разными частотами:
-
2.5 Гц – частота на “прикладном уровне” модели (генератор порождает числа от 0 до 10)
-
10 Гц – частота потока битов после цифровой модуляции (4-битные пакеты)
-
80 Гц – частота на физическом уровне (биполярный цифровой сигнал и манчестерское кодирование 1 к 8)
На принимающей стороне производится подсчет ошибок, как на уровне чисел, так и на уровне битов.
Структура модели
В модель входят:
-
Генератор чисел от 0 до 10
-
Модулятор, который переводит их в 4-битные последовательности
-
Преобразователь униполярного сигнала в биполярный
-
Цифровой фильтр для применения к сигналу кода Манчестера
-
Канал с добавлением гауссовского шума
И набор обратных операций:
-
Сопряженный принимающий фильтр для кода Манчестера
-
Преобразователь из биполярного сигнала в униполярный
-
Блок подсчета битовых ошибок между отправленным и принятым сигналом
-
Демодулятор, который из каждой группы по 4 бита делает числа от 0 до 10
Общий вид модели
Такая модель позволяет заглянуть в каждую линию связи и посмотреть, что из себя представляет сигнал на каждом этапе передачи.
Запуск модели из скрипта
Для автоматизации анализа нужно закрыть модель (если она открыта на холсте) и запустить эту модель под программным управлением.
# Запуск модели
if "simple_digital_channel" in [m.name for m in engee.get_all_models()]
model = engee.open( "simple_digital_channel" );
else
model = engee.load( "$(@__DIR__)/simple_digital_channel.engee" );
end
results = engee.run( model )
Dict{String, DataFrames.DataFrame} with 9 entries:
"Кол-во ошибок передачи" => 101×2 DataFrame…
"Приемный фильтр" => 801×2 DataFrame…
"Выходной бинарный вектор" => 26×2 DataFrame…
"Входной сигнал и задержка" => 26×2 DataFrame…
"Бинарный вектор" => 26×2 DataFrame…
"Входной сигнал" => 26×2 DataFrame…
"Сигнал в канале" => 801×2 DataFrame…
"Формирующий фильтр" => 801×2 DataFrame…
"Реконструкция сигнала" => 26×2 DataFrame…
#engee.close( "simple_digital_channel", force=true );
Вывод графиков
Подключение библиотек
# Подключение библиотек
using DataFrames, Plots, Measures
gr(); # Подключение бэкенда - метода отображения графики
Анализ информации на входе и выходе (ряд чисел)
# Загрузка данных
Sin = results["Входной сигнал и задержка"];
Sout = results["Реконструкция сигнала"];
# Построение графиков
plot(
plot( Sin.time, Sin.value, st=:step, xlabel="Время", ylabel="Числа", title="Числа на входе", leg=false ),
plot( Sout.time, Sout.value, st=:step, xlabel="Время", ylabel="Числа", title="Числа на выходе", leg=false ),
layout=grid(1, 2, widths=(4/8,4/8)), size=(900,300), margin=5mm, guidefont = font( 7 )
)
Анализ битовых массивов на входе и выходе
# Загрузка данных
Bin = results["Бинарный вектор"]
Bout = results["Выходной бинарный вектор"]
Bin_a = [v[1] for v in Bin.value]
Bin_b = [v[2] for v in Bin.value]
Bin_c = [v[3] for v in Bin.value]
Bin_d = [v[4] for v in Bin.value]
Bout_a = [v[1] for v in Bout.value]
Bout_b = [v[2] for v in Bout.value]
Bout_c = [v[3] for v in Bout.value]
Bout_d = [v[4] for v in Bout.value]
# Построение графиков
plot(
plot( Bin.time, [Bin_a Bin_b.+1.1 Bin_c.+2.2 Bin_d.+3.3], st=:step,
xlabel="Время", ylabel="Биты", title="Входной массив", leg=false ),
plot( Bout.time, [Bout_a Bout_b.+1.1 Bout_c.+2.2 Bout_d.+3.3], st=:step,
xlabel="Время", ylabel="Биты", title="Выходной массив", leg=false ),
layout=grid(1, 2, widths=(4/8,4/8)), size=(900,300), margin=5mm, guidefont = font( 7 )
)
Отобразим количество ошибочно принятых битов
# Загрузка данных
ERC = results["Кол-во ошибок передачи"]
# Построение графиков
plot(
plot( ERC.time, ERC.value, st=:step, xlabel="Время", ylabel="Сигнал", title="Количество ошибок приема", leg=false ),
size=(900,400), margin=5mm, guidefont = font( 7 )
)
Изучим шум в канале
# Загрузка данных
Fin = results["Формирующий фильтр"];
AWGN_out = results["Сигнал в канале"];
Fout = results["Приемный фильтр"];
# Построение графиков
plot(
plot( Fin.time, Fin.value, st=:step, xlabel="Время", ylabel="Сигнал", title="Сигнал из формирующиего фильтра (идеальный)", leg=false ),
plot( AWGN_out.time, AWGN_out.value, st=:step, xlabel="Время", ylabel="Сигнал", title="Сигнал в канале (с белым шумом)", leg=false ),
plot( Fout.time, Fout.value, st=:step, xlabel="Время", ylabel="Сигнал", title="Сигнал после принимающего фильтра", leg=false ),
layout=grid(3, 1),
size=(900,600), margin=5mm, guidefont = font( 7 )
)
Вывод
На основе этого примера можно рассчитывать параметры избыточности кодирования, проверять коды коррекции ошибок или проверять работу канала связи на физическом уровне с другим кодированием сигнала: частотным, фазовым, сделать канал частью виртуального стенда и многое другое.
Платформа Engee позволяет очень наглядно продемонстрировать работу цифровой электроники, подбирать параметры и отлаживать алгоритмы и подкреплять все наглядными иллюстрациями.