基于FPGA的Remote ID GMSK调制解调链路设计与实现
2026/9/17 3:11:49 网站建设 项目流程

最近刚把一个Remote ID的调制解调链路完整跑通,从方案评估、RTL编写到板级空口联调,前后花了差不多两个月。这个项目不是要把整个BLE协议栈塞进FPGA,核心就聚焦在物理层的调制解调:把Remote ID规定的比特流,经过GMSK/GFSK成形、DDS上变频、DA输出,变成2.4GHz的射频信号发出去;接收端再用FPGA独立完成下变频、同步、差分解调和CRC校验,把报文恢复出来。Remote ID这类远程识别应用,目前国内实际落地的大部分广播都走2.4GHz蓝牙信道,调制方式就是GFSK,调制指数0.5、BT=0.5,所以FPGA实现的重点也是这个物理层。这篇文章把我从方案选型到调试踩坑的完整路径写下来,给正在做GMSK调制解调、FPGA通信链路或者想搞懂Remote ID物理实现的人做个参考。

1. Remote ID项目概况与调制解调方案选型

1.1 Remote ID到底在传什么

Remote ID直译过来是远程识别,用在无人驾驶航空器上,要求飞行器在飞行过程中主动广播自己的身份和位置信息。地面人员用手机、专用接收器或者固定监测节点,就能知道周围是谁在飞、从哪里起飞的、当前在哪个位置、速度高度怎么样。过去无人机一多,地面很难判断哪一架是谁的,出个意外也找不到机主;Remote ID就是为了解决这个识别问题。

从协议栈看,Remote ID属于应用层消息,广播的数据内容一般包括:

  • 运营商分配的飞行器ID或ICAO地址
  • 当前经纬度、海拔高度
  • 水平速度、垂直速度、航向
  • 飞行状态(自动飞行、悬停、降落等)
  • 电池电量等可选扩展信息

这些消息按固定周期广播,比如每秒1到5包。地面接收设备只要在有效距离内,就能把消息解出来。传播距离跟发射功率、天线增益、接收灵敏度和环境遮挡都有关系,一般要求几百米到一公里以上能可靠收到。

在物理层,很多标准的Remote ID广播方案走的是2.4GHz蓝牙广播信道,尤其是BLE 5.0的扩展广播,包可以发的更长、数据速率和调度也更灵活,而且手机内置BLE接收器直接就能解,不需要额外专用终端。这就给调制解调模块提了一个明确需求:得做一个能在2.4GHz频段发送和接收GFSK/GMSK信号的物理层。

1.2 调制方式选型:为什么是GFSK/GMSK而不是别的

做调制解调方案选型的时候,我对比过好几种方式,包括MSK、GFSK(严格说GMSK是h=0.5的GFSK)、QPSK和OFDM。Remote ID这个场景有几个特点:单包数据量不大、要求接收设备普及、发射端往往是电池供电的小型无人机。这几个特点决定了调制方式不能太复杂、峰均比不能太高、频谱效率够用就行。

GFSK/GMSK的优势正好覆盖这些点:

一是恒包络。GFSK/GMSK是频率调制,信号幅度恒定,对发射端的功率放大器线性度要求很低,可以工作在饱和区,效率高,适合无人机这种对功耗敏感的设备。

二是接收端兼容性好。BLE用的就是GFSK,手机芯片天然支持,地面接收不需要额外硬件。如果选OFDM这类调制,手机端是解不了Remote ID专用信号的。

三是实现复杂度适中。GFSK/GMSK不用做信道估计和均衡,差分解调在FPGA里实现非常省资源,同步算法也比QPSK/OFDM简单几个量级。

做个小对比,我当时是这么梳理的:

调制方式峰均比抗噪性能FPGA资源接收端兼容性适不适合Remote ID
MSK一般适合,但频谱滚降差
GFSK/GMSK好(BLE就用的它)非常合适
QPSK中等一般,非主流方案
OFDM不适合,功耗和复杂度太高

最终结论很直接:走BLE广播兼容路线,物理层调制方式就是GFSK,调制指数0.5,BT=0.5。

1.3 为什么用FPGA做调制解调

