电脑上的 MP3,经以太网送进 Zynq-7010,最后变成 FPGA 引脚上的 1 bit 波形,让普通 FM 收音机播放音乐。 数字音乐输入不需要 ADC,RF 输出没有使用多位 DAC。首次桌面实验中,一根杜邦线就让收音机听到了歌声。
已实现 87 MHz、真正立体声、480 Mbit/s 串行输出,包含官方 FIFO/FIR IP、定点 DSP、NCO、OSERDESE2 和 PS 顶层连接。 Vitis Unified 2024.2 的 lwIP TCP → DDR 缓冲 → AXI DMA 音频链路已上板播放 MP3; 修复接收窗口流控后,使用者反馈连续播放没有卡顿。轻微底噪、音量和射频质量仍在改进。 软件用法见 网络音频固件说明,RTL 测量结果见 RTL 验证记录。
版本提示:当前 RTL 音频增益为 1/4,比原 1/8 版本提高约 6 dB。
增益回归已通过,新版 bitstream 已上板;当前硬件交接文件为 xsa/091302.xsa,xsa/091301.xsa 保留原 1/8 版本。
现有射频分离度/SNR 仿真报告也属于原版本,不是新版实测指标。
flowchart TD
A[电脑 MP3 / WAV] --> B[解码为 48 kHz S16LE 双声道]
B --> C[lwIP TCP / PS DDR]
C --> D[AXI DMA / AXIS FIFO]
D --> E[预加重 / 19 kHz 导频 / 立体声编码]
E --> F[FM NCO / OSERDESE2]
F --> G[1 bit RF 输出]
G --> H[FM 收音机]
先按 软件说明 加载匹配的 bitstream、初始化 PS、运行 fm_app.elf 并 Continue。
开发板默认 192.168.2.10/24、TCP 端口 5001,电脑使用同网段地址。
uv run --no-project scripts/send-audio.py --tone 10
uv run --no-project scripts/send-audio.py --file "D:\Music\song.mp3"测试音为左声道 1 kHz、右声道 2 kHz。--file 在电脑上转换音频,支持 MP3;
首次运行 uv 会下载解码依赖。--wav 可直接发送已经准备好的 48 kHz PCM16 双声道 WAV。
- FPGA:Vivado 2024.2,器件
xc7z010clg400-2,打开prj/prj.xpr,顶层fm_top;生成 IP、综合、实现并生成 bitstream。 - PS 软件:Vitis Unified 2024.2(不是旧版 SDK/XSCT 工程流程),从 XSA 创建 standalone Cortex-A9 #0 平台,
加入 lwip220,并使用
vitis/fm_app/src中的源文件。详细域名、参数及 Python API 构建入口见 软件说明。 - 仿真:MATLAB/Simulink R2023b 及文中列出的工具箱。基本 RTL 回归使用 Icarus Verilog;官方 IP 联合仿真使用 Vivado/XSim。
工程来自 Windows 开发环境,Vitis 组件配置和部分历史文档保留原工作区绝对路径。
换目录/换电脑时应重建 Vitis 平台、更新 XSA 路径,不能直接复用缺失的 BSP/export 缓存。
constraints/top.xdc 针对本次接线:50 MHz 输入 K17、复位 M20、LED T12、RF P20/LVCMOS33;其他板卡需重新核对。
目前模拟输出滤波、杂散、时钟抖动和真实射频指标尚未完成测量;桌面能接收不代表成品发射机指标。
原创内容使用 MIT 许可证,第三方组件范围见 NOTICE.md。 参与方式和回归入口见 CONTRIBUTING.md。
87 MHz 真正立体声 FM 发射 RTL:用户通过 Zynq HP + AXI DMA 提供 48 kHz 双声道 S16LE PCM,RTL 接收 32bit AXIS(低 16bit 左、高 16bit 右,带 TKEEP/TLAST)。 详细接线、包语义、时钟、缓冲、立体声编码与验证计划见 RTL 设计文档。 下文仿真操作与参数表仍描述现有单声道参考模型。
FPGA 基础模块优先使用 Vivado IP/XPM(FIFO、时钟、FIR、CDC),不自行重写;Vivado 操作统一使用 synthpilot MCP。 用户最新 DMA 为 32bit AXIS,直接对接音频格式,音频跨域使用 AXIS Data FIFO。 现有时钟和 BD 的核对结果见 BD 对接记录。
1bitFM/
├── simulink/ # MATLAB 源码与可直接运行的 .slx 模型
├── rtl/ # 可综合 RTL 源码
├── tb/ # RTL 仿真测试平台
├── constraints/ # 时钟、引脚与 IO 约束
├── prj/ # 用户创建的 Vivado 工程,入口 prj.xpr
├── xsa/ # 含 bitstream 的硬件交接文件
├── vitis/ # Unified 2024.2 平台配置与 fm_app C 源码
├── scripts/ # 构建、验证与网络音频发送工具
├── tests/software/ # C 固件状态机与 Python 发送工具测试
└── docs/ # FPGA 架构和开发步骤
FPGA 工程使用 Vivado 2024.2,器件为 xc7z010clg400-2,综合顶层为 fm_top。
见 FPGA 开发说明。模型、源码和工程配置纳入 Git;
仿真结果、模型备份、编译缓存及 Vivado 运行产物保留在本机并由 .gitignore 排除。
在 MATLAB 中将当前目录设为本项目根目录,然后运行:
addpath(fullfile(pwd, 'simulink'));
metrics = runFmDemo();首次运行会生成并打开 simulink/fm1bit_tx.slx。已有模型会保留,不会自动重建覆盖。
也可直接打开模型,点击 Run,默认输入为 10 ms 的 1 kHz 测试音。
双击 Audio_scope 查看输入音频和恢复音频,双击两个子系统查看内部信号链。
接收解调随模型运行,频谱绘图与定量验证使用 runFmDemo。
修改源代码后运行 buildFmModel(true) 重建;重建前会备份磁盘模型,且拒绝覆盖尚未保存的模型编辑。
测试自己的音乐片段:
metrics = runFmDemo("F:/audio/music.wav", 0.05);脚本读取文件开头,转为单声道 48 kHz,限制音频带宽至 15 kHz,并限制幅度。完整 RF 仿真每秒产生 4.8 亿个比特,当前入口限定片段为 6–100 ms;这用于波形和频谱验证,不适合整首音乐播放。 输入文件没有自动导出或播放。默认单音测试要求音频相关系数 > 0.98、重建 SNR > 20 dB。
48 kHz PCM → 限幅 → 频率控制字 → 32bit 相位累加 → 最高位 → 1bit RF
顶层:PCM_48kHz → FM_Modulator → FM_Demodulator → Recovered_audio。
FM_Modulator 内部包含限幅和 32bit 相位累加器,输出 RF 比特、频率控制字和限幅后的监测音频。
FM_Demodulator 内部为:87 MHz 复数下变频 → 两级低通抽取至 480 kHz → 相位差鉴频 → 15 kHz 低通抽取至 48 kHz。
本振相位、滤波器状态和鉴频器的前一采样值均跨帧保持,每个 RF 帧恢复一个音频样本。
接收端只接收 RF 比特,不读取发射频率控制字或原始音频。
接收滤波改为因果 FIR 实现,保留启动瞬态;滤波与鉴频的名义延迟为 190.625 微秒,
此外发射音频零阶保持对应约半个音频采样周期的延迟。Scope 显示真实延迟,脚本测量则进行延迟对齐,
并排除首尾瞬态。该指标与旧版离线 filtfilt 接收器的数值不能直接等同。
验证脚本通过独立批量 upfirdn 接收链检查 Simulink 的流式输出,不对模型输出再做解调。
| 参数 | 当前值 |
|---|---|
| 输入 | 48 kHz 单声道 PCM |
| 默认测试音 | 1 kHz,幅度 0.8 |
| 载频 | 87 MHz |
| 满幅频偏 | ±75 kHz(测试音峰值频偏 ±60 kHz) |
| RF 比特率 | 480 Mbit/s |
| 相位 | 32bit、模 2^32 回绕 |
| 帧大小 | 每个音频样本 10000 个比特 |
频率控制字:K = round((fc + deviation * audio) / bitRate * 2^32)。
每个比特先更新相位 phase = mod(phase + K, 2^32),再取最高位。
模型使用整数值 double 精确表示 32bit 状态,避免 MATLAB 原生 uint32 加法饱和;它是算法参考模型,
并非可直接部署的 HDL 架构。帧之间连续保留相位,验证脚本用独立闭式公式逐比特检查。
这里的 1bit 是 FM 方波的两个电平,不是音频 PCM 压缩成 1bit,也不是 Sigma-Delta 调制。 数字音乐文件不需要 ADC;输出端不需要多位 DAC,但实际硬件仍需要合适的输出接口和射频滤波, 用于选择目标频带并抑制谐波。仿真的数字频谱只覆盖第一奈奎斯特区,不包含物理引脚的模拟频谱副本。
simulink/buildFmModel.m:程序化构建模型。simulink/fmNcoFrame.m:写入 MATLAB Function 模块的 NCO 代码;修改后需另行重建模型才能生效。simulink/fmDownconvertFrame.m:连续本振与复数混频。simulink/fmChannelFilterFrame.m:两级多相 FIR 滤波抽取。simulink/fmDiscriminateFrame.m:相位差鉴频。simulink/fmAudioFilterFrame.m:音频低通与抽取。simulink/runFmDemo.m:运行、逐比特及接收参考核对、测量和绘图。simulink/results/fm_demo.png:波形、频谱和解调音频。simulink/results/metrics.json:本次仿真测量。simulink/results/fm_metrics.mat:测量与音频数据,不保存庞大 RF 数据。
依赖:MATLAB、Simulink、MATLAB Function 模块支持、Signal Processing Toolbox、DSP System Toolbox;已检测环境为 R2023b。
按 RTL 设计文档的 M1~M5 推进: AXIS/FIFO/并行 NCO → 双声道定点与立体声编码 → 集成回归 → 串行器和时序验证 → 用户 BD 对接。
上述旧 Simulink 模型仍为单声道;新增 RTL 回归覆盖预加重、立体声复合信号和串行器延迟。 输出模拟滤波器、时钟抖动和 IO 电气特性尚未模拟。 音频 SNR 是理想软件接收链下与对齐输入相比的重建误差指标,不是板级实测指标。
- AMD OSERDESE2 原语
- AMD 7 Series SelectIO 用户指南 UG471
- MathWorks MATLAB Function 程序化配置
- MathWorks 多相 FIR 抽取器
📢 广告位 · FPGA 开发 MCP 插件:synthpilot.dev
