☰
电赛A题调制度测量装置:AM/FM量程边界与误差控制
2026/10/30 3:08:20 网站建设 项目流程

简介:这份代码包围绕2021年全国大学生电子设计竞赛A题“信号失真度测量”展开,面向电赛备赛者、MSP430F5529嵌入式学习者及需要信号采集与失真分析参考的开发者。方案以MSP430F5529为主控,完成信号采样与失真度计算,并借助NRF24L01无线模块把结果发送到手机端显示,曾获省级一等奖,适合借鉴基础功能实现、模块联调与工程组织方式,也能据此复现主控程序、无线收发和显示交互等模块。压缩包共990个文件、约31.58MB,涵盖C/H源码、Keil工程与配置文件、编译中间文件、HEX烧录文件以及无线模块相关资料,可帮助读者还原完整工程结构、梳理ADC采样与频谱分析流程,并排查编译、下载和通信环节的问题。目前已有4031人学习,对需要赛题代码框架和移动端结果显示思路的读者具有较高参考价值。

1. 电赛A题:调制度测量装置里,最容易翻车的不是算法而是量程边界

电赛A题这道调制度测量装置,翻车点常常不在算法,而在量程边界。调制度 10% 的调幅波,边带幅度只有载波的二十分之一,换成示波器几乎看不见;调制度拉到 90%,包络又贴到零,任何一点底噪都会让谷值判错。2021 年这道题把调幅波调制度、调频波调频度、载波频率、调制频率四个量塞进一台装置,基本要求考的是精度守不守得住,发挥部分比的是小调制度、弱信号下读数稳不稳。它考的不是谁会调库,是谁能把整条测量链路从头讲到尾——这也是测评现场被追问最多的地方。适合已经能跑通 FFT、但读数一到边界就飘的人。

2. 考点拆解:四个测量量与评分表上的权重分布

2.1 基本要求与发挥部分,哪些指标必须一次测准

这类题目的指标写法很固定,一般拆成三件事:测什么量、在什么范围内测、允许多大误差。基本要求通常给调制度一个百分比范围,给载波频率一个频段,给调制频率一个音频范围,再对每个量给出绝对误差上限;发挥部分往上加小调制度、多音调制、自动区分调幅与调频这些花样。

评分逻辑要提前想明白:绝大多数测评是按测点独立计分,不是按误差比例扣。你在量程中段测得再漂亮,只要量程两端的测点超差,那几分就是零。所以时间分配上,宁可少做一个发挥项,也要把基本要求的上下边界各测三遍确认。

还有几条容易被忽略的隐性要求:装置要独立工作,不能靠外部仪器辅助读数;单一电源供电;显示要能分辨到最后一位有效数字。这些不加分,但做不到会直接判"功能不完整"。

提示:拿到题面第一件事不是画框图,是把所有"范围 + 误差"抄成一张表,标出哪些是边界测点。测评老师就是照这张表一个个测过去的。

2.2 定义式与耦合关系:为什么 ma 和 fc 不能各测各的

调幅波的写法是载波乘一个随调制信号起伏的包络,调制度 ma 的经典定义是包络最大值与最小值之差比上两者之和,等价的频域写法是"两倍边带幅度除以载波幅度"。调频波则是载波相位里塞进一个积分项,调频度 mf 等于最大频偏除以调制频率。

两个定义放一起看,耦合关系就出来了。测 ma 要先知道载波频率 fc,才能做数字下变频、把包络取干净;测 mf 要先知道调制频率 fm,才能把测到的频偏换算成无量纲的调频度。四个量是链式的,前一级歪一点,后面全跟着歪。

这也是为什么"先粗测频率、再做解调、最后算比值"这个顺序不能反。反过来做,等于在未知载波位置的频谱上瞎找边带,找错了还以为是算法有问题。

采样环节还有一条岔路要选:直接采样要求采样率至少四倍载波,短波段下这个数字不低;带通采样让载波混叠到一个中频上,采样率可以降下来,但必须算清楚混叠后的频率落在哪,否则后面所有频率都是错的。

2.3 现场排序题:先测哪个量,思路怎么讲

测评时很爱问的一道题是:"如果只允许你先测一个量,再拿它推其他三个,你选哪个?"

标准答法是选载波频率,理由要讲三层。第一层,fc 在频谱上是全局最大峰,信噪比最好,最容易一次测准;第二层,有了 fc 才能做数字下变频,把调幅波的包络和调频波的瞬时频偏解出来,这是后面一切的前提;第三层,fc 定了,fm 才有地方找——调幅波去包络谱里找,调频波去瞬时频率谱里找,搜索范围直接从全频段缩到音频段。