Remote ID的调制解调用FPGA,有人会觉得大材小用,毕竟BLE的GFSK调制解调一个几块钱的BLE SoC就能做。但项目场景不一样,我们做的是可重构的协议验证平台和信号级测试设备,不仅要支持Remote ID标准现有方案,还要能快速改调制参数、改包格式、验证新的广播方案。

FPGA在这里面有几个不可替代的优势:

第一是并行多通道。FPGA可以同时做多路接收,比如一个FPGA芯片里放8个并行的解调器,同时解8个不同频点的Remote ID信号,这个用MCU很难做到,用多颗BLE SoC又贵又难同步。

第二是时序确定性和低延迟。调制解调链路全在硬件里跑,延迟恒定,适合做对时间敏感的测试设备和信号采集分析系统。

第三是可观测性和可重构性。在FPGA里调试,中间信号随便拉出来看,ILA一抓就是真实的比特波形;算法参数改一下重新综合下载就完事。相比流片或者改ASIC,周期短得多。

所以这个项目里FPGA扮演的角色,更接近一个开放物理层平台:上行做发射信号生成,下行做全数字接收机,中间所有算法和协议细节全部可控。

2. 发射链路设计:从比特流到GMSK射频信号

2.1 发射链路整体架构与比特处理流程

发射链路要回答的问题是:Remote ID的原始消息,怎么变成一路标准的GFSK射频信号?我用的架构分成三段:比特处理、GMSK调制、上变频输出。

完整的数据流是:

Remote ID消息 → CRC校验计算 → 白化 → 高斯成形滤波 → 相位累加器 → DDS查表生成IQ → 插值滤波 → DA转换 → 射频前端 → 天线

为什么中间要插白化这一级?这是很多人容易忽略的。GFSK是频率调制,如果数据流里出现连续的0或者连续的1,那么发送端频率会持续停在一个偏移位置上,接收端做数据判决和定时恢复时,很容易因为长时间没有跳变而失锁。白化就是用伪随机序列把原始比特打散,让发送出来的符号序列尽量均衡地出现0和1变化。BLE用的白化LFSR是x^7+x^4+1这个多项式,初值0x7F。在白化这件事上要注意:发送端白化的方向和数据位序,必须和接收端解白化完全对应,有一点点不对,后面CRC100%过不了。

CRC也是链路层必须的一环,用来在接收端判断这一包数据有没有被破坏。我们用的CRC格式跟BLE广播帧保持一致,24位CRC,多项式0x000065B,初值0x555555。这种CRC在FPGA里可以用线性反馈移位寄存器搭,也可以查表,但查表在高速率下更省时序。

2.2 高斯成形滤波与GMSK调制器实现

这里应该是整个发射链路技术含量最高的地方。GMSK和普通FSK的区别,在于进调制器之前,矩形比特流要先通过一个高斯低通滤波器。高斯滤波器把原本陡峭的矩形脉冲变成平滑的连续波形,这样VCO/NCO的频率变化就不是突跳的,而是连续缓慢变化,从而压缩了信号带宽。

高斯滤波器的频率特性由B和T的乘积决定,也就是BT因子。BT=0.5表示高斯滤波器的3dB带宽等于符号速率的0.5倍。Remote ID用的符号速率是1Msps,T=1μs,所以B=500kHz。BT越小,频谱越窄,但符号间干扰越重;BT越大,越接近普通FSK,频谱宽。BLE选择BT=0.5是个折中,既满足频带要求,解码复杂度也可控。

FPGA实现高斯成形滤波,我用的是ROM查表法,这也是工程里最常见的做法。基本原理是:把输入比特序列和一个固定长度的高斯脉冲做卷积,由于输入是二值的,卷积结果可以预先算好存到ROM里,按比特序列索引直接查出来。具体来说,我存储了256个点的高斯响应系数,ROM深度随意,能覆盖若干个符号周期就行,输出有符号数,位宽设置成12bit。

高斯滤波器的输出还要转成相位。这里有一个非常关键的设计选择:相位累加器必须放在DDS之前,并且用累加的方式生成瞬时相位。原因很简单,GMSK是连续相位调制,相位不能有突变,如果直接用频偏去控制载波,每切换一个符号就跳一次频率,带宽会瞬间展宽好几倍。正确做法是:

