简介:这份资源围绕通信干扰的识别与时频分析展开,面向通信工程、信号处理方向的学生与工程师,帮助读者建立对常见干扰类型的直观认识,并借助时频图理解其频率随时间的变化规律。压缩包内共5个文件,均为m脚本文件,整体约4KB,分别对应单音干扰、多音干扰、线性扫频干扰、梳状干扰等典型干扰信号的生成与仿真,便于在MATLAB环境中直接运行、观察波形与频谱特征。资源描述中系统梳理了单音干扰、多音干扰、射频噪声干扰、线性扫频干扰与梳状干扰的成因及在时频图上的表现,并提及短时傅立叶变换、小波变换等时频分析手段在定位干扰源、评估干扰强度与制定抗干扰策略中的作用。目前已有510人学习,适合作为通信抗干扰课程实验、毕业设计或相关课题的入门参考,通过脚本复现可加深对干扰机理与抑制思路的理解。
1. 通信干扰识别:为什么你盯着频谱却看不出问题
做无线通信的工程师大概都经历过这种场景:现场信号质量突然恶化,误码率飙升,你打开频谱仪一看,底噪正常,没有明显的大信号压过来,频谱上干干净净。但通信就是不通。这时候如果切到时频图,问题往往一目了然——某个时间段内出现了一片规律性的能量块,或者一条斜着扫过去的亮线,又或者整个底噪被均匀抬高了几个dB但频谱上完全看不出来。
这就是“常见的通信干扰及其时频图”这个方向要解决的核心问题:单纯看频域或单纯看时域,都会漏掉大量干扰信息。时频图把时间和频率两个维度同时展开,干扰信号的调制方式、持续时间、周期规律、扫频斜率这些特征,全都会在时频平面上留下独特的“指纹”。
这篇文章面向的是需要做干扰排查、信号监测、通信链路保障的一线工程师。不管你是用USRP做采集、用RTL-SDR做监测,还是在仿真环境里生成干扰样本训练分类模型,下面要讲的东西都能直接落地。我会把常见干扰类型在时频图上的表现、怎么生成和采集数据、怎么做时频变换、怎么调参数、以及实际踩过的坑,按可复现的路径讲清楚。
2. 常见干扰类型在时频图上的指纹特征
2.1 单音、多音与窄带干扰:最容易被忽视的“简单”干扰
单音干扰就是在某个频点上持续发射一个正弦波。在时频图上,它表现为一条水平亮线,频率位置固定,时间上连续。看起来很简单,但实际排查时有个坑:如果单音功率不够大,在频谱上可能只比底噪高几个dB,你扫一眼就忽略了。但在时频图上,因为时间维度的累积,这条线会非常明显。
多音干扰就是多个单音叠加,时频图上出现多条平行水平线。窄带干扰则是单音附近有一定带宽的调制信号,时频图上表现为一条有一定宽度的水平亮带。
用Python生成一个单音加窄带干扰的时频图,核心代码如下:
import numpy as np import matplotlib.pyplot as plt from scipy import signal # 参数设置 fs = 1e6 # 采样率 1MHz duration = 0.01 # 时长 10ms t = np.arange(0, duration, 1/fs) # 生成单音干扰:频率 200kHz tone = 0.5 * np.exp(1j * 2 * np.pi * 200e3 * t) # 生成窄带干扰:中心频率 500kHz,带宽 20kHz narrowband = 0.3 * np.exp(1j * 2 * np.pi * 500e3 * t) * \ np.exp(1j * 2 * np.pi * 10e3 * t) # 简化模型 # 合成信号 signal_composite = tone + narrowband + 0.01 * (np.random.randn(len(t)) + 1j*np.random.randn(len(t))) # 计算时频图(STFT) f, t_spec, Zxx = signal.stft(signal_composite, fs, nperseg=256, noverlap=200) # 绘制时频图 plt.figure(figsize=(10, 6)) plt.pcolormesh(t_spec*1000, f/1e3, 20*np.log10(np.abs(Zxx)+1e-10), shading='gouraud') plt.xlabel('时间 (ms)') plt.ylabel('频率 (kHz)') plt.title('单音与窄带干扰时频图') plt.colorbar(label='幅度 (dB)') plt.show()这段代码的关键参数是nperseg和noverlap。nperseg=256意味着频率分辨率是fs/nperseg,在1MHz采样率下约3.9kHz。如果你要分辨更窄的干扰,需要增大nperseg,但时间分辨率会下降。noverlap=200让相邻窗重叠约78%,时频图更平滑。实际排查中,我一般先用nperseg=1024看全局,发现可疑区域后再用nperseg=256局部放大。
注意:单音干扰在时频图上是一条水平线,但如果你的STFT窗长太短,频率分辨率不够,这条线会糊成一片,看起来像窄带干扰。窗长选择直接决定你能区分多细的频谱结构。
2.2 扫频干扰:时频图上的斜线为什么有时是弯的
扫频干扰是现场最常见的恶意或无意干扰之一。它的瞬时频率随时间线性或非线性变化。在时频图上,线性扫频表现为一条斜线,斜率就是扫频速率。如果扫频速率很快,比如1GHz/s,而你的STFT时间窗又比较长,那么在一个窗内频率已经变化了很多,时频图上这条斜线会变粗甚至断裂。
生成线性扫频干扰的代码:
# 线性扫频干扰:从100kHz扫到900kHz,周期5ms sweep_rate = (900e3 - 100e3) / 5e-3 # 160 MHz/s f_start = 100e3 phase = 2 * np.pi * (f_start * t + 0.5 * sweep_rate * t**2) sweep = 0.4 * np.exp(1j * phase) # 注意:这里t只取一个扫频周期内的数据 t_sweep = np.arange(0, 5e-3, 1/fs) phase_sweep = 2 * np.pi * (f_start * t_sweep + 0.5 * sweep_rate * t_sweep**2) sweep_signal = 0.4 * np.exp(1j * phase_sweep)这里有个血泪经验:扫频干扰的时频图斜线斜率不仅取决于扫频速率,还取决于你的STFT参数。如果扫频速率是160MHz/s,而你的STFT时间分辨率是0.256ms(nperseg=256,fs=1MHz),那么在一个时间窗内频率变化了约41kHz。如果频率分辨率是3.9kHz,这条斜线在时频图上会呈现为宽度约10个频率格的粗线。要得到清晰的细斜线,要么提高采样率,要么缩短窗长,要么用更高级的时频分析方法。
实际排查中,我遇到过扫频干扰的时频图斜线是弯的——那是因为干扰源用的是VCO(压控振荡器)而不是DDS(直接数字合成),VCO的调谐电压和频率之间不是严格线性关系。这种非线性扫频在时频图上表现为一条弯曲的轨迹,用线性拟合去预测下一时刻的频率会翻车。
2.3 脉冲干扰与突发干扰:时间维度上的“闪现”
脉冲干扰的特点是持续时间极短,可能只有几微秒到几毫秒,但功率可能很大。在频谱上,如果脉冲占空比很低,你正好扫到它的概率很小,频谱仪上看不到。但在时频图上,因为时间轴是连续的,脉冲会表现为垂直的亮线——在某个时间点,整个频段或部分频段突然出现能量。
突发干扰类似,但持续时间稍长,可能带有一定的调制特征。比如蓝牙的跳频信号,在时频图上表现为一系列短促的亮块,在多个频点之间跳跃。
生成周期脉冲干扰:
# 脉冲干扰:周期1ms,脉宽100us pulse_period = 1e-3 pulse_width = 100e-6 pulse_train = np.zeros_like(t) for i in range(int(duration / pulse_period)): start_idx = int(i * pulse_period * fs) end_idx = int((i * pulse_period + pulse_width) * fs) if end_idx < len(t): pulse_train[start_idx:end_idx] = 1 # 脉冲调制到载波上 pulse_interference = 0.6 * pulse_train * np.exp(1j * 2 * np.pi * 300e3 * t)脉冲干扰在时频图上的表现取决于脉冲宽度和STFT窗长的关系。如果脉冲宽度远小于窗长,时频图上的亮线在时间轴上会被展宽到约一个窗长。这意味着你看到的脉冲宽度可能比实际宽。要准确测量脉冲宽度,窗长必须小于脉冲宽度。但窗长太小,频率分辨率又不够。这是一个需要权衡的参数选择问题。
我一般会先用大窗长看全局,确认脉冲的周期和大致时间位置,然后用小窗长局部放大测量精确宽度。如果脉冲太窄,比如只有几微秒,那可能需要用更高采样率或者专门的脉冲检测算法,而不是依赖STFT。
3. 从采集到成像:时频图生成的完整链路
3.1 用USRP或RTL-SDR采集IQ数据:采样率与中心频率怎么定
做实际干扰排查,第一步是采集IQ数据。用USRP B210或者RTL-SDR都可以,区别在于带宽和动态范围。RTL-SDR便宜,但只有8位量化,动态范围约50dB,如果干扰信号和有用信号功率差很大,弱信号会被量化噪声淹没。USRP B210是12位,动态范围好很多,但价格也上去了。
采集时两个关键参数:采样率和中心频率。采样率决定了你能看到的瞬时带宽。如果干扰可能出现在1GHz到1.1GHz之间,那采样率至少200MHz才能覆盖。但RTL-SDR最大采样率3.2MHz,USRP B210最大56MHz。如果干扰带宽超过采集带宽,你需要多次采集或者用扫频方式拼接。
中心频率的设置有个技巧:不要设在你要观察的频段正中间。因为零中频架构在中心频率附近有DC offset和IQ不平衡,时频图中间会出现一条亮线,容易和单音干扰混淆。我一般把中心频率偏移几十kHz到几百kHz,让目标频段落在时频图的一侧。
用Python通过UHD采集USRP数据的示例:
import uhd import numpy as np # USRP采集参数 usrp = uhd.usrp.MultiUSRP("type=b200") usrp.set_rx_rate(10e6) # 采样率 10MHz usrp.set_rx_freq(uhd.types.TuneRequest(915e6)) # 中心频率 915MHz usrp.set_rx_gain(40) # 增益 40dB # 采集10ms数据 samples = usrp.recv_num_samps(100000, 915e6, 10e6, [0], 40) # samples是复数数组,可以直接用于STFTset_rx_gain的设置很关键。增益太低,弱干扰看不到;增益太高,强干扰会导致ADC饱和,时频图上出现谐波和互调产物,你会误以为有多个干扰源。我一般从30dB开始,观察时频图,如果底噪在-80dB以下且没有削顶,就逐步增加增益直到干扰清晰但不过载。
注意:RTL-SDR的增益是分段可调的,不同增益档位的噪声系数不同。如果发现时频图底噪忽高忽低,可能是自动增益控制(AGC)在起作用。做干扰分析时一定要关掉AGC,用手动增益。
3.2 STFT参数选择:窗函数、窗长、重叠率对时频图的影响
STFT是生成时频图最常用的方法,但参数选择直接决定你能不能看到想要的细节。核心参数有三个:窗函数、窗长(nperseg)、重叠率(noverlap)。
窗函数的选择:矩形窗频率分辨率最高,但频谱泄漏严重,强干扰旁边会出现虚假的旁瓣亮线。汉宁窗(Hann)泄漏小,但主瓣变宽,频率分辨率下降。我一般用汉宁窗做通用观察,如果两个干扰靠得很近需要分辨,换矩形窗但要注意旁瓣。
窗长的选择:这是最关键的参数。窗长决定了频率分辨率(fs/nperseg)和时间分辨率(nperseg/fs)。两者乘积约等于1,不可兼得。对于常见的通信干扰:
| 干扰类型 | 建议窗长 | 理由 |
|---|---|---|
| 单音/窄带 | 1024-4096 | 需要高频率分辨率区分紧密间隔 |
| 扫频 | 128-512 | 需要高时间分辨率跟踪频率变化 |
| 脉冲 | 64-256 | 需要高时间分辨率测量脉冲宽度 |
| 宽带噪声 | 512-1024 | 折中即可 |
重叠率的选择:重叠率越高,时频图越平滑,但计算量越大。一般50%-75%重叠就够了。如果重叠率太低,时频图上会出现栅栏效应,快速变化的干扰会被漏掉。
用scipy.signal.stft时,noverlap参数直接控制重叠点数。比如nperseg=256, noverlap=200就是约78%重叠。如果内存紧张,可以降到noverlap=128(50%重叠)。
3.3 时频图后处理:动态范围压缩与干扰增强
原始STFT输出的幅度动态范围可能很大,强干扰和弱干扰在同一个色阶下,弱的根本看不见。这时候需要做动态范围压缩。最简单的方法是对幅度取对数(dB),然后设置色阶的上下限。
# 计算STFT f, t_spec, Zxx = signal.stft(signal_composite, fs, nperseg=256, noverlap=200) # 转换为dB Zxx_db = 20 * np.log10(np.abs(Zxx) + 1e-10) # 动态范围压缩:只显示底噪以上30dB的范围 noise_floor = np.median(Zxx_db) # 估计底噪 vmin = noise_floor + 3 # 低于底噪+3dB的不显示 vmax = noise_floor + 30 # 高于底噪+30dB的饱和 plt.pcolormesh(t_spec*1000, f/1e3, Zxx_db, shading='gouraud', vmin=vmin, vmax=vmax)vmin和vmax的设置是门艺术。vmin设得太低,底噪的随机起伏会显示成一片雪花,干扰反而看不清。vmax设得太高,强干扰和弱干扰的对比度不够。我一般先用np.median估计底噪,然后vmin=底噪+3dB,vmax=底噪+25到30dB。如果干扰特别强,可以适当提高vmax。
还有一种干扰增强方法:对时频图做二维CFAR检测。在时频平面上滑动一个窗口,计算窗口内均值和方差,如果中心点超过均值加若干倍标准差,就判定为干扰像素。这样可以把干扰从背景中分割出来,便于后续分类。
4. 干扰排查避坑:时频图上的假象与误判
4.1 坑一:时频图上的亮线不一定是干扰
现象:时频图上出现一条水平亮线,频率固定,看起来像单音干扰。但关闭发射机后这条线还在。
原因:可能是接收机自身的本振泄漏、DC offset、或者外部晶振的谐波。USRP和RTL-SDR在中心频率处都有DC offset,表现为零频附近的一条亮线。另外,如果附近有FM广播塔,它的谐波可能落在你的观察频段内。
解决:先把中心频率偏移几百kHz,看亮线是否跟着移动。如果亮线始终在零频位置,那就是DC offset,在时频图上把零频附近几个格屏蔽掉即可。如果亮线频率固定不随中心频率变化,那可能是外部真实信号,需要用定向天线测向确认。
4.2 坑二:扫频干扰的斜率在时频图上被“压缩”了
现象:已知干扰源扫频速率是100MHz/s,但时频图上测出来的斜率只有50MHz/s。
原因:STFT的时间窗内频率已经变化,时频图上的亮线是窗内平均效果。如果扫频速率是100MHz/s,窗长0.256ms,窗内频率变化25.6kHz。如果频率分辨率是3.9kHz,这条斜线在频率方向被展宽了约6.5个格,时间方向也被展宽了1个窗长。你测到的斜率是“模糊后”的斜率,比真实值小。
解决:要准确测量扫频速率,窗长必须满足:窗内频率变化远小于频率分辨率。即扫频速率 × 窗长 << fs/nperseg。对于100MHz/s的扫频,如果fs=1MHz,nperseg=256,窗长0.256ms,窗内变化25.6kHz,频率分辨率3.9kHz,不满足条件。需要把nperseg降到64,窗长0.064ms,窗内变化6.4kHz,频率分辨率15.6kHz,勉强满足。或者提高采样率到10MHz,nperseg=256,频率分辨率39kHz,窗内变化25.6kHz,满足。
4.3 坑三:脉冲干扰的重复周期在时频图上“消失”了
现象:用频谱仪能看到脉冲干扰的频谱包络,但在时频图上找不到规律的脉冲。
原因:脉冲的重复周期可能大于你的采集时长。比如脉冲每100ms出现一次,但你只采集了10ms数据,时频图上只有一条垂直亮线,看不出周期。或者脉冲宽度极窄,STFT窗长太大,脉冲被平均到整个窗内,时频图上只看到底噪略微抬高。
解决:先延长采集时间到至少覆盖几个脉冲周期。如果脉冲太窄,用高采样率采集原始IQ,然后在时域上做脉冲检测(比如包络检波加阈值判决),找到脉冲位置后再做STFT局部放大。
4.4 坑四:多径效应让单音干扰在时频图上“分裂”
现象:一个单音干扰在时频图上显示为多条间隔很近的水平线。
原因:多径传播导致同一信号以不同时延到达接收机,在频域上表现为频率选择性衰落,在时频图上就是多条平行线。这不是多个干扰源,而是同一个信号的多径副本。
解决:观察这些线的频率间隔是否与多径时延的倒数一致。如果间隔是固定的,且改变接收位置后间隔变化,那就是多径。把接收机移动几米,如果亮线合并或消失,确认是多径。
4.5 坑五:ADC饱和产生的谐波被误判为多音干扰
现象:时频图上出现等间隔的多条水平线,看起来像多音干扰。
原因:强干扰信号导致ADC饱和,产生谐波和互调产物。这些谐波在时频图上就是等间隔的亮线。如果你把增益调低,这些线会消失或减弱。
解决:降低接收增益,观察这些等间隔亮线是否减弱。如果减弱,就是ADC非线性产物。另外,检查时域波形是否有削顶。做干扰分析时,增益一定要留足余量,确保最强信号不导致ADC饱和。
5. 用CNN做干扰分类:从时频图到自动识别
5.1 数据集构建:时频图样本的生成与标注
要做自动干扰分类,第一步是构建数据集。实际采集的干扰样本标注成本高,我一般先用仿真生成大量样本,再用少量实测数据做微调。
仿真生成时,每种干扰类型随机化参数:频率位置、功率、持续时间、扫频速率、脉冲周期等。这样训练出来的模型泛化能力更好。生成时频图后,保存为灰度图或伪彩色图,标签就是干扰类型。
import numpy as np from scipy import signal import cv2 def generate_tf_image(interference_type, fs=1e6, duration=0.01): """生成指定干扰类型的时频图""" t = np.arange(0, duration, 1/fs) if interference_type == 'single_tone': freq = np.random.uniform(100e3, 900e3) sig = 0.5 * np.exp(1j * 2 * np.pi * freq * t) elif interference_type == 'sweep': f_start = np.random.uniform(100e3, 300e3) f_end = np.random.uniform(700e3, 900e3) sweep_rate = (f_end - f_start) / duration phase = 2 * np.pi * (f_start * t + 0.5 * sweep_rate * t**2) sig = 0.4 * np.exp(1j * phase) elif interference_type == 'pulse': period = np.random.uniform(0.5e-3, 2e-3) width = np.random.uniform(50e-6, 200e-6) pulse = np.zeros_like(t) for i in range(int(duration / period)): s = int(i * period * fs) e = int((i * period + width) * fs) if e < len(t): pulse[s:e] = 1 sig = 0.6 * pulse * np.exp(1j * 2 * np.pi * 300e3 * t) else: sig = 0.01 * (np.random.randn(len(t)) + 1j*np.random.randn(len(t))) # 加噪声 sig += 0.01 * (np.random.randn(len(t)) + 1j*np.random.randn(len(t))) # STFT f, t_spec, Zxx = signal.stft(sig, fs, nperseg=256, noverlap=200) Zxx_db = 20 * np.log10(np.abs(Zxx) + 1e-10) # 归一化到0-255 Zxx_norm = (Zxx_db - Zxx_db.min()) / (Zxx_db.max() - Zxx_db.min()) * 255 return Zxx_norm.astype(np.uint8)这个函数每次调用生成一张时频图,参数随机化。生成几千张后,按8:1:1划分训练集、验证集、测试集。注意:同一类干扰的不同样本要放在同一个集合里,避免数据泄漏。比如单音干扰的样本1在训练集,样本2在测试集,但它们的频率可能很接近,模型可能记住频率而不是学习干扰特征。我一般按频率范围划分:训练集用100-400kHz,验证集用400-600kHz,测试集用600-900kHz。
5.2 轻量级CNN模型:在嵌入式设备上跑干扰识别
时频图分类不需要ResNet那么大的模型。一个4层卷积加2层全连接的轻量级CNN就够了,参数量控制在100k以内,可以在树莓派或Jetson Nano上实时跑。
import torch import torch.nn as nn class InterferenceCNN(nn.Module): def __init__(self, num_classes=4): super().__init__() self.conv_layers = nn.Sequential( nn.Conv2d(1, 16, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(16, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(64, 64, 3, padding=1), nn.ReLU(), nn.AdaptiveAvgPool2d((4,4)) ) self.fc = nn.Sequential( nn.Linear(64*4*4, 128), nn.ReLU(), nn.Dropout(0.3), nn.Linear(128, num_classes) ) def forward(self, x): x = self.conv_layers(x) x = x.view(x.size(0), -1) return self.fc(x)输入是单通道时频图,尺寸建议128x128或256x256。太大推理慢,太小细节丢失。训练时用交叉熵损失,Adam优化器,学习率1e-3,batch size 32。训练20-30个epoch就够了,因为时频图特征比较明显。
注意:实际部署时,时频图的动态范围压缩参数要和训练时一致。如果训练时用底噪+30dB的色阶,部署时用底噪+20dB,模型准确率会下降。我一般把归一化参数固定下来,不随环境变化。
5.3 实测数据微调:解决仿真与实际的域偏移
仿真数据训练的模型,直接用到实测数据上,准确率可能掉20%-30%。原因是仿真没有考虑多径、接收机非线性、外部噪声等实际因素。解决办法是用少量实测数据做微调。
微调时,冻结卷积层,只训练全连接层。学习率降到1e-4,训练5-10个epoch。实测数据不需要太多,每类50-100个样本就够了。标注时注意:一个时频图里可能同时存在多种干扰,这时候要么做多标签分类,要么把主要干扰类型作为标签。
我一般会保留一个“未知”类,把不确定的样本扔进去。这样模型不会强行把未知干扰分到已知类里,减少误报。
5.4 推理加速:从PyTorch到ONNX再到TensorRT
如果要在嵌入式设备上实时推理,PyTorch太慢。我一般导出为ONNX,然后用TensorRT或OpenVINO加速。
# 导出ONNX dummy_input = torch.randn(1, 1, 128, 128) torch.onnx.export(model, dummy_input, "interference_cnn.onnx", input_names=['input'], output_names=['output'], dynamic_axes={'input': {0: 'batch'}, 'output': {0: 'batch'}})导出后,用ONNX Runtime测试推理速度。在Jetson Nano上,128x128输入的推理时间约5-10ms,可以做到每秒100帧以上。如果还不够快,用TensorRT进一步优化,FP16量化后可以到2-3ms。
实际部署时,STFT计算和CNN推理可以流水线并行。采集一段IQ数据,做STFT,送CNN推理,同时采集下一段。这样整体延迟可以控制在20ms以内。
6. 时频图分辨率与干扰检测的权衡:一个具体技巧
做干扰排查久了,你会发现一个矛盾:时频图的时间分辨率和频率分辨率永远不够用。扫频干扰需要高时间分辨率,窄带干扰需要高频率分辨率,脉冲干扰两者都要。但STFT的测不准原理决定了你不可能同时获得高时间分辨率和高频率分辨率。
我的经验是:不要试图用一张时频图解决所有问题。正确的做法是分层排查。
第一层:用大窗长(nperseg=4096)生成全局时频图,频率分辨率高,能看到所有窄带和单音干扰。时间分辨率差,但扫频和脉冲的大致位置能看到。
第二层:对可疑时间段,用小窗长(nperseg=64)局部放大,时间分辨率高,能看清扫频斜率和脉冲宽度。
第三层:如果两层都看不清,用其他方法。比如对窄带干扰用高分辨率谱估计(MUSIC、ESPRIT),对脉冲干扰用时域包络检测,对扫频干扰用分数阶傅里叶变换(FRFT)。
这里给一个自适应窗长的具体实现思路:
def adaptive_stft(signal, fs, target_freq_res=1e3, target_time_res=1e-4): """ 根据目标频率分辨率和时间分辨率自动选择窗长 target_freq_res: 期望频率分辨率 (Hz) target_time_res: 期望时间分辨率 (s) """ nperseg_freq = int(fs / target_freq_res) # 满足频率分辨率的窗长 nperseg_time = int(target_time_res * fs) # 满足时间分辨率的窗长 # 取两者中较小的,保证时间分辨率 nperseg = min(nperseg_freq, nperseg_time) nperseg = max(nperseg, 32) # 最小32点 nperseg = min(nperseg, len(signal) // 4) # 不超过信号长度的1/4 noverlap = int(nperseg * 0.75) f, t, Zxx = signal.stft(signal, fs, nperseg=nperseg, noverlap=noverlap) return f, t, Zxx这个函数根据你期望的频率分辨率和时间分辨率,自动选择窗长。实际使用时,先设一个宽松的频率分辨率(比如10kHz)和时间分辨率(比如0.1ms),看全局。发现可疑区域后,缩小时间范围,重新调用这个函数,设更严格的参数。
还有一个技巧:对时频图做多分辨率分析。用不同窗长生成多张时频图,然后融合。比如大窗长的时频图用于检测窄带干扰,小窗长的用于检测脉冲和扫频。融合时,对每个像素取最大值或加权平均。这样一张图里既有高频率分辨率又有高时间分辨率。
我最后悔的一次排查是:现场有一个每200ms出现一次的脉冲干扰,宽度只有10微秒。我用nperseg=1024的窗长,时频图上完全看不到脉冲,只看到底噪偶尔抬高。折腾了一下午,最后用nperseg=64才看到。如果一开始就用自适应窗长,十分钟就能定位。所以现在我的习惯是:永远先用小窗长快速扫一遍,确认没有窄脉冲,再用大窗长细看频谱结构。这个顺序不能反。
希望帮到你。
本文还有配套的精品资源,点击获取