再加一句"比值量优先"的原则会更稳:凡是能化成两条谱线幅度之比的量,就别用绝对幅度。前端放大器增益随温度飘、滤波器通带不平,这些误差在比值里直接抵消,在绝对值里一分不少全留下来。

追问如果接一句"fc 估偏 1% 会怎样",答法是把影响分开说:调幅波这边,下变频残留的载波会被低通滤掉大半,ma 的偏差很小;调频波这边,相位差分直接把频率误差带进瞬时频偏,mf 会明显偏。所以调频通道对 fc 的精度要求比调幅通道高一个档。

3. 高频考点:AM 调制度 ma 的三条路线与选型答辩

3.1 路线一:下变频加包络检波,峰值谷值法

最直观的做法是先数字下变频,把载波搬到零频,低通滤掉高频分量,剩下的复信号取模就是包络,再从包络的峰谷算 ma。

直接对原始采样做希尔伯特变换取模也能得到包络,但包络上会叠一层载波频率的纹波,取最大值时很可能取在纹波尖上,读数随采样相位跳。先下变频再低通,等于把这层纹波从源头掐掉。

import numpy as np def am_index_envelope(x, fs, fc): """x: 采样序列; fs: 采样率; fc: 载波粗测频率""" n = len(x) t = np.arange(n) / fs # 1) 数字下变频:把载波搬到零频 bb = x * np.exp(-2j * np.pi * fc * t) # 2) 低通:窗口长度取整数个载波周期,避免残余纹波 w = max(3, int(round(fs / fc)) * 4) bb = np.convolve(bb, np.ones(w) / w, mode='same') # 3) 取模得到包络 env = np.abs(bb) # 4) 掐掉两端过渡段,用分位数代替极值 env = env[int(0.1 * n):int(0.9 * n)] hi = np.percentile(env, 99.0) lo = np.percentile(env, 1.0) return (hi - lo) / (hi + lo), env

几个参数不能乱设。低通窗口长度要取载波周期的整数倍,取 4 个周期是个折中:再短,残余纹波压不住;再长,包络本身的起伏会被平滑掉,小调制度时尤其明显。分位数用 99 和 1 是经验值,对应正态分布约 2.3 倍标准差的位置,信噪比好的时候偏差不到半个百分点;噪声大的场合可以放宽到 95 和 5,代价是 ma 会被系统性低估。

这条路线最大的优点是不用做长 FFT,几十毫秒的数据就够,实时性好。最大的问题在边界:ma 低于 15% 时,包络起伏只有均值的百分之十几,和噪声同量级,分位数怎么调都不稳。这时候必须换路线。

3.2 路线二:FFT 边带比值法,配合栅栏效应校正

调幅波的频谱很干净:一根载波,两根边带,边带幅度各是载波的 ma/2。所以只要把三根谱线的幅度读准,ma 就是一个除法。

import numpy as np def am_index_fft(x, fs, fm_guess, span=0.2): """span: 在 fc±fm 附近的搜索比例,默认 ±20%""" n = len(x) X = np.fft.rfft(x * np.hanning(n)) mag = np.abs(X) freqs = np.fft.rfftfreq(n, 1 / fs) kc = int(np.argmax(mag)) # 载波峰:全谱最大 fc = freqs[kc] def peak_near(f0): lo = np.searchsorted(freqs, f0 * (1 - span)) hi = np.searchsorted(freqs, f0 * (1 + span)) k = lo + int(np.argmax(mag[lo:hi])) return mag[k] a_up = peak_near(fc + fm_guess) # 上边带 a_dn = peak_near(fc - fm_guess) # 下边带 a_sb = 0.5 * (a_up + a_dn) # 双边带取平均,抵消不对称 return 2 * a_sb / mag[kc], fc

为什么这里用汉宁窗:矩形窗的旁瓣只衰减十几个 dB,载波那么强,旁瓣会直接盖住边带,小调制度时读出来的"边带"其实是载波的泄漏。汉宁窗旁瓣压到三十多 dB,代价是主瓣变宽到 4 个谱线间隔。