瞬时频率 = 高斯滤波输出 × 最大频偏 瞬时相位 = 对瞬时频率做积分 IQ输出 = cos(瞬时相位)和sin(瞬时相位)

最大频偏的计算:GFSK的峰值频偏fd与调制指数h、符号速率Rb的关系是fd = h×Rb/2。h=0.5、Rb=1Msps时,峰值频偏正好250kHz。这个值很重要,NCO频率控制字就是按它算的。

我在系统时钟64MHz下做了个32位累加器,输出频率的频率控制字:

freq_word = 期望频率 / 系统时钟 × 2^32 = 250kHz / 64MHz × 2^32 = 16,777,216 = 0x01000000

这个数算出来刚好是0x01000000,非常规整,调试的时候很容易验证。实际运行时,频率控制字是正负变化的:高斯滤波输出为正值时,累加器往加的方向走,频偏为正;滤波输出为负值时,频偏为负。相位累加器和后面的正余弦查找表构成了一个标准的DDS,输出就是I/Q两路中频或基带信号。

最后一级是插值滤波,把1Msps的符号率插到64MHz系统时钟率上,我是用三级CIC插值加一级补偿FIR实现的,插值率64。CIC实现插值非常省资源,三个积分器加三个梳状滤波器就完事,缺点是通带不够平,后面接一个反sinc补偿滤波器就能拉回来。

2.3 数字上变频、DA输出与模拟前端衔接

FPGA里DDS出来的IQ信号,如果是零中频方案,直接给DA转换器转成模拟的I/Q基带信号,然后送进来的外置正交调制器或者RF收发芯片上变频到2.4GHz。我当时的做法是让FPGA输出I/Q到AD9361这类射频收发前端,它的内部直接完成从基带到射频的上变频,寄存器配置通过SPI接口完成,FPGA只负责给数据和时钟。

这里要特别提醒一个坑:DA输出和射频前端的时钟必须同源,否则I/Q信号和本振之间会有慢速频率漂移,解调端看到的星座图会转圈。最简单的做法是让射频前端的主时钟PLL锁定到FPGA送来的参考时钟上,或者在FPGA内部直接用射频前端反馈回来的时钟做同步设计。

发射端调完,拿频谱仪看信号,第一眼看的是频谱模板。GMSK的频谱应该是平滑、左右近似对称的单峰,如果看到频谱宽度明显超标,多半是高斯滤波器截断长度不够或者BT参数配错;如果看到频谱上有杂散,检查时钟和DA数据对齐。

3. 接收链路设计:同步解调与Remote ID消息恢复

3.1 接收机架构与数字下变频

接收链路比发射复杂得多,因为信号到了接收端,既不知道载波频率偏差多少,也不知道每个符号的边界在哪。Remote ID接收用的架构和发射端镜像对称:天线进来以后,射频前端完成低噪声放大和下变频,把2.4GHz信号变成正交的I/Q基带信号,ADC采样后送进FPGA。ADC的采样率我们选了64Msps,这样相对于1Msps符号率有64倍过采样,给后面同步和时钟恢复留了足够裕量。

FPGA内部第一级是数字下变频,本质就是一个数字混频器。如果射频前端输出已经是零中频基带,那FPGA内部只需要做低通滤波和抽取。抽取不是随便抽的,直接每64个点留一个会混叠,必须先用抗混叠滤波器过滤掉带外噪声。我用的方案是CIC抽取加半带滤波器级联,抽取率64一路抽到2Msps,也就是每个符号2个采样点。这个2倍过采样的位置正好是后面定时恢复算法最舒服的工作点,再多过采样对性能没本质帮助,白白浪费资源。

3.2 定时同步、频偏校正与差分解调实现

接收端的核心难点全在同步。先说载波频偏。无人机在飞,收发双方晶振也有误差,即使标称都是2.4GHz,实际频率偏差几十到一两百kHz都很常见。GFSK本身是频率调制,频偏直接叠加在信号上,如果不处理,判决会偏向一边,误码率立刻升高。

