峰值保持用滑动窗最大值
仿真跑起来后,突然发现实际频谱仪的工程师真不容易——那些丝般顺滑的频谱显示背后,藏着无数个深夜调试滤波器的黑眼圈。不过至少下次用频谱仪时,看到跳动的轨迹线,能会心一笑:这哥们儿现在正执行着和我差不多的算法呢。打开MATLAB敲下第一行代码的时候,我盯着屏幕上闪烁的光标突然意识到——这玩意儿和真实的频谱仪之间,隔着的可能不只是几行代码的距离。记得有次参数设错,1MHz的RBW硬是把10kHz的信号给
扫频式频谱仪中频算法仿真代码
打开MATLAB敲下第一行代码的时候,我盯着屏幕上闪烁的光标突然意识到——这玩意儿和真实的频谱仪之间,隔着的可能不只是几行代码的距离。扫频式频谱仪的中频处理就像个黑盒子,今天咱们就试着用代码撬开它看看。

先来段混频的骚操作:
def mixer(if_signal, lo_freq, sample_rate):
t = np.arange(len(if_signal)) / sample_rate
lo_i = np.cos(2 * np.pi * lo_freq * t)
lo_q = -np.sin(2 * np.pi * lo_freq * t)
return if_signal * lo_i, if_signal * lo_q
这代码看着简单,实际上正交本振信号的负号藏着玄机。有次我把负号写反了,结果相位谱直接放飞自我,调了三天才发现是这里的问题。注意那个-sin可不是随便写的,它保证了I/Q两路信号的正交性,就像咖啡配奶泡的黄金组合。
接下来轮到FIR滤波器登场:
% 设计带通滤波器
filt_order = 64;
nyq = sample_rate/2;
b = fir1(filt_order, [flow/nyq, fhigh/nyq], 'bandpass', hamming(filt_order+1));
filtered_i = filter(b, 1, i_mixed);
filtered_q = filter(b, 1, q_mixed);
这里有个坑爹的地方:滤波器阶数必须足够高才能保证陡峭的滚降。但阶数太高又会导致实时处理时延迟爆炸,就像用高射炮打蚊子。有次为了抓个小信号把阶数设到256,结果扫频速度慢得能泡碗面。

扫频式频谱仪中频算法仿真代码
检波环节最容易被轻视:
def detector(i, q):
magnitude = np.sqrt(i**2 + q**2)
window_size = int(sample_rate / rbw)
return uniform_filter1d(magnitude, window_size, mode='nearest')
这个滑动窗最大值滤波才是频谱显示的真正灵魂。RBW(分辨率带宽)参数直接决定窗口大小,搞不好会把脉冲信号显示成小山包。记得有次参数设错,1MHz的RBW硬是把10kHz的信号给吞了,现场演示直接翻车。

最后拼装整个处理链:
def sweep_processor(rf_signal, start_freq, stop_freq, rbw):
spectrum = []
for current_lo in np.linspace(start_freq, stop_freq, 1000):
i, q = mixer(rf_signal, current_lo, sample_rate)
# 下变频到零中频
i_low = low_pass_filter(i)
q_low = low_pass_filter(q)
# 检波后处理
detected = detector(i_low, q_low)
spectrum.append(np.max(detected))
return spectrum
这个循环扫频的过程就像用放大镜一寸寸检查频谱。调试时建议先拿单频信号试刀,比如生成个10MHz+20MHz的双音信号,看看频谱图上能不能准确跳出两个尖峰。
仿真跑起来后,突然发现实际频谱仪的工程师真不容易——那些丝般顺滑的频谱显示背后,藏着无数个深夜调试滤波器的黑眼圈。代码虽然能仿真个大概,但真实世界的电磁噪声、相位噪声这些幺蛾子,可不是几行Python能完全复现的。不过至少下次用频谱仪时,看到跳动的轨迹线,能会心一笑:这哥们儿现在正执行着和我差不多的算法呢。

更多推荐
所有评论(0)