主瓣宽度直接决定了 FFT 点数够不够。载波和边带在频率上相距 fm,要把两团主瓣分开,至少要求频率分辨率优于 fm 的三分之一,也就是点数不少于三倍采样率除以调制频率。这个数字算出来往往比想象的大,很多人在这里踩坑,用 1024 点去做 1 kHz 调制的信号,边带和载波糊成一团。

栅栏效应是第二条误差来源。边带峰未必正好落在某条谱线上,落在两条谱线中间时幅度最多被低估一成多,ma 就系统性偏小。工程上的做法是做抛物线插值:找到峰值谱线 k 及其左右两条,用三点幅度反算真实峰位置。

def parabolic_offset(a, b, c): """a,b,c 为 k-1,k,k+1 三条谱线幅度; 返回相对 k 的小数偏移""" d = a - 2 * b + c return 0.0 if abs(d) < 1e-12 else 0.5 * (a - c) / d

算出的偏移量代回去修正幅度,频率和幅度都能提一个数量级。这个技巧不复杂,但测评时被问到"你怎么处理栅栏效应",能报出公式和误差改善量,分就稳了。

3.3 三条路线的对比表与追问怎么接

路线适用 ma 区间数据量主要误差源现场调试难度
下变频包络 + 分位数20% 以上几十毫秒峰谷判读受噪声影响低,参数少
FFT 边带比值 + 插值5% 以上几百毫秒以上分辨率不足、栅栏效应中,点数要算
模拟二极管检波30% 以上连续二极管死区、温度漂移低但边界差

三类方案的差别,本质上是"时域判峰"和"频域读线"的差别。时域省算力,边界差;频域费算力,边界好。真正稳的做法是两个都实现,按 ma 的粗测值自动切换:先用包络法粗算一个 ma,低于阈值就转 FFT 法。这个切换逻辑本身就是一个加分点。

常被追问的还有"为什么不用二极管包络检波"。答法不要否定它,要说清边界:二极管有零点几伏的死区,小调制度时谷值根本检不出来;温度一变,死区跟着变,读数漂。它便宜、快、不需要 ADC,做粗测或做参考通道都合适,但拿它去顶指标不现实。

4. 高频考点:FM 调频度 mf 与两个频率量的估计

4.1 瞬时频率法:相位差分拿 Δf,再除 fm

调频波的调频度是最大频偏除以调制频率,所以核心是两件事:把瞬时频率曲线画出来,读出它的峰峰值;再把这根曲线的振荡频率测出来。

瞬时频率靠解析信号的相位差分拿。相邻两点的相位差除以采样间隔,就是这一点的瞬时角频率。乘上解析信号、去掉载波分量之后,剩下的就是纯频偏曲线。

import numpy as np from scipy.signal import hilbert, medfilt def fm_index(x, fs, fc): n = len(x) t = np.arange(n) / fs z = hilbert(x) * np.exp(-2j * np.pi * fc * t) dphi = np.diff(np.unwrap(np.angle(z))) f_inst = dphi * fs / (2 * np.pi) # 相对 fc 的瞬时频偏 f_inst = medfilt(f_inst, 5) # 中值滤波去掉脉冲噪声 f_inst = f_inst[int(0.1 * n):int(0.9 * n)] df_pp = np.percentile(f_inst, 99) - np.percentile(f_inst, 1) # 约等于 2Δf seg = f_inst * np.hanning(len(f_inst)) fm = np.fft.rfftfreq(len(seg), 1 / fs)[int(np.argmax(np.abs(np.fft.rfft(seg))))] return (df_pp / 2) / fm, fm, f_inst

采样率是这条路线成败的关键。相位差分的噪声会被采样率放大:每个采样点的相位噪声是固定量级,差分除以采样间隔后,频率噪声正比于采样率。只按两倍载波取采样率,差分级别的噪声就能吃掉整个频偏读数。工程上取八到十倍载波,或者用带通采样把载波搬到中频再处理。

中值滤波窗口取五个点是个起点,实际要按"一个载波周期对应几个采样点"来定。窗口短了去不掉脉冲,长了会把频偏曲线的峰削平,mf 偏小。

有个反直觉的结论值得记住:fc 估偏一点,对 mf 的影响其实不大。因为频偏曲线整体平移,峰峰值不变。真正被 fc 误差影响的是载波频率那个测点本身。这一点答出来,能说明你是真做过,不是背的。

4.2 贝塞尔边带比值法:小 mf 好用,大 mf 会翻车

调频波的频谱是贝塞尔函数的展开,载波幅度正比于零阶,第一对边带正比于一阶,依此类推。小调频度下有个简洁近似:一阶边带幅度比上载波幅度,正好约等于 mf 的一半。