工程上最实用的方法是差分解调。差分解调的思想:GFSK信号的信息承载在相邻符号的相位变化上,而不是绝对相位上。调制的每个符号相对前一个符号累计的相位是+90度(符号为1)或者-90度(符号为0)。接收端只要把两个相邻符号的相位相减,正负就能判断0/1。它的好处是绝对载波相位不需要知道,天然免疫静态相位偏移。

但是差分解调不能完全不管频偏。假设本地载波和发送载波有Δf的偏差,那么每个符号的相位差会额外叠加2π×Δf×T这么多,对1Msps符号率来说,100kHz频偏就给每个符号带了约36度的额外相位偏移,这会直接覆盖正常的90度相位差。所以必须有频偏估计和补偿。

频偏估计怎么做?发射端的前导码是0101交替的重复序列,在交替码型下,正常符号相位差是恒定的。接收端把一段前导码的差分相位取平均,平均值和理论值的偏差就对应频偏。如果长时间平均算出来平均差分相位是120度而理论应该是90度,那额外的30度就是频偏造成的,换算成频率就是Δf=30/360×1MHz≈83kHz。估计出来后在混频器后端加一个NCO补偿掉。

定时同步我用的Gardner算法。Gardner算法是一种非数据辅助的定时误差检测,它利用每个符号的过零点和中点采样来计算定时误差,误差信号经过环路滤波器,再控制一个插值器,把采样点调整到最佳判决时刻。简单说,Gardner算法去找每个符号波形变化最剧烈的点,让采样点稳定在那附近。经典误差计算公式:

e(k) = I(k-1/2)×[I(k)-I(k-1)] + Q(k-1/2)×[Q(k)-Q(k-1)]

这里I(k-1/2)是符号中间的采样点,I(k)和I(k-1)是相邻符号的判决点。误差通过二阶环路滤波(比例+积分结构)后,反馈给插值滤波器。我调试时把环路带宽设置在1kHz到2kHz之间,太低环路锁定慢,太高容易在低信噪比下抖。如果频偏比较大,先让AFC把频偏粗调进入几十kHz以内,再开启Gardner定时环路,否则环路很难收敛。

3.3 帧同步、去白化与CRC校验恢复消息

解调出比特流以后,还不能直接交给上层软件,因为FPGA解出来的是一堆连续的符号串,连包的边界在哪里都不知道。帧同步干的事就是在比特流里找包头的起始位置。

Remote ID广播帧一般在包头放了一段固定的接入码或者同步字。接收端用滑动相关器在解调比特流里搜索这个固定序列,32比特接入码在FPGA里实现一个32位的相关器很简单,把硬判决后的数据流一路打拍,和已知序列做逐位异或再加总,相关值大于一个门限就判定捕获到包。如果32比特全部一致,相关峰会出现一个非常尖锐的尖峰;如果因为频偏或噪声产生个别误码,相关峰会下降,门限要选择合适的值,通常取22到26位匹配就能触发。

捕获到帧头之后,按已知的包格式把载荷部分切出来。这时要还原的事情正好是发射端的逆过程:先对载荷比特做了解白化,LFSR初值、生成多项式都和发射端一样,然后做CRC校验,用同样的CRC多项式把收到的载荷重新算一遍CRC,和包尾带的CRC比对,一致说明整包无误。到这里,一条Remote ID消息就算完整从射频信号恢复成了可读的比特数据,再交给上层软件解析成经纬度、高度这些业务字段。

整个接收链路的FPGA资源占用不高,差分解调加定时环路加相关器,加起来不超过2000个ALM,在Cyclone V级别的中端器件上非常轻松。这也是为什么一个FPGA里可以放多路并行解调器的原因。

4. 系统联调、性能验证与实测指标分析

4.1 测试环境搭建与交叉验证思路

项目推进到联调阶段,我建立了三套测试环境,分别解决不同层面的验证问题。

第一套是纯板级自发自收。一个FPGA板子同时跑发射链路和接收链路,发射基带信号在FPGA内部直接环回给接收端,不经过射频。这种方式能快速验证协议栈和基带算法逻辑是否正确,特别是CRC、白化、帧同步这些数字逻辑有没有bug。缺点是射频链路上的噪声、频偏、多径都没有被覆盖到。

