Лабораторная 5.7 — BPSK-повышающий дискретизатор символов 8x¶
Цель¶
Вставить явный мост между частотами между BPSK-маппером символов и RRC TX FIR, работающим на частоте отсчётов.
Новый блок принимает один отсчёт Q1.15 на символьной частоте и выдаёт поток 8x с вставленными нулями (zero-stuffing), нужный формирующему фильтру:
BPSK-маппер -> 8x upsampler / zero-stuffer -> RRC TX FIR -> будущий ЦАП / RF-тракт
Исполняемый HDL-пакет¶
| Файл | Назначение |
|---|---|
blocks/block_05_fpga_hdl_flow/rtl/bpsk_upsampler_8x.v |
мост от символьной частоты к частоте отсчётов с SPS = 8 |
blocks/block_05_fpga_hdl_flow/python/generate_bpsk_upsampler_8x_vectors.py |
генерирует детерминированные входные и ожидаемые выходные векторы из общего пакета Блока 11 |
blocks/block_05_fpga_hdl_flow/tb/tb_bpsk_upsampler_8x.v |
самопроверяющийся Verilog-testbench |
blocks/block_05_fpga_hdl_flow/tb/bpsk_upsampler_8x_input_vectors.txt |
сгенерированный поток символов Q1.15 |
blocks/block_05_fpga_hdl_flow/tb/bpsk_upsampler_8x_expected_vectors.txt |
сгенерированный поток отсчётов с вставленными нулями |
Запуск из корня репозитория:
python blocks/block_05_fpga_hdl_flow/python/generate_bpsk_upsampler_8x_vectors.py
iverilog -g2012 \
-o blocks/block_05_fpga_hdl_flow/tb/tb_bpsk_upsampler_8x.out \
blocks/block_05_fpga_hdl_flow/rtl/bpsk_upsampler_8x.v \
blocks/block_05_fpga_hdl_flow/tb/tb_bpsk_upsampler_8x.v
vvp blocks/block_05_fpga_hdl_flow/tb/tb_bpsk_upsampler_8x.out
Ожидаемый результат:
PASS: bpsk_upsampler_8x test completed without errors
Почему этот блок важен¶
Маппер символов и TX FIR по природе работают на разных эффективных частотах:
- выход маппера: один комплексный символ за символьный период;
- вход TX FIR: один комплексный отсчёт за каждый такт FPGA в домене частоты отсчётов.
Без явного блока вставки нулей маппер невозможно подключить к формирующему фильтру в детерминированной RTL-цепочке.
Контракт интерфейса¶
| Сигнал | Смысл |
|---|---|
in_valid |
источник выставляет один комплексный символ Q1.15 |
in_ready |
upsampler может принять следующий символ |
out_valid |
доступен один выходной отсчёт на частоте отсчётов |
out_i, out_q |
первый отсчёт: символ, следующие SPS-1 отсчётов: нули |
Блок держит out_valid высоким на всё 8-отсчётное расширение каждого принятого символа.
Общие входные данные¶
Python-генератор использует:
| Общий файл | Роль |
|---|---|
tx_symbols_q15.txt |
точная последовательность символов из общего пакета BPSK |
config.json |
задаёт samples_per_symbol = 8 |
Чего ожидать¶
PASS: bpsk_upsampler_8x test completed without errors (281 symbols, 2248 samples)
2248 = 281 x 8. Блок вставляет нули: символ выходит на фазе 0, следующие 7 выходных отсчётов это нули, и in_ready опущен на эти 7 тактов. RRC-фильтр из Lab 5.6 превращает эти импульсы с нулями в сформированный сигнал.
Раннер курса генерирует векторы, компилирует, запускает симуляцию и считает ошибкой любую строку FAIL или ненулевой код выхода симулятора:
python tools/run_block5_hdl_smoke.py --test tb_bpsk_upsampler_8x
Упражнения¶
Каждое упражнение ниже: намеренная мутация RTL в одну строку. Внесите её, запустите testbench, прочитайте сообщения и верните файл (git checkout -- <file>). Приведённые выводы получены на Icarus Verilog 12.0.
- Укоротите счётчик на один:
if (phase == SPS - 2). Testbench сообщает 786 ошибок. Первая:out=(32767,0) expected=(0,0) idx=7(следующий символ пришёл на отсчёт раньше), последняя:out_valid=0 expected=1 idx=2247(поток закончился раньше). Ошибка на единицу в счётчике проявляется как периодическое смещение, а не как случайная ошибка. - Почему вставка нулей, а не удержание (повтор символа 8 раз)? Опишите, что удержание делает со спектром до RRC-фильтра.
- При вставке нулей средняя мощность на выходной отсчёт падает в 8 раз. 65 коэффициентов TX в
rtl/bpsk_rrc_tx_fir_taps.memв сумме дают около 2.85 (близко к корню из 8), наибольший коэффициент: 0.387. Объясните, откуда такое масштабирование и какой запас оно оставляет до полной шкалы Q1.15.
Ответы (сверены с RTL и стендом)
- Наблюдаемый вывод приведён в упражнении: счётчик, ошибающийся на единицу, даёт периодическое рассогласование.
- Удержание символа на 8 отсчётов свёртывает последовательность импульсов с 8-отсчётным прямоугольником: спектр умножается на sinc, который проседает по полосе и лишь частично подавляет образы. RRC-фильтр после него формировал бы уже прямоугольно отфильтрованный импульс, поэтому импульс TX перестал бы быть корнем из приподнятого косинуса, согласованный фильтр RX перестал бы ему соответствовать, и появилась бы межсимвольная интерференция. Вставка нулей оставляет образы во весь рост, но целиком отдаёт форму импульса RRC-фильтру, который их и убирает.
- Коэффициенты имеют единичную энергию (
Σ h² = 1,000), поэтому каждый символ несёт ту же энергию, что один отсчёт полной шкалы; их сумма 2,85 ≈ √8: усиление по постоянному току, возвращающее множитель 8, потерянный при вставке нулей. Каждый выходной отсчёт это сумма по одной полифазной ветви, не большеΣ|h[p + 8m]| = 0,55амплитуды символа: около 5,2 дБ запаса до полной шкалы Q1.15 (8,2 дБ над самым большим отводом 0,387).
Лабораторная 5.7b: повышение частоты и TX-фильтр как один полифазный фильтр¶
Нули, которые вставляет этот блок, дальше по тракту не бесплатны: bpsk_rrc_tx_fir их умножает. Для
выходной фазы p (0..7) ненулевой вход встречают только отводы p, p+8, ..., p+64, поэтому
y[8n + p] = sum over m of h[p + 8m] * s[n - m], m = 0..8
rtl/bpsk_rrc_tx_polyphase.v вычисляет именно это: 9 умножителей на канал с коэффициентами,
меняющимися с фазой, регистровое дерево сумматоров, те же округление и насыщение. У него порты пары
(вход символов с in_ready, выход отсчётов), и он проверяется потактово против bpsk_upsampler_8x,
за которым стоит bpsk_rrc_tx_fir:
iverilog -g2012 -o /tmp/tx_pp.vvp \
blocks/block_05_fpga_hdl_flow/rtl/bpsk_upsampler_8x.v \
blocks/block_05_fpga_hdl_flow/rtl/bpsk_rrc_tx_fir.v \
blocks/block_05_fpga_hdl_flow/rtl/bpsk_rrc_tx_polyphase.v \
blocks/block_05_fpga_hdl_flow/tb/tb_bpsk_rrc_tx_polyphase_equivalence.v
vvp /tmp/tx_pp.vvp
PASS: bpsk_rrc_tx_polyphase equals bpsk_upsampler_8x + bpsk_rrc_tx_fir clock for clock (600 symbols, 4800 samples, 0 saturated)
Vivado 2021.1 на xc7z020clg400-2 на 100 МГц (отчёт):
| Реализация | LUT | FF | DSP48E1 | WNS |
|---|---|---|---|---|
bpsk_upsampler_8x + bpsk_rrc_tx_fir |
169 | 2303 | 96 | +3,038 нс (фильтр) |
bpsk_rrc_tx_polyphase |
404 | 541 | 14 | +3,233 нс |
Тот же выход, седьмая часть DSP-блоков и четверть триггеров; лишние LUT: мультиплексоры коэффициентов. Аппаратный TX-тракт сохраняет исходную пару, так что на плате ничего не меняется.
- В проекте 18 умножений (по 9 на канал), а DSP-блоков 14. Синтезируйте его
(
python tools/generate_block5_bpsk_vivado_reports.py --top bpsk_rrc_tx_polyphaseпишет отчёты) и прочитайте «DSP: Preliminary Mapping Report» в журнале синтеза: большинство блоков получает вход B шириной всего 2-3 бита. Куда делась остальная часть каждого коэффициента и чего это стоит в LUT? - Почему согласованный фильтр приёмника в лабораторной 5.8 не может использовать тот же приём и какая структура на приёмной стороне могла бы (подумайте о децимации после согласованного фильтра)?
Чек-лист отчёта¶
- Объяснено, почему граница «маппер: FIR» является многочастотным интерфейсом.
- Показаны тайминги
in_readyиout_validминимум для двух символов. - Указано, что ожидаемый выход: один отсчёт символа и семь нулей.
- Показано, как этот блок питает
bpsk_rrc_tx_fir.vна следующем шаге интеграции.
Шаблон инженерного вывода¶
BPSK-upsampler 8x превращает один отсчёт Q1.15 на символьной частоте в восемь выходных отсчётов на частоте отсчётов.
Это явный мост по времени между маппером символов и RRC TX FIR.
С этим блоком TX-тракт HDL получает детерминированный входной поток на частоте отсчётов для формирования импульса.