mfJ0J1J1/J02·J1/J0
0.20.99000.09950.10050.201
0.50.93850.24230.25820.516
1.00.76520.44010.57511.150
1.50.51180.55791.09002.180
2.00.22390.57702.57705.150
2.40.00250.5202208 量级—

表里能读出两件事。mf 小于 0.5 的时候,那个"乘二"的近似误差在百分之三以内,可以直接用;mf 到了 1,误差就上到一成半,必须查表反解。更要命的是非单调:零阶贝塞尔函数在 2.4 附近过零,比值在这里发散,过了这个点又往下走,同一个比值对应两个甚至多个 mf。

所以这条路线只在 mf 小于 1 的窄区间里能独立用,其余情况要么配合高阶边带联合反解,要么干脆退回瞬时频率法。反过来,小 mf 恰恰是瞬时频率法最难受的区间——两条路线正好互补,按粗测值切换是正解。

顺便说一个校准技巧:零阶贝塞尔函数过零时载波谱线会消失,这叫载波零点法。用标准信号源把 mf 缓慢调到载波消失,此时 mf 恰好是那个已知的零点,可以拿来标定整个调频通道的增益。这个方法不需要高精度仪器,现场很好用。

4.3 载波与调制频率:闸门法、等精度与频谱插值

载波频率如果靠计数法测,误差主要来自闸门的 ±1 个计数。闸门时间固定时,被测频率越低,相对误差越大。真正的解法是等精度测量:闸门由被测信号自己开合,同时数被测脉冲和标准时钟脉冲,误差只跟标准时钟和闸门长度有关,跟被测频率无关。

调制频率这边,走频谱更省事,但分辨率同样是硬约束。频率分辨率等于采样率除以点数,想读准 fm 就得把点数堆上去,或者做频谱插值。插值公式前面给过一个,用在三条谱线上,能把频率估计精度提高五到十倍,代价只是几行代码。

两个频率量的共同要求是:测 fc 时用宽带通道,测 fm 时用窄带通道,别指望一条路径同时满足。前端切换量程之后,滤波器的群延迟会变,包络的相位会跟着变,这一点在下一章还会展开。

4.4 追问演练:mf 小于 1 时读数为什么开始抖

测评老师很爱在这个点上停一下:"你的调频度在小信号端为什么跳得厉害?"

答题分三层。第一层讲现象归因:mf 小意味着频偏小,瞬时频率曲线的摆幅和相位差分的噪声同量级,信噪比直接塌了。第二层讲分母:mf 等于频偏除以调制频率,分母的测量误差和分子的误差按同样的比例进结果,两边一叠加,误差翻倍。第三层讲对策:加大采样率压噪声、多段数据同步平均、或者在 mf 小于某个阈值时自动切到贝塞尔边带比值法——小 mf 时能量集中在第一对边带,比值法正好占便宜。

最后补一句"我在两种方法之间做了交叉校验,读数相差超过阈值就提示重新测量",这句话的分量比任何公式都重,因为它说明你想过读数的可信度问题。

5. 易错点:测评台上五个当场失分的做法

5.1 用最大值最小值直接算 ma

错在哪:包络序列直接求全局最大和全局最小,代进定义式算调制度。

为什么错:单点极值对噪声最敏感。噪声让最大值偏高、最小值偏低,分子被放大、分母被压缩,ma 系统性偏大,而且随着信噪比下降越来越偏。现场换个信号源幅度,读数就跳一格,评委一眼看出不稳。

怎么答对:改成 99 和 1 分位数,或者对包络做直方图找双峰。答辩时把"极值统计量对野值敏感"这句话说出来,再补一句"分位数相当于给峰谷判读加了一个软阈值",这题就过了。

5.2 采样率只按两倍载波取

错在哪:按奈奎斯特定理取最低采样率,觉得够用就行。

为什么错:定理保证的是"能恢复",不是"能测准"。调幅通道里,采样率低意味着每个载波周期只有两三个点,下变频后的低通几乎没得选;调频通道里,相位差分噪声正比于采样率,两倍采样下瞬时频偏的抖动可以直接吃掉小 mf 的读数。

怎么答对:说清楚两条路线各自的采样率下限,直接采样取八到十倍载波,或者走带通采样但必须显式算出混叠后的频率并做校验。答辩时主动说"我留了多少余量、为什么留",比报一个数字更有说服力。