第二套是射频空口对打。一块板子发,另一块板子收,两块板用线缆直连或者通过天线在空中传输。这个场景最接近真实使用环境,但问题定位也最难,一旦误码,是要查发射端还是接收端,需要借助频谱仪、误码仪配合看。

第三套是信号采集回放。用矢量信号源把调制好的GFSK信号录下来,叠加不同信噪比、频偏、多径参数,再灌给FPGA接收板,用来测试接收灵敏度和边界性能。这套环境最大的价值是可重复——同一个信号样本反复灌,调整不同算法参数对比效果,非常方便。

交叉验证方面,我特意买了两款不同的BLE接收设备,一个是手机蓝牙抓包工具,一个是支持BLE broadcast的接收器模块。用我们FPGA发射板定时广播Remote ID消息,这两款独立设备都能正确解码出消息里的ID和经纬度,就说明发射端物理层和协议层是符合业界兼容标准的。

4.2 关键性能指标实测

联调完成后我做了系统性的指标测试,整理了几个对Remote ID物理层最重要的指标:

指标设计目标实测结果结论
调制指数0.45~0.550.49通过
峰值频偏250kHz246kHz通过
发射频谱模板跳变平滑满足模板通过
接收灵敏度(1%PER)优于-90dBm-93dBm通过
接收动态范围大于60dB70dB通过
广播周期200ms稳定200ms通过

接收灵敏度是卡得比较严的一项。BLE/GFSK在1Msps速率下理论灵敏度能做到-95dBm左右,我们实测到-93dBm附近达到1%丢包率,和理论值已经很接近。中间发现影响灵敏度最大的因素不是算法本身,而是ADC输入端的增益分配:射频前端增益开得太大,带内噪声一起放大,信噪比反而下降;增益开得太小,量化噪声占主导。花了几天时间把自动增益控制的起控点调到-70dBm,全动态范围性能才平稳下来。

另外一个值得说的指标是邻道干扰抑制。GFSK的频谱比OFDM的矩形频谱宽一些,邻道的信号容易漏进来。我第一版接收滤波器带宽设计得偏窄,邻道抗扰好了,但带内有用的信号也被削掉一部分,灵敏度掉了有2dB。后来把接收滤波器参数改成根升余弦和抗混叠级联,灵敏度回到-93dBm的同时,邻道抑制也满足需求。

4.3 多通道与多广播场景扩展验证

Remote ID的调制解调平台用到真实场景,经常要同时接收多架无人机。多通道能力是FPGA方案相对其他实现的最大优势。

我在这块板子上实现了4路并行的接收解调链路,每路独立配置接收频点和灵敏度。实现过程中发现资源不是瓶颈,时钟树才是。4路解调器每个都有自己的NCO、插值器和相关器,摆在同一个FPGA里,如果每路都用独立时钟,时钟管理器很快就用完了。后来我把4路接收统一挂在同一个64MHz时钟域下,每路只做不同的数字混频频率,也就是用一个基带解调器,配合4个不同频率的NCO把信号分到不同通道里。这个架构更像一个小的并行频谱监测器,既省资源又稳定。

多通道联调时还出现过一个问题:4路同时工作后,FPGA功耗上升,局部门控时钟的时序余量变小,偶发出现解调结果突然翻转。后来在布局布线层面把4路接收分散到不同的时钟区域,并打开了物理综合的优化选项,问题就消失了。这种问题在单通道验证阶段根本不会暴露,必须做多通道压力测试才能发现。

5. 调试现场实录:踩过的坑与排查技巧

5.1 白化方向不对导致CRC永远不过

这个坑让我印象很深刻。第一版发射接收联调的时候,发送端自己给自己发,看到信号频谱正常、星座图正常、相关器也能稳定触发,但CRC永远校验失败,收到的包内容稳定地错误,而且错得很有规律。

排查过程持续了两天。先用ILA在FPGA内部对比发送端和接收端的比特流,发现接收端解出来的payload和发送端对比有固定的比特偏移。这个特征指向两种可能:要么帧同步位置找错了,要么解白化方向反了。帧同步位置我用人工构造的固定测试包验证过没问题,那就只剩白化了。

