射頻檢測(cè)實(shí)戰(zhàn):從SDR信號(hào)采集到MATLAB/Python雙語言識(shí)別)
簡(jiǎn)介這是一套面向無人機(jī)安防與低空監(jiān)管場(chǎng)景的MATLAB/Python代碼庫(kù)聚焦通過射頻信號(hào)實(shí)現(xiàn)無人機(jī)檢測(cè)與識(shí)別適合無線信號(hào)處理、機(jī)器學(xué)習(xí)方向的研究者和開發(fā)者直接參考或復(fù)用。資源壓縮包共18個(gè)文件大小僅1.85MB核心包括7個(gè)MATLAB腳本、1個(gè)Python分類腳本以及LabVIEW射頻錄制與回放工程和README/PDF說明文檔覆蓋從數(shù)據(jù)聚合、信號(hào)標(biāo)注到特征分析和分類實(shí)驗(yàn)的完整鏈路。已有182人學(xué)習(xí)下載。源碼附帶了多個(gè)可直接運(yùn)行的演示模塊能夠?qū)o人機(jī)射頻信號(hào)進(jìn)行頻率、強(qiáng)度、模式等特征提取并借助SVM、決策樹、隨機(jī)森林等算法訓(xùn)練識(shí)別模型同時(shí)保留了數(shù)據(jù)清洗與結(jié)果可視化環(huán)節(jié)LabVIEW模塊可用于真實(shí)信號(hào)錄制與回放便于搭建實(shí)驗(yàn)環(huán)境。這套開源代碼降低了無人機(jī)信號(hào)識(shí)別技術(shù)門檻無論用于科研驗(yàn)證還是實(shí)際項(xiàng)目開發(fā)都能提供清晰的實(shí)現(xiàn)路徑。 先說個(gè)結(jié)論無人機(jī)射頻檢測(cè)這類項(xiàng)目80%的精力都花在數(shù)據(jù)側(cè)和信號(hào)前端模型反而是最后才需要考慮的問題。我最近整理了一套基于無人機(jī)射頻信號(hào)做無人機(jī)檢測(cè)和識(shí)別的代碼倉(cāng)庫(kù)同時(shí)包含MATLAB和Python兩套實(shí)現(xiàn)最近在社區(qū)里反復(fù)和人聊這些代碼怎么用、為什么這么設(shè)計(jì)。這里把整個(gè)系統(tǒng)的思路、關(guān)鍵算法、踩坑過程和可復(fù)現(xiàn)細(xì)節(jié)一次性講清楚適合準(zhǔn)備用低成本SDR起步做射頻感知、或者剛拿到類似開源倉(cāng)庫(kù)準(zhǔn)備二次開發(fā)的工程師。這套代碼解決的事情說簡(jiǎn)單點(diǎn)就是在某個(gè)區(qū)域部署一臺(tái)接收機(jī)通過被動(dòng)接收無人機(jī)遙控鏈路和圖傳鏈路產(chǎn)生的射頻信號(hào)判斷無人機(jī)是否存在以及識(shí)別它屬于哪一類、哪一型號(hào)。代碼鏈路從IQ采集、預(yù)處理、特征提取到分類器訓(xùn)練和推理都有對(duì)應(yīng)模塊。我把MATLAB和Python的邊界劃得很清楚MATLAB負(fù)責(zé)信號(hào)處理原型驗(yàn)證Python負(fù)責(zé)機(jī)器學(xué)習(xí)與最終部署兩邊用統(tǒng)一的文件格式交換數(shù)據(jù)。你如果期待的是無人機(jī)雷達(dá)測(cè)向或者三維定位這個(gè)倉(cāng)庫(kù)不合適它做的是射頻信號(hào)層面的檢測(cè)和識(shí)別。1. 無人機(jī)射頻檢測(cè)到底在解決什么問題1.1 無人機(jī)的“射頻指紋”藏在哪些鏈路里消費(fèi)級(jí)無人機(jī)工作時(shí)至少有兩套射頻鏈路處于活躍狀態(tài)遙控鏈路和圖傳鏈路。遙控鏈路通常使用2.4GHz或5.8GHz的ISM頻段圖傳鏈路也集中在這附近有些機(jī)型還走5.2GHz。關(guān)鍵在于即使沒有回傳圖像遙控器與無人機(jī)之間也會(huì)周期性發(fā)送控制包比如固定每幾十毫秒一包用于保持鏈路同步和指令交互。這意味著只要無人機(jī)在飛射頻信號(hào)就會(huì)間歇性出現(xiàn)。這些信號(hào)在頻譜上通常表現(xiàn)為幾種形態(tài)遙控信號(hào)多采用跳頻或窄帶調(diào)制在頻譜圖上是一系列跳來跳去的窄峰圖傳信號(hào)帶寬比遙控寬很多可能是幾十MHz甚至更寬的OFDM波形。所以射頻檢測(cè)的核心是對(duì)這些形態(tài)進(jìn)行持續(xù)監(jiān)控從周圍一大堆Wi-Fi、藍(lán)牙、運(yùn)營(yíng)商通信和工業(yè)噪聲里把無人機(jī)的特征摘出來。1.2 檢測(cè)、識(shí)別和定位是三個(gè)不同難度很多人把“檢測(cè)”和“識(shí)別”混在一起實(shí)際上這是兩個(gè)完全不同的任務(wù)。檢測(cè)是二分類問題回答“這個(gè)頻段里有沒有疑似無人機(jī)信號(hào)”識(shí)別是分類問題回答“如果檢測(cè)到它屬于哪類設(shè)備或哪個(gè)型號(hào)”。倉(cāng)庫(kù)里兩個(gè)任務(wù)都有代碼路徑。檢測(cè)用能量和頻域特征輸出異常分?jǐn)?shù)識(shí)別用機(jī)器學(xué)習(xí)模型對(duì)信號(hào)片段分類比如區(qū)分“大疆Mavic系列”“穿越機(jī)圖傳”“普通遙控器開關(guān)信號(hào)”。識(shí)別粒度完全取決于訓(xùn)練數(shù)據(jù)里有哪些標(biāo)簽別指望一個(gè)只有三類樣本的模型到現(xiàn)場(chǎng)能認(rèn)出新機(jī)型的固件差異。定位則是另一個(gè)量級(jí)的問題需要多通道陣列天線、相位差校準(zhǔn)和DOA估計(jì)算法。這個(gè)倉(cāng)庫(kù)沒有覆蓋定位但后續(xù)可以在數(shù)據(jù)采集端預(yù)留多通道接口。1.3 被動(dòng)射頻方案在工程上有什么優(yōu)勢(shì)我選擇射頻方案而不是視覺或雷達(dá)是因?yàn)樗袔讞l非常實(shí)際的好處第一被動(dòng)接收不主動(dòng)發(fā)射電磁波部署合規(guī)壓力小也適合長(zhǎng)時(shí)間值守第二設(shè)備成本低一套軟件無線電接收機(jī)加上天線幾百到幾千塊錢就能起步第三不受光照和雨霧影響監(jiān)控終端放在室內(nèi)天線外置就能連續(xù)工作。當(dāng)然也有明顯短板射頻方案無法直接測(cè)距只能告訴你“這個(gè)區(qū)域里有某種無人機(jī)在通信”不能告訴你它飛在哪個(gè)方向、離你多遠(yuǎn)。所以工程上通常用射頻做廣域感知再用其他手段做精確定位。2. 數(shù)據(jù)是怎么來的接收機(jī)選型、采樣參數(shù)與數(shù)據(jù)集構(gòu)建2.1 低成本的SDR硬件能做到什么程度倉(cāng)庫(kù)默認(rèn)使用軟件無線電接收機(jī)采集數(shù)據(jù)。不同硬件的能力差別很大實(shí)測(cè)過幾類常見的設(shè)備這里直接給個(gè)選型參考設(shè)備頻率范圍最大采樣帶寬適合場(chǎng)景RTL-SDR24MHz-1.7GHz約2.4MSPS低頻段實(shí)驗(yàn)驗(yàn)證2.4GHz需要碰運(yùn)氣HackRF One1MHz-6GHz20MSPS2.4GHz/5.8GHz主流無人機(jī)頻段采集USRP B20070MHz-6GHz56MSPS多通道、高質(zhì)量數(shù)據(jù)集用于復(fù)雜模型如果只做遙控鏈路檢測(cè)RTL-SDR那套方案在1GHz以下頻段還能用但消費(fèi)級(jí)無人機(jī)大多在2.4GHz和5.8GHzRTL-SDR在2.4GHz接收能力很有限。我測(cè)試后最推薦HackRF One起步覆蓋頻率夠、采樣帶寬夠、驅(qū)動(dòng)生態(tài)也成熟。采樣率不要貪高。HackRF雖然能開到20MHz帶寬但帶寬越大單文件數(shù)據(jù)量越大后面做訓(xùn)練時(shí)的I/O瓶頸越明顯。倉(cāng)庫(kù)默認(rèn)用2MSPS或4MSPS先把窄帶遙控鏈路的檢測(cè)驗(yàn)證完再考慮要不要拉高帶寬抓圖傳。2.2 采集環(huán)境與標(biāo)注方法采集時(shí)除了記錄IQ數(shù)據(jù)本身還要同步記錄一份metadata中心頻率、采樣率、時(shí)間戳、無人機(jī)型號(hào)、遙控模式、圖傳開關(guān)狀態(tài)、環(huán)境類型開闊地、樓宇旁、工業(yè)區(qū)。這些信息是后續(xù)分析特征漂移的關(guān)鍵比樣本本身更重要。標(biāo)注我建議半自動(dòng)方式先用MATLAB把采集文件畫成頻譜圖人工標(biāo)記有信號(hào)的時(shí)間段再寫腳本把對(duì)應(yīng)區(qū)間切成1秒窗口。不要手工一個(gè)個(gè)截速度慢且容易標(biāo)錯(cuò)。標(biāo)簽也不要只寫“有無人機(jī)”盡量寫“機(jī)型遙控模式圖傳開/關(guān)”這樣訓(xùn)練出來的模型更有實(shí)際意義也能方便排查錯(cuò)誤。數(shù)據(jù)集的構(gòu)成上一定保留三類樣本純背景噪聲、無人機(jī)信號(hào)、同頻段干擾信號(hào)。很多人只采集無人機(jī)和靜默噪聲結(jié)果模型把Wi-Fi突發(fā)當(dāng)成了無人機(jī)因?yàn)橛?xùn)練時(shí)從沒見過這種負(fù)樣本。2.3 數(shù)據(jù)規(guī)模與平衡策略如果只有剛開始采集的幾百條樣本別急著上深度學(xué)習(xí)。我的經(jīng)驗(yàn)是每類至少300秒信號(hào)加上同等時(shí)長(zhǎng)的純?cè)肼曄劝褌鹘y(tǒng)機(jī)器學(xué)習(xí)基線跑出來。分類不平衡時(shí)可以在傳統(tǒng)模型里用類別加權(quán)或者在時(shí)頻圖上做頻移和噪聲疊加增強(qiáng)比在IQ空間里做回波增強(qiáng)容易得多。3. MATLAB與Python各承擔(dān)什么角色雙語言管線拆解3.1 MATLAB側(cè)快速驗(yàn)證信號(hào)處理邏輯我習(xí)慣用MATLAB做采集數(shù)據(jù)的離線預(yù)覽和信號(hào)前端驗(yàn)證。Signal Processing Toolbox里的spectrogram、cwt、medfilt1、findpeaks都很成熟畫時(shí)頻圖、做閾值分割非常快。檢測(cè)部分的核心邏輯其實(shí)很短讀IQ數(shù)據(jù)分幀做FFT估計(jì)噪聲底再去找連續(xù)超閾值的頻帶。MATLAB里寫起來大概是這樣cfg jsondecode(fileread(config/config.json)); x read_iq(cfg.data_file); [S, F, T] spectrogram(x, hamming(cfg.fft_size), cfg.overlap, cfg.fft_size, cfg.fs); pow_dB 10*log10(abs(S) eps); noise_floor median(pow_dB, 2) cfg.threshold_k * std(pow_dB, 0, 2); flag any(pow_dB noise_floor, 1);這套東西在MATLAB里迭代很快但我從不把訓(xùn)練放MATLAB。矩陣實(shí)驗(yàn)室的強(qiáng)項(xiàng)是算法原型工程化訓(xùn)練還是放Python更順。3.2 Python側(cè)特征工程、訓(xùn)練和推理Python這邊我用VSCode配合venv管理環(huán)境Python 3.9起步。倉(cāng)庫(kù)的依賴很簡(jiǎn)單numpy、scipy、scikit-learn、matplotlib深度學(xué)習(xí)可選tensorflow或pytorch。Dataloader用numpy從二進(jìn)制文件讀IQscipy.signal做重采樣和濾波特征用scikit-learn的train_test_split劃分分類器默認(rèn)RandomForest模型庫(kù)里也放了一個(gè)三層CNN用于擴(kuò)展。這里有個(gè)原則不要在Python里重復(fù)做復(fù)雜的信號(hào)前端處理能在MATLAB離線預(yù)處理好的就提前做完。訓(xùn)練代碼只關(guān)心窗口化特征就好。import numpy as np raw np.fromfile(path, dtypenp.float32) iq raw[0::2] 1j * raw[1::2]3.3 兩套代碼如何交換數(shù)據(jù)很多開源倉(cāng)庫(kù)MATLAB和Python各玩各的數(shù)據(jù)格式對(duì)不上最后我都要重構(gòu)一遍。這個(gè)倉(cāng)庫(kù)里我統(tǒng)一采用原始IQ存為float32二進(jìn)制文件metadata放同路徑JSON預(yù)處理后的特征數(shù)組存成.npy文件。MATLAB端不直接寫.npy可以借助現(xiàn)成的npy讀寫工具庫(kù)或者干脆輸出無頭二進(jìn)制文件Python這邊用np.fromfile讀。不要依賴.mat作為唯一交換格式Python讀.mat的體驗(yàn)太差HDF5和npy都更順。4. 檢測(cè)與識(shí)別算法從能量檢測(cè)到深度學(xué)習(xí)的完整方案4.1 作為底線的能量檢測(cè)和頻域特征無人機(jī)控制信號(hào)在頻域上通常表現(xiàn)為瞬時(shí)的窄帶峰或跳頻序列和寬帶Wi-Fi圖傳不太一樣。最簡(jiǎn)單可靠的檢測(cè)算法是分幀F(xiàn)FT后用噪聲底加一個(gè)動(dòng)態(tài)閾值找出超過閾值的頻窗。閾值不能寫死。先對(duì)每個(gè)頻點(diǎn)做中位數(shù)濾波得到噪聲底估計(jì)再乘一個(gè)系數(shù)作為檢測(cè)門限。系數(shù)建議3-5倍標(biāo)準(zhǔn)差太小會(huì)把環(huán)境底噪誤判成信號(hào)太大又會(huì)漏掉弱信號(hào)。多個(gè)連續(xù)幀在同一頻帶出現(xiàn)才判定為可疑源這可以濾掉瞬時(shí)干擾。更穩(wěn)一點(diǎn)可以上CFAR檢測(cè)但小樣本下和動(dòng)態(tài)閾值差距不大。我的建議是先用動(dòng)態(tài)閾值跑通流程再根據(jù)實(shí)際誤報(bào)率決定要不要上CFAR。4.2 傳統(tǒng)特征加隨機(jī)森林小數(shù)據(jù)集的首選當(dāng)標(biāo)注樣本只有幾千條時(shí)深度學(xué)習(xí)優(yōu)勢(shì)不大隨機(jī)森林加手工特征是最穩(wěn)的路線。倉(cāng)庫(kù)里提供了一個(gè)特征表對(duì)每個(gè)1秒窗口提取RMS、峰值均值比、頻譜平坦度、頻帶寬度、峰值個(gè)數(shù)、零交叉率、譜熵再加上STFT頻帶的幾個(gè)統(tǒng)計(jì)量。這些特征加在一起用隨機(jī)森林在5倍交叉驗(yàn)證下通常能到90%左右。特征選擇別貪多先用全量特征跑一版再用feature_importance把明顯沒用的特征去掉。RF模型在幾百棵樹以上性能提升非常有限100棵樹足夠作為默認(rèn)。4.3 時(shí)頻圖加CNN數(shù)據(jù)量夠大的時(shí)候再用如果數(shù)據(jù)集到了幾萬條數(shù)量級(jí)再把時(shí)頻圖送CNN。具體做法是把每個(gè)窗口的STFT幅度譜歸一化成灰度圖輸入一個(gè)簡(jiǎn)單卷積網(wǎng)絡(luò)。倉(cāng)庫(kù)里放的是一個(gè)輕量模型64x64輸入三層Conv2D加BN加MaxPoolDense層64維加Dropout最后softmax輸出類型。STFT參數(shù)直接決定識(shí)別效果。FFT長(zhǎng)度決定頻率分辨率窗口長(zhǎng)度決定時(shí)間分辨率。對(duì)無人機(jī)跳頻遙控信號(hào)我建議FFT長(zhǎng)度1024、50%重疊這樣頻譜細(xì)節(jié)和時(shí)間細(xì)節(jié)都有保障。直接用原始IQ訓(xùn)練也不是不行但時(shí)頻圖的可解釋性更好也方便在圖上做頻移、噪聲疊加這類數(shù)據(jù)增強(qiáng)。5. 實(shí)測(cè)中踩過的幾個(gè)坑與完整排查思路5.1 測(cè)試集準(zhǔn)確率很高現(xiàn)場(chǎng)檢測(cè)率突然下降第一個(gè)版本在實(shí)驗(yàn)室里用錄好的文件測(cè)試準(zhǔn)確率95%。拿到室外開闊地一跑誤報(bào)率瞬間上來。排查鏈路是這樣的先看實(shí)時(shí)頻譜圖發(fā)現(xiàn)環(huán)境里頻段占用明顯噪聲底比實(shí)驗(yàn)室高8dB左右。原來的檢測(cè)閾值是固定值到新環(huán)境自然失靈。解決辦法是把所有閾值改成和環(huán)境噪聲底實(shí)時(shí)綁定的相對(duì)值誤報(bào)立刻降下來。這個(gè)教訓(xùn)之后倉(cāng)庫(kù)里所有檢測(cè)參數(shù)都改成了動(dòng)態(tài)形式不再提供寫死的絕對(duì)閾值。5.2 同一型號(hào)無人機(jī)的特征漂移第二種典型問題同一款無人機(jī)遙控器固件版本不同跳頻序列和包長(zhǎng)度會(huì)有變化。模型在舊固件上識(shí)別很好新固件樣本進(jìn)來后置信度明顯下降。我一開始以為是模型過擬合后來把新舊固件的時(shí)頻圖放在一起對(duì)比才發(fā)現(xiàn)根本不是過擬合而是特征分布確實(shí)移動(dòng)了。解決辦法是訓(xùn)練時(shí)盡量多采集幾臺(tái)不同批次、不同固件的設(shè)備人為制造多樣性。另外天線朝向也影響信號(hào)幅度模型不能太依賴幅度特征要更多使用頻域形狀特征。5.3 實(shí)時(shí)推理卡頓先查數(shù)據(jù)管線別賴模型在樹莓派或者普通筆記本上跑實(shí)時(shí)推理模型本身只占少量CPU反而從SDR讀取數(shù)據(jù)、分幀做FFT、窗口滑動(dòng)的整個(gè)流程特別慢。我起初以為是模型太重profile之后發(fā)現(xiàn)瓶頸在SDR讀取函數(shù)阻塞了后面的計(jì)算。解決方法是把實(shí)時(shí)鏈路改成獨(dú)立采集線程加隊(duì)列緩存采集線程只管把數(shù)據(jù)塊塞進(jìn)隊(duì)列識(shí)別線程從隊(duì)列里取批處理最后用一個(gè)批處理STFT統(tǒng)一出結(jié)果。倉(cāng)庫(kù)里的infer_live.py用的就是這個(gè)結(jié)構(gòu)不要再看成一行while True循環(huán)讀數(shù)據(jù)算一次的例子。6. 倉(cāng)庫(kù)結(jié)構(gòu)、參數(shù)配置與后續(xù)擴(kuò)展方向6.1 一個(gè)拿來就能跑的目錄長(zhǎng)這樣倉(cāng)庫(kù)我建議按語言拆開但共享配置和數(shù)據(jù)路徑drone-rf-detector/ ├── matlab/ │ ├── acquisition/ │ ├── preprocessing/ │ └── visualization/ ├── python/ │ ├── dataloader.py │ ├── features.py │ ├── train_ml.py │ ├── train_cnn.py │ └── infer_live.py ├── config/ │ └── config.json ├── data/ │ ├── raw/ │ └── processed/ └── models/讀完一個(gè)目錄就能知道每個(gè)文件的職責(zé)比把所有腳本堆在根目錄要省心得多。所有腳本從config.json讀路徑和參數(shù)不在代碼里寫絕對(duì)路徑。6.2 環(huán)境配置和幾個(gè)關(guān)鍵參數(shù)MATLAB側(cè)建議安裝Signal Processing Toolbox和Communications Toolbox我測(cè)試時(shí)用的MATLAB R2022b跑在Linux下Windows也沒有問題。Python側(cè)就是VSCode加venv依賴寫進(jìn)requirements.txt不要用一堆Anaconda channel折騰環(huán)境。幾個(gè)關(guān)鍵參數(shù)給出一組默認(rèn)值實(shí)際用時(shí)要重新標(biāo)定參數(shù)建議值說明center_freq2.45GHz遙控鏈路主要頻段sample_rate2MSPS窄帶遙控信號(hào)夠用fft_size1024頻率分辨率約1.95kHzoverlap512時(shí)間重疊50%threshold_k3-5噪聲底倍數(shù)6.3 后續(xù)可擴(kuò)展方向這套系統(tǒng)其實(shí)只是第一層。后續(xù)可以在接收端加第二個(gè)通道用兩通道之間的相位差做來波方向估計(jì)也可以朝設(shè)備指紋方向做嘗試識(shí)別同一型號(hào)的不同個(gè)體邊緣部署方面可以把Python腳本導(dǎo)出成TensorRT或者C實(shí)現(xiàn)跑在更輕量的設(shè)備上。我自己下一步打算把整套代碼遷移到樹莓派5上用多通道同步采集試試看看延遲和識(shí)別精度能到什么程度。有實(shí)際結(jié)果再單獨(dú)寫一篇。本文還有配套的精品資源點(diǎn)擊獲取