5.3 一个 FFT 同时测四个量

错在哪:一帧数据做一次频谱,载波、边带、调制频率全在同一张谱上找。

为什么错:四类谱线的分辨率需求差一个量级。载波频率是窄带高峰,几百点就够;边带要和载波分开,点数得往上翻;调制频率藏在包络里,得先把载波去掉。用一套参数硬扛,结果是每一项都勉强及格,边界测点全超差。

怎么答对:讲清"分通道、分量程"的结构——粗测用短帧快出结果,精测用长帧单独跑,两次测量之间用粗测结果约束搜索范围。这不是浪费算力,是把算力花在刀刃上。

5.4 换量程不重跑基线

错在哪:前端换挡之后接着往下测,不重新做零点和增益校准。

为什么错:换挡意味着换了一条模拟通道,放大器的增益误差、抗混叠滤波器的群延迟、甚至 ADC 输入端的偏置全都变了。包络法对这种变化尤其敏感,因为它读的是绝对幅度。血泪经验是:中段测得很准,一换到小量程,ma 整体偏了两三个百分点。

怎么答对:给出"换挡即重校"的流程,并说明用内部参考信号做两点校准,零点用静默段、增益用标准幅度段。答辩时说清"我把校准做成了换挡后的自动动作,操作者不需要记住",评委会认这个设计。

5.5 显示直接刷单次结果

错在哪:每次测量就把当前值直接推到屏幕上,末位一直跳。

为什么错:单次测量的方差摆在那儿,末位跳动不代表算法差,但评委看到的就是"读数不稳",稳定度这一项直接扣。而且人眼对跳动的容忍度极低,跳两下就会被判"不可用"。

怎么答对:加滑动平均,并且设一个死区——变化量小于末位一个字就不刷新。同时保留一个"快速模式"用于找信号,一个"稳定模式"用于读数,用按键切换。答辩时把这两种模式的区别讲清楚,说明你知道实时性和稳定性是矛盾的。

6. 从代码到测评台:把误差压到指标内的三步走

代码跑通只是起点,能不能在测评台上守住指标,取决于误差有没有被分配过。我的做法是把自己的链路按环节列出来,逐段估误差,再决定每一段花多少代价。

环节典型误差来源处理动作现场怎么验证
前端调理增益漂移、滤波器通带不平换挡自动重校,通道幅频建档换挡后测同一点,看读数是否回原位
采样相位噪声、时钟抖动采样率留八倍余量,时钟走独立低抖路径输入纯载波,看瞬时频率曲线的厚度
频率估计分辨率不足、栅栏效应长帧加窗,三点抛物线插值换不同点数的两帧,看结果是否收敛
比值计算谱线泄漏、边带不对称双边带取平均,搜峰范围按 fm 约束人为让上下边带不等,看平均是否稳
显示单次方差大滑动平均 + 死区刷新连续观察一分钟,末位是否只在一个字内跳

三步走的顺序别搞反。第一步是分段验证:只给纯载波,看频率读数准不准;再给单音调幅,看包络好不好;最后给调频,看瞬时频率曲线干不干净。哪一步的残差超了预期,就停在那里查,不要带着病往下走。第二步是边界扫描:调制度从 10% 一路拉到 90%,每 10% 记一个点,画出误差曲线。误差曲线如果是单调的,说明有一处系统性偏差,可以补;如果是忽大忽小的锯齿,说明是随机噪声,得靠平均。第三步才是自动切换:把前面测出来的边界写进判断条件,让装置自己选路线。

押题的角度也说一句。这类题现场的追问高度集中在三个方向:一是"边界上你怎么保证",二是"两种方法结果不一致你信谁",三是"如果只能保留一个误差源,你砍哪个"。前两个对应上面的边界扫描和交叉校验,第三个考的是误差分配的意识——答"砍掉前端增益漂移,因为它同时污染所有测量量,而频谱分辨率只污染小调制度那一段",方向就对了。

从那以后我每次做完这类测量装置,都会强制走一遍"纯载波—单音调幅—单音调频"的三段验证,哪怕时间只剩半小时。因为翻车从来不是因为算法不够聪明,而是因为没人愿意在边界上多测那三个点。这份A题代码工程按调幅、调频、频率估计分了模块,参数和切换阈值都写在注释里,照着跑一遍再对着自己的板子改,比看十篇经验帖快。希望帮到你。

本文还有配套的精品资源,点击获取

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

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

立即咨询