后来逐位比对发射端白化和接收端解白化的时序关系,发现我在接收端用的是正向LFSR生成器,而发射端白化时用的是反向抽取。一个LFSR按位输出和按字节输出,数据流向完全不同,如果接收端按字节反序去解白化,结果就是整体错位。修正后CRC立刻全部通过。这个案例给我的教训:链路层实现的时候,收发两端的白化、CRC位序这些“规格参数”一定要在一开始就用表格对照清楚,不要靠猜,也不要自然以为“一样”。

5.2 高斯滤波截断长度与邻道泄漏的平衡

GMSK高斯滤波器的冲激响应理论上是无限长的,FPGA里不可能存无限长,必须截断。截断长度和邻道泄漏是一对矛盾:截断太短,高斯脉冲的尾部被砍掉,等效滤波器频率响应出现肩峰,频谱旁瓣变大,邻道泄漏超规;截断太长,滤波输出延迟变大,ROM容量和乘法器资源都上涨。

我测试下来,BT=0.5的GMSK,高斯响应截断到±2个符号周期附近是底线,这时候邻道泄漏大概能控制在-50dBc以下;如果要求更严格,考虑截到±3个符号周期。再往上加,改善非常有限,资源开销倒是翻倍。工程上把两组结果摆出来量化比较,无论是做标准测试还是做产品,都有说服力。

5.3 载波频偏与时钟漂移:环路参数怎么调

接收端最容易翻车的场景是:把发射端和接收端分开放,两套板子各自的晶振都有±20ppm偏差,2.4GHz频点下相当于±48kHz的频偏;如果无人机在高速运动,多普勒效应再加几kHz。这个量级的频偏,单纯靠差分解调里的AFC慢环路跟踪是不够的。

实际操作中我把频率同步分了两步:第一步是频率粗捕获,在前导码阶段用很短的时间窗口做快速频偏估计,把大频偏一次性拉到十几kHz以内;第二步是频率精跟踪,用判决反馈环路持续校正剩余频偏。环路带宽的选择有一个经验法则:粗捕获环路带宽可以设到几十kHz,锁定速度很快;精跟踪环路的带宽要压到1kHz左右,否则会把噪声一起带进来,误码率反而升高。用这个两段式频偏同步结构,接收机能容忍的频偏范围从±10kHz扩展到了±120kHz。

5.4 调试效率:仿真、ILA与自动化测试

最后分享几个提高FPGA调制解调调试效率的技巧。

第一,仿真测试永远比上板测试快。调制解调链路所有模块都可以写成可综合RTL,同时也建立一套对应的仿真testbench,用真实波形激励灌进去跑。像Gardner环路收敛、AFC频偏校正这些算法层面的问题,在ModelSim/QuestaSim里用几万行仿真波形足以验证清楚。我整个项目下来,90%的算法bug是在仿真阶段解决的,真正上板后才暴露的都是接口和时序问题。

第二,ILA抓信号是物理层调试的利器。FPGA内部信号对外的IO一般不会引出来,用了ILA相当于在芯片内部放了一个逻辑分析仪。我调试接收链路时,把时钟恢复插值器的输出、相关器峰值、环路滤波器误差信号都挂到ILA上,一次抓512个样本,能直接看到信号在时域里的形态。那个CRC不过的问题,就是靠对比ILA里收发同步字位置定位出来的。

第三,学会做自动化批量测试。单次测试只能覆盖一个频点和一组参数。修完一个问题,参数换一组继续跑,手动操作不仅慢还容易漏。我写了一套简单的Python脚本,通过JTAG和上位机通信,自动切换发射功率、频偏和信噪比,批量跑误码率测试,结果直接生成表格对比。这套自动化环境帮我在最后一周内完成了上百组回归测试,把好几种边界场景的性能摸得很透。

最后再分享一个我对做这类项目的心得:Remote ID的调制解调FPGA实现,难点从来不是某一个单独模块,而是发射和接收两端所有细节的循环咬合。白化、CRC、同步、频偏补偿,任何一处差了一样,整个消息就解不出来。做的时候不要追求一步到位,把每一级模块单独验证通过后再联调,出问题的时候,先用最简单的数据样本去缩小范围,再逐步加真实数据,这是最稳妥的路子。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询