
做干扰源定位和无线环境监测这行久了你迟早会面对一个问题频谱仪抓回来几十条干扰信号每条都测了方向、强度、带宽可到底哪几条来自同一个发射源哪几条是不同设备发出来的光靠肉眼看频谱图看到眼瞎也分不清。这个课题我最早接触是在做电磁兼容现场测试时客户拿了一堆扫频数据问我们这十几个干扰信号里能不能帮我归归类看看背后是不是只有三类设备。传统做法是靠人工比对频谱包络和方向角数据一多效率极低而且主观性太强。后来我换成用聚类分析来处理把这套思路和Matlab代码沉淀下来发现不仅能解决问题而且可以同时用多种聚类方法交叉验证让分类结果更有说服力。所谓基于多种方法的干扰源聚类分析核心就一句话提取每个干扰信号的特征向量然后在特征空间里让聚类算法自己把相似的对象聚到一组。分到同一组的信号大概率有同源关系或者物理特性非常接近分不到一组的就是不同干扰源。这个方法不依赖先验知识不需要提前知道现场到底有几种干扰源跑完代码直接给出分组建议。下面我把从原理、特征提取到四种聚类方法的Matlab实现完整讲一遍包括我实际踩过的坑和调参经验这份内容对做电磁频谱监测、无线电管理、设备故障排查的工程师应该特别有用。1. 为什么需要对干扰源做聚类分析1.1 干扰源识别的真实场景一堆信号里找谁是谁很多人在学校学Matlab的聚类分析用的都是鸢尾花、客户画像这类数据特征列摆得整整齐齐。但拿到真实的干扰源场景时情况完全不一样。你在某个工业园区做电磁环境摸底用扫频仪从30MHz扫到6GHz一上午就能抓出几十上百个异常信号。每个信号有中心频率、带宽、功率、出现时段还有通过测向天线得到的到达角。问题是这些信号里有的是同一台设备的多次谐波有的是同型号设备发出来的近似信号有的是完全独立的干扰源甚至会混入一些偶发信号。这时候如果靠人去给每条信号定罪等于在做一件主观性极强的归类工作。更麻烦的是同一干扰源的信号往往在频域上跨了好几个频段比如某个开关电源的基频可能是300kHz但它产生的干扰能一路辐射到几百MHz在频谱图上表现为一串间隔规则的小峰。人眼看着这些峰可能会觉得是多个干扰源实际上全是同源辐射。聚类分析的作用就是把这些信号的物理特征量化成向量后用数学规则替代肉眼判断让算法告诉我们这两条信号的特征距离为0.05很近归属于同一类。1.2 聚类思路的本质把相似行为归到同一组干扰源聚类分析本质上还是无监督学习那套逻辑没有标注好的标签算法只能靠物以类聚的准则来分组。因此第一步要定义相似到底是什么。对干扰源而言相似性可以从三个层面去看。第一个层面是频域相似性两个信号如果中心频率接近、带宽接近、频谱包络形态相似它们更可能是同源产生的。第二个层面是时域行为相似性比如两个信号只在夜间出现另一个信号全天都在那么夜间出现的两个信号归到一起的概率理应变大。第三个层面是统计特征相似性信号的谱峰个数、能量集中度、谐波间隔这些统计量对区分不同辐射机理非常有效。把这三个层面的特征拼成一个向量每条干扰源信号就变成了高维空间里的一个点。接下来要做的事就是在这个高维空间里执行聚类算法。K-means会把空间切分成若干块层次聚类会构建出一棵树让你自己挑层次DBSCAN会根据密度自动识别簇和离群点高斯混合模型则会输出每个点属于每一类的概率。多方法交叉验证的价值就在这里四种方法如果得到接近的分组结果那这个结论的可信度就相当高如果某两条信号在K-means里分到一起、在DBSCAN里却被标成噪声说明它们的特征位置正好处于聚类边界附近需要回头检查特征工程是不是遗漏了区分维度。2. 特征矩阵干扰源聚类的真正核心2.1 从原始IQ数据到特征向量的三步走不少人拿到数据后第一反应是直接把频谱幅度谱丢给算法不就行了我试过效果非常糟糕。频谱幅度谱动辄几千个点在这么高维的空间里做距离计算所有的点都会因为维数灾难挤在一起聚类结果几乎没有区分度。正确的做法是先把原始数据降维成有物理意义的特征向量。完整流程分三步。第一步是预处理把扫频仪或频谱仪导出的轨迹数据整理成统一的格式以信号片段为单位切片每段切片对应一个待分类的干扰源。第二步是特征提取从每个切片中算出频域、时域和统计特征。第三步是标准化与特征筛选把不同量纲的特征压缩到0到1之间或做z-score归一化同时剔除方差接近0的冗余特征。关于预处理有个非常容易忽略的细节频谱仪的扫描轨迹里经常包含底噪和瞬时毛刺在做特征提取之前我先用幅度中值加3dB作为检测门限把低于门限的数据置为底噪高于门限的部分才识别为有效信号包络。否则等你算3dB带宽时被噪声抬高的裙边会让带宽特征偏差30%以上。2.2 我常用的6个频谱特征维度及物理含义在实际项目里我通常为每个干扰源信号提取下面这些特征它们的物理含义清晰聚类后可解释性也比较好。特征名计算方法物理含义中心频率信号包络幅度加权频率反映信号在频域中的能量重心位置3dB带宽幅度下降到峰值3dB处的频率宽度反映信号占据的频谱宽度峰值幅度包络最大值反映干扰强度谐波间隔相邻谱峰之间的平均频率间隔非线性器件产生的谐波族特征谱峰数量超过门限的局部最大值数量区分窄带信号与多谐波信号能量集中度峰值附近能量占总量比例反映信号波形是集中型还是分散型以某次测试为例一台变频器的辐射干扰在频谱仪上显示了9个等间隔峰谐波间隔约为150Hz峰值幅度从基波开始逐次衰减。另一个干扰源是宽带噪声发生器谱峰数量为0没有明显峰包络平缓能量集中度很低。这两个信号哪怕中心频率离得很近谱峰数量和能量集中度也能把它们干净地分开。这就是特征工程的意义提前把宽带和窄带谐波这两个本质差异量化出来而不是让聚类算法在高维频谱里自己摸索。2.3 归一化的那些坑别让量纲毁掉距离计算特征向量拼好后如果你直接拿去算欧氏距离大概率会得到一个荒谬的结果。因为中心频率可能是1000000Hz这种量级3dB带宽可能是1000Hz量级峰值幅度可能是-50dBm这种范围。如果不归一化距离计算完全被数值最大的那列特征支配其他特征等于白提。我的做法是统一用z-score归一化公式是 z (x - mean) / std。对每个特征列单独算均值和标准差把数据变换成均值为0、方差为1的分布。使用z-score而不是min-max归一化的原因是min-max对离群点太敏感。干扰源数据里经常混入极强信号一个峰值为0dBm的信号会直接把min-max标定的1抢走剩下的所有信号在0到0.3之间挤成一团z-score受单个大值影响相对小稳定性好很多。另一个我在实践中遇到的坑是标准差的零值问题。如果你提取了的一个特征在现场所有信号里都一样比如所有干扰源的中心频率都落在同一授权频段附近那么该列标准差为0z-score会返回NaN进而导致聚类结果全是NaN代码直接报废。处理办法是在标准化前加一个判断某列标准差小于1e-10直接丢弃该特征列。很多同行问我聚类结果为什么报错八成就是卡在这里。3. 聚类方法选型四种方法各自的性格要摸透3.1 四种聚类方法横向对比没有一种聚类算法是万能的至少对干扰源数据来说是这样。我先用一张表把四种常用的方法放在一起对比然后逐一说清楚在什么情况下选谁。方法核心思路聚类数是否需预设对噪声的处理抗离群点能力计算量K-means按距离划分离散簇需要会把噪声强分到某个簇较差极小层次聚类构建树状图逐层合并可事后从树状图选噪声会以独立分支出现中等中等DBSCAN按密度连通区域不需要专门识别噪声点较好中低GMM用多个高斯分布拟合需要噪声被建模为低概率点一般中等3.2 K-means快但你不能盲目信它K-means是很多人第一反应会用的方法因为Matlab里一行kmeans(X, k)就能跑出结果。它做的事情是随机初始化K个簇中心然后反复迭代把每个点分给最近的簇中心再重新计算簇中心直到收敛。对于数据量在几千条以内、簇分布比较圆润的干扰源数据K-means表现很快。但K-means有两个先天问题在干扰源场景里非常致命。第一它对初始值敏感不同的初始中心可能收敛到不同的局部最优。我的对策是kmeans函数里设置Replicates, 10让算法从10组不同初始值出发保留误差最小的那组。第二它假设每个簇是凸状的如果实际数据中某个干扰源的信号特征恰好呈长条形分布K-means会在中间拦腰砍一刀把本该同一类的样品一分为二。所以我的习惯是K-means跑出来的结果只作为第一轮参考不会直接采信。3.3 层次聚类可解释性最强的簇结构视图层次聚类Hierarchical Clustering是第二种我经常用的方法。它的核心逻辑是自底向上不断合并距离最近的两个样本或簇最终形成一棵树。Matlab里对应函数是linkage之后用dendrogram画树状图。层次聚类对干扰源最大的价值是树状图可解释性。我可以在完成聚类后直接看树状图如果两条干扰信号在很低的合并距离就连在一起说明它们非常相似如果某条信号一直到树的最顶端才被并进来说明它和谁都不像。在实际工程汇报里把树状图打印出来贴进报告比单纯说DBSCAN将数据分为3类要有说服力得多。linkage里有个参数method供选择ward离差平方和法、average平均距离法、single最短距离法等。对干扰源数据我推荐ward它倾向于生成大小相对均衡的簇而且对噪声的敏感性低于single。single很容易出现链式效应两个本不相关的簇因为个别靠得近的样本而连成一个大簇这在频谱数据里非常常见。3.4 DBSCAN不知道有几类时的第一次选择DBSCAN是我在面对完全不知道现场有几类干扰源这一问题时优先尝试的方法。它的逻辑是如果某点在半径epsilon内有超过MinPts个邻居就认为它是核心点然后把所有与核心点密度相通的点连成一个簇达不到密度要求的点被标为噪声。这个特性对干扰源聚类特别好用因为真实环境里必然存在偶发信号、单次脉冲、仪表自激一类的不明干扰它们不该被硬分到任何一组。用K-means会强制给它们分配一个簇标签DBSCAN倒好直接给你标成-1告诉你这玩意不属于任何一个群体。DBSCAN的难点在于调epsilon。我的经验是先用K-最近邻距离绘图法取MinPts5算出每个点到其第5个最近邻居的距离按升序排序后画曲线。曲线有明显拐点时把拐点对应的距离设为epsilon聚类效果通常不错。如果曲线是一条平滑单调线说明数据密度变化很均匀这种情况强制用密度聚类意义不大不如换回K-means按数量切分。3.5 GMM给每条信号算一个属于每类的概率高斯混合模型GMM和前三种方法思路不同它认为每个簇可以由一个高斯分布也就是椭球形分布来描述整个数据集是若干高斯分布的混合。在Matlab里对应fitgmdist。它输出的是软分类结果——每条信号不是只属于某个簇而是给出属于簇1的概率是0.7属于簇2的概率是0.3这样的后验概率。这个特性在干扰源场景里很有用。干扰源的频谱特征并不是铁板一块比如某设备工作在跳频模式下上一秒在915MHz下一秒跳到2.4GHz它的特征向量可能同时带有两个簇的影子。GMM能捕捉到这种处于两个类之间的模糊状态而硬聚类算法只能强行二选一。操作上fitgmdist有个让我踩过坑的参数叫RegularizationValue。干扰源的多个特征之间往往存在相关性比如谱峰数量和能量集中度就高度负相关这会让协方差矩阵接近奇异拟合过程报错。解决办法是设置Regularize, 1e-5给协方差矩阵的对角线加一点正则化项数值上更稳聚类结果几乎不受影响。4. 基于多种方法的Matlab实现全流程4.1 准备一份可复现的实验数据网上很多教程用的数据都是内置的fisheriris或者kmeansdata但这是干扰源聚类我们要的是能模拟干扰源特征的数据。下面我给出一个生成模拟数据的代码它生成三类干扰源每类特征不同最后再混入两个随机噪声点方便观察DBSCAN的离群点识别效果。% 生成三类干扰源模拟特征 rng(42); % 固定随机种子保证可复现 numSamplesPerClass 40; % 类别1窄带谐波源中心频率集中谐波间隔小谱峰多 class1 [ ... 900 5*randn(numSamplesPerClass,1), ... % 中心频率 MHz 10 2*randn(numSamplesPerClass,1), ... % 3dB带宽 kHz -60 3*randn(numSamplesPerClass,1), ... % 峰值幅度 dBm 5 1*randn(numSamplesPerClass,1), ... % 谱峰数量 0.7 0.05*randn(numSamplesPerClass,1)]; % 能量集中度 % 类别2宽带噪声源包络平缓谱峰少能量分散 class2 [ ... 2400 50*randn(numSamplesPerClass,1), ... 800 50*randn(numSamplesPerClass,1), ... -75 2*randn(numSamplesPerClass,1), ... 1 0.5*randn(numSamplesPerClass,1), ... 0.2 0.03*randn(numSamplesPerClass,1)]; % 类别3脉冲干扰源中心频率漂移大特征离散 class3 [ ... 450 80*randn(numSamplesPerClass,1), ... 50 15*randn(numSamplesPerClass,1), ... -50 5*randn(numSamplesPerClass,1), ... 2 1*randn(numSamplesPerClass,1), ... 0.5 0.1*randn(numSamplesPerClass,1)]; X_partial [class1; class2; class3]; % 添加两个孤立的离群点模拟偶发强干扰 outliers [1500, 3, -40, 6, 0.8; 3200, 10, -35, 2, 0.4]; X [X_partial; outliers]; trueLabel [ones(numSamplesPerClass,1); 2*ones(numSamplesPerClass,1); 3*ones(numSamplesPerClass,1); -1; -1];这段数据一共122行每行5列正好对应前面说的5个主要特征。前40行是窄带谐波类中间40行是宽带噪声类后40行是脉冲类最后两行是故意放进去的异常值。我一般先用这种已知标签的数据做验证确认算法流程无误后再换成真实扫频数据。4.2 特征标准化不可跳过的一步生成好特征矩阵后进入标准化的代码。这里有一个重要细节标准化必须在聚类之前对整个X做而不能对每个类别分别做。很多人写代码时图省事忘了这步直接丢进kmeans最后聚类结果几乎全被中心频率这一列支配。% 标准化函数对每列做z-score并丢弃方差接近0的列 function [X_std, keptIdx] zscore_robust(X) numFeatures size(X, 2); mu mean(X, 1); sigma std(X, 0, 1); keptIdx sigma 1e-10; X_std zeros(size(X, 1), sum(keptIdx)); for j 1:sum(keptIdx) col find(keptIdx); X_std(:, j) (X(:, col(j)) - mu(col(j))) / sigma(col(j)); end end这个自定义函数的好处是自动丢弃特征方差为0的列。调用方式[X_std, keptIdx] zscore_robust(X);标准化之后X_std里的每一列都是无量纲的、大致在-3到3之间的数据。现在可以放心去做聚类了。4.3 四种聚类方法核心代码实现下面这段是我在工程项目里一直在用的核心代码四种方法一次性输出结果。% 1) K-means聚类给定聚类数K3 K 3; rng(42); idx_kmeans kmeans(X_std, K, Replicates, 10, MaxIter, 500); % 2) 层次聚类使用Ward连接法 tree linkage(X_std, ward, euclidean); idx_hier cluster(tree, MaxClust, K); % 3) DBSCAN使用自己计算出的epsilon和MinPts epsilon 1.2; % 需要根据K-最近邻距离图调整 MinPts 5; idx_dbscan dbscan(X_std, epsilon, MinPts); % 4) 高斯混合模型GMM也需要指定分量数K gmmModel fitgmdist(X_std, K, RegularizationValue, 1e-5, ... Replicates, 5, Options, statset(MaxIter, 600)); % 得到后验概率矩阵size为 [样本数, K]每行概率之和为1 posteriorProb posterior(gmmModel, X_std); [~, idx_gmm] max(posteriorProb, [], 2);需要注意两个细节。第一K-means里的Replicates能有效避免随机初始值的影响但是设置太大比如50会明显拖慢速度我一般取10。第二GMM里的RegularizationValue千万不要省一旦省略真实数据里特征相关性高的时候协方差矩阵奇异代码直接红字报错报错信息是ill-conditioned covariance。4.4 聚类有效性评估轮廓系数与ARI只看分类结果图就下结论是不够的工程上还需要量化指标来辅助判断这次聚类到底好不好。我通常同时看两个指标。轮廓系数Silhouette Coefficient衡量的是簇内紧密度和簇间分离度的综合情况。轮廓系数范围为-1到1越接近1说明聚类效果越好。Matlab里一行evalclusters就可以搞定eva evalclusters(X_std, idx_kmeans, Silhouette); disp([K-means轮廓系数: , num2str(eva.CriterionValues)]);对模拟数据K-means的轮廓系数一般在0.6到0.8之间说明类内紧凑、类间分离明显。若实际聚类中轮廓系数低于0.4我会立刻回头检查特征工程而不是盲目调聚类参数。第二个指标是调整兰德指数ARI用来比较两种聚类结果的一致性。在干扰源项目里我们用多种聚类方法做交叉验证ARI就是量化它们一致性的工具。比如K-means的结果和层次聚类的结果ARI为1代表完全一致0代表随机一致。Matlab里ari rand_index(idx_kmeans, idx_hier, adjusted); disp([K-means与层次聚类ARI: , num2str(ari)]);rand_index函数是Matlab R2024a之后新增的函数如果老版本没有可以用下面的等价实现替代function ari compute_ari(labels1, labels2) % 用混淆矩阵计算调整兰德指数 n numel(labels1); confusionMat zeros(max(labels1), max(labels2)); for i 1:n confusionMat(labels1(i), labels2(i)) ... confusionMat(labels1(i), labels2(i)) 1; end % 防止DBSCAN的-1噪声标签干扰简单置为独立的较大编号 labels1(labels1 1) max(labels1) 1; % 具体计算过程省略可使用外部实现替代 end在实际项目里我通常要求K-means、层次聚类、GMM三者之间的ARI至少达到0.75才认为分类结果可靠如果达不到通常说明某个干扰源类在特征空间上重叠太严重需要引入新的特征维度。4.5 聚类结果可视化scatter与dendrogram聚类做完不画图等于白做。对干扰源数据二维画图是必须的但因为特征矩阵是五维直接scatter(X(:,1), X(:,2))只能看到两个维度的投影可能恰好把最能区分的维度漏掉了。我的习惯是先做PCA降维保留前两个主成分再上色画图。% PCA降到二维 [coeff, score, ~] pca(X_std); X_pca score(:, 1:2); figure(Color, w, Position, [100 100 900 400]); subplot(1,2,1); gscatter(X_pca(:,1), X_pca(:,2), idx_kmeans, rbk, o^s, 8); grid on; box on; title(K-means聚类结果 (PCA降维), FontSize, 12); xlabel(PC1); ylabel(PC2); subplot(1,2,2); gscatter(X_pca(:,1), X_pca(:,2), idx_dbscan, rbkgm, o^s*d, 8); grid on; box on; title(DBSCAN聚类结果 (PCA降维), FontSize, 12); xlabel(PC1); ylabel(PC2);层次聚类还需要单独画树状图这一步在给客户汇报时特别加分figure(Color, w, Position, [150 100 1000 400]); dendrogram(tree, 0, ColorThreshold, 60); title(层次聚类树状图, FontSize, 12); xlabel(样本序号); ylabel(合并距离);树状图的纵坐标是样本或簇合并时的距离。纵坐标越低就合并的说明两个样本在特征空间里靠得越近。在报告里你可以这样做给出一条虚线阈值。% 根据树状图纵轴手动设置一个合理的切割阈值 threshold 25; subplot(1,1,1); dendrogram(tree, 0); hold on; yline(threshold, --r, 聚类阈值);设置阈值后树状图在虚线下被切割成若干独立子树每棵子树就是一个类别。这个切割位置的选取没有任何公式完全取决于你希望分辨率多高阈值越低类越多部分相似样本会被拆开阈值越高类越少不同源信号可能被合并。这也是层次聚类比K-means多出来的一个自由度但也意味着它更容易被主观选择影响。5. 干扰源聚类里的几个特殊坑5.1 K从哪来肘部图不靠谱时的替代方案K-means和GMM都需要预设类别数K。最经典的方法是肘部图法分别计算K1到8时的组内平方和SSE画出曲线找拐点作为K。这个方法在干扰源数据上经常失效因为真实的干扰源数据往往存在重叠SSE曲线是一条平滑递减线没有明显拐点。我换了一套更可靠的方案先跑一遍DBSCAN用密度聚类得到的簇数作为K的参考初值。DBSCAN不需要预设K虽然在真实数据上有一定调参量但那只是一个参数epsilon比盲目猜K要直观得多。或者在已知部分信号来源的情况下比如现场知道至少有两台变频器和一台焊机在运行可以从业务侧给出K的下限和上限然后在区间内用轮廓系数自动挑K。代码这样写% 遍历K2到6选择轮廓系数最高的K bestK 2; bestScore -inf; for testK 2:6 rng(42); idx_test kmeans(X_std, testK, Replicates, 10); s mean(silhouette(X_std, idx_test)); if s bestScore bestScore s; bestK testK; end end disp([自动选择的K, num2str(bestK), , 轮廓系数, num2str(bestScore)]);这种方式选出的K反映了数据自身的几何结构比靠肉眼盯图更稳定。当然它也不是银弹如果真实干扰源的类在特征空间里呈长尾分布轮廓系数会偏好小K。最终宁可多看看树状图的结构再定。5.2 底噪与离群点不要让单次偶发信号污染聚类中心前面模拟数据里我故意在末尾放了两行离群点。真实场景里这种离群点一点也不罕见一次静电放电、一台微波炉开门的瞬间泄漏、一个汽车点火脉冲都是单次偶发信号特征和任何稳定干扰源都不像。如果直接用K-means处理包含离群点的数据每个离群点都会强行拉偏一个簇中心导致整个类的划分偏移。处理方式分两步。第一步在聚类之前先用DBSCAN跑一遍把被标记为-1的点先剔除掉第二步把剔除的离群点单独做成一个未归类列表后续用K-means或者层次聚类只对剩下的干净集合聚类。这样做的好处是聚类中心不容易被异常值带偏同时未归类列表也方便追溯到单次事件的频谱截图。5.3 特征雷同导致类别吞并一个典型排查过程有一次我们在现场做某产业园区的干扰源摸底四种聚类方法输出了非常不一致的结果。K-means分出4类层次聚类却只分3类DBSCAN更是把四分之一的点标成噪声。查了半天问题出在特征矩阵上两个不同类型的干扰源一个宽带噪声源和一个跳频扩频信号它们的中心频率方差都很大3dB带宽都宽、谱峰数量都少。在特征空间里它们像两个重叠的云团几乎无法区分。这种时候加再多聚类算法也没用。正确的排查思路是回到频域图观察这两个类别在原始频谱包络上的差异。看完发现宽带噪声源的频谱包络是缓慢起伏的锅盖形跳频扩频信号则是一个个小脉冲叠加出的梳子形。于是新加了一个特征包络起伏度计算方式是对归一化包络做相邻点差分的绝对均值。结果两类立即分开聚类一致性也上来了。这个案例想说明的是聚类算法对输入特征极其敏感。方法再多特征没选对一切都是白搭。这也是我在开头强调特征工程是核心的原因。5.4 多方法结果不一致时听谁的交叉验证好是好但也会遇到结果不一致的尴尬时刻。我的处理优先级是按数据量来定数据里混杂大量离群点或噪声时优先选择DBSCAN的结果因为它天生对噪声更稳健数据干净但类边界模糊时优先参考GMM的概率输出因为软分配更符合跳频信号两边沾的物理事实需要给领导做汇报时优先看层次聚类的树状图因为可解释性最强能在大屏幕上直接讲清楚为什么这两条信号归为一类。如果不同方法的划分差异实在太大我会引入共识聚类的思路把多种方法的聚类结果综合成一个相似度矩阵统计两两样本在多少次聚类中被分到同一组然后对这个相似度矩阵再跑一次层次聚类。这个过程相当于让多种算法投票。Matlab里实现也不难用乘法更新相似度矩阵即可下面给一个简版逻辑n size(X_std, 1); consensusMat zeros(n, n); allIdx [idx_kmeans, idx_hier, idx_gmm]; for methodID 1:3 currentIdx allIdx(:, methodID); sameMap (currentIdx - currentIdx 0); consensusMat consensusMat sameMap; end % 归一化到0-1然后做层次聚类 consensusMat consensusMat / 3; distConsensus 1 - consensusMat; treeConsensus linkage(squareform(distConsensus), average); idx_consensus cluster(treeConsensus, MaxClust, bestK);这段代码的思路就是统计每对信号在多个方法里被分到同一类的投票次数。每次被分到一起就累计1分最终得分高说明多种方法都认为它们同源可信度自然高。6. 这份代码在实际项目中的应用边界6.1 适合什么样的数据场景这套基于多种方法聚类分析的流程最适合的场景有三大类。第一类是电磁环境日常监测监测站每天会固定扫一遍辖区内的频谱日积月累攒下几千条异常信号记录用聚类把信号按疑似同源设备归类能辅助判断辖区内有多少种常发性干扰源。第二类是干扰排查的初步筛选当你在某个频段抓到多起互调干扰用聚类把互调产物按干扰源分组能减少逐一交叉定位的耗时。第三类是设备指纹分类同型号的无线设备辐射特征常常近似聚类可以把多个设备的信号归到一类帮助管理人员掌握在用设备的品牌和型号分布。最适合的特征数据格式是每条信号一行、每列一个物理特征的表格。特征来源可以是频谱仪轨迹、矢量信号分析仪的IQ数据、甚至是带RSSI的传感器网络数据。关键限制是同一批数据里特征定义必须完全一致不能上半段用扫频仪分辨率30kHz下半段用分辨率100kHz否则带宽特征的物理含义就变了聚类也会失真。6.2 不适用场景聚类不是定位器也不是标签机有一点必须说清楚干扰源聚类分析做不到精确定位它只能把疑似同一类的信号归组告诉你这些信号的特征行为很像不能告诉你设备的经纬度坐标。如果需要定位聚类结果只能作为预筛选前置步骤聚类之后仍然要配合测向交叉定位或到达时差定位去做单一信号源的物理定位。另外聚类也做不到给它一组信号自动告诉你干扰源的具体设备型号。聚类输出的是第1类、第2类、第3类要把它映射成变频器、微波炉、开关电源还需要人工对每个簇的代表波形做二次识别。我在一些项目里尝试过用聚类簇内的频谱模板去匹配已知设备数据库但准确率受数据库覆盖度影响大目前可靠度还达不到自动化的程度。6.3 扩展方向时频特征、谐波追迹与深层特征距离特征工程基本结束之后还有几步扩展可以做我最近在项目的二期迭代里就沿两个方向在做延伸。第一个扩展方向是时频特征把每条信号切片做短时傅里叶变换STFT然后从时频谱图里提取像频谱图长宽比、频点漂移范围、占空比这类特征。这类特征特别适合区分同频段的跳频信号和定频信号。第二个扩展方向是谐波追迹把一条信号的多次谐波间隔作为特征代码里我已经用了谱峰数量和谐波间隔但如果能把谐波间隔和基频频率做差、做比例可以有效把同一个设备产生的多次谐波识别成一组。至于深层特征我也尝试过直接从频谱包络用自编码器提取低维表示然后用提取出的嵌入向量做聚类。优点是绕过了人工特征设计的偏向性缺点是可解释性差项目汇报时很难向客户解释嵌入向量的第12维代表什么物理量。所以目前来看人工特征加多方法聚类的组合在干扰源分析这个领域依然是实用度最高的平衡方案。最后说一个我自己的强烈建议如果你是新接触这个方法先在模拟数据上跑通整条流程把四种方法和评估指标都体验一遍再换成真实项目数据。真数据里的噪声、丢包、底噪变化都是模拟世界遇不到的但你在模拟世界积累的调参经验和对每种方法脾气的感觉能帮你少走很多弯路。提示别在拿到真实数据的第一天就调epsilon和K先花半天时间认真做特征工程。特征能分开的聚类算法随便选效果都不差特征选不对再高级的聚类算法也无能为力。