字下變頻:FPGA實現(xiàn)帶通采樣及抽取濾波鏈路設(shè)計)
1. 從射頻到基帶中頻采樣到底在解決什么問題搞過軟件無線電或者雷達接收鏈路的人大概率都繞不開一個經(jīng)典架構(gòu)選擇射頻信號下來之后到底是在射頻直接采樣還是先搬到中頻再采樣這個問題我在不同項目里反復(fù)遇到過每次選型都得重新算一遍賬。中頻采樣與數(shù)字下變頻這套組合拳本質(zhì)上解決的是一個很樸素的矛盾——ADC的采樣率上限和信號帶寬需求之間的沖突。先說背景。按照奈奎斯特采樣定理要無失真地恢復(fù)一個信號采樣率至少得是信號最高頻率的兩倍。假設(shè)你有一個中心頻率2.4GHz、帶寬20MHz的射頻信號如果直接對這個射頻信號采樣理論上采樣率得超過4.8GHz。這個量級的ADC不僅貴得離譜功耗和散熱也是災(zāi)難。但如果你先把射頻信號通過模擬混頻搬到一個較低的中頻比如70MHz或者140MHz這時候信號的中心頻率降下來了帶寬還是20MHz你只需要一個采樣率略高于140MHz的ADC就能搞定。這就是中頻采樣存在的第一個理由用模擬混頻換取ADC采樣率的降低。但中頻采樣還有第二個更精妙的地方叫做帶通采樣。這個概念很多人第一次接觸會覺得反直覺。假設(shè)中頻信號中心頻率70MHz帶寬20MHz信號實際占據(jù)的頻譜范圍是60MHz到80MHz。按照低通采樣的思路采樣率得大于160MHz。但帶通采樣定理告訴我們只要采樣率滿足特定條件用遠低于信號最高頻率的采樣率也能無混疊地采到這個帶通信號。具體來說如果信號帶寬為B中心頻率為f0采樣率fs滿足2B ≤ fs ≤ 2f0/(m)這樣的關(guān)系m取滿足條件的整數(shù)就能實現(xiàn)頻譜搬移式的采樣。比如上面這個例子選fs50MHz信號會被搬到12.5MHz附近依然完整保留20MHz帶寬的信息。這里有個關(guān)鍵點容易被忽略帶通采樣不是沒有代價的。采樣之后信號的頻譜會以fs為周期進行延拓如果參數(shù)選得不好延拓出來的頻譜副本會和原始頻譜重疊產(chǎn)生混疊。所以選采樣率的時候必須畫頻譜圖驗證不能拍腦袋。我一般會先在紙上把信號頻譜、采樣頻率、各次諧波的位置都標(biāo)出來確認沒有重疊再往下走。那數(shù)字下變頻又是在干什么ADC采樣之后你拿到的是一個實信號序列頻譜關(guān)于零頻對稱正負頻率各有一半。但通信或者雷達處理真正關(guān)心的是基帶復(fù)信號也就是I/Q兩路。數(shù)字下變頻的核心任務(wù)就是把中頻上的帶通信號搬到零頻附近同時產(chǎn)生正交的I/Q兩路并且通過抽取濾波把采樣率降下來減輕后續(xù)處理壓力。整個過程用數(shù)字方式實現(xiàn)避免了模擬混頻器的本振泄漏、I/Q不平衡等一堆麻煩事。所以這套架構(gòu)的完整鏈路是射頻信號 → 模擬混頻搬到中頻 → ADC帶通采樣 → 數(shù)字下變頻混頻抽取濾波→ 基帶I/Q信號 → 后續(xù)解調(diào)或脈壓處理。每一步都有它的道理缺一不可。適合閱讀這篇內(nèi)容的人應(yīng)該是對FPGA信號處理有一定了解、正在做接收機鏈路設(shè)計、或者想搞清楚軟件無線電底層原理的工程師。如果你之前只是調(diào)用過現(xiàn)成的IP核沒自己算過參數(shù)、沒踩過混疊的坑那接下來的內(nèi)容應(yīng)該能幫你把這條鏈路真正吃透。2. 帶通采樣的參數(shù)計算別讓混疊毀掉你的鏈路2.1 采樣率選擇的約束條件推導(dǎo)帶通采樣的采樣率選擇不是隨便挑一個大于兩倍帶寬的數(shù)就行。我見過太多人在這里翻車包括我自己早期做的一個項目當(dāng)時選了個自認為很安全的采樣率結(jié)果頻譜搬移之后發(fā)現(xiàn)邊帶剛好壓在一起信噪比直接掉了十幾個dB。后來老老實實把公式推了一遍才搞明白問題出在哪。帶通采樣定理的完整表述是這樣的對于一個帶寬為B、最高頻率為fH的帶通信號如果采樣率fs滿足fs ≥ 2B保證帶寬信息不丟失存在整數(shù)m使得 2fH/m ≤ fs ≤ 2fL/(m-1)其中fL是信號最低頻率fH是最高頻率m取滿足條件的正整數(shù)。這個公式看起來有點繞但實際操作的時候可以換個思路先確定你希望信號被搬到哪個頻率位置然后反推采樣率。舉個實際例子。假設(shè)中頻信號中心頻率140MHz帶寬20MHz所以fL130MHzfH150MHz。我想讓采樣后的信號落在20MHz到40MHz這個區(qū)間中心30MHz那么采樣率應(yīng)該選多少信號搬移后的中心頻率f_if和原始中心頻率f0、采樣率fs的關(guān)系是f_if |f0 - k·fs|其中k是某個整數(shù)。代入f0140MHzf_if30MHz如果k1則fs110MHz如果k2則fs55MHz。驗證一下55MHz是否滿足帶通采樣條件2B40MHz ≤ 55MHz且2fH/m ≤ fs ≤ 2fL/(m-1)取m52×150/5602×130/46560 ≤ 55不成立。取m62×150/6502×130/55250 ≤ 55 ≤ 52不成立。所以55MHz不行。再試110MHzm2時2×150/21502×130/1130130 ≤ 110不成立。m3時2×150/31002×130/2130100 ≤ 110 ≤ 130成立。所以110MHz是可行的。這個計算過程看起來繁瑣但實際做幾次就有感覺了。我通常會在Excel里拉一個表把可能的m值和對應(yīng)的采樣率范圍都列出來然后從中挑一個和ADC器件支持的采樣率最接近的值。2.2 采樣后頻譜搬移的直觀理解很多人對帶通采樣的頻譜搬移感到困惑覺得信號怎么就從140MHz跑到30MHz去了。其實用一句話就能解釋清楚采樣就是在頻域上把原始頻譜以fs為周期進行復(fù)制粘貼。原始信號在140MHz附近采樣之后它的頻譜副本會出現(xiàn)在140±n·fs的位置上。你只需要找到其中一個落在低頻區(qū)域的副本那就是你想要的。還是用上面的例子fs110MHz原始信號在130到150MHz。采樣后頻譜副本出現(xiàn)在130-11020MHz 到 150-11040MHz這就是我們要的130110240MHz 到 150110260MHz130-220-90MHz 到 150-220-70MHz負頻率對應(yīng)正頻率的鏡像可以看到20到40MHz這個副本完整保留了20MHz的帶寬信息而且和別的副本沒有重疊。這就是帶通采樣的精髓用低采樣率把高頻信號折疊到低頻同時保證折疊后的頻譜不重疊。但這里有個坑如果信號本身不是理想的帶通信號比如帶外有噪聲或者雜散這些成分也會被折疊進來。所以中頻濾波器的作用非常關(guān)鍵必須在ADC之前把帶外成分濾干凈。我一般會在中頻放大器后面加一個聲表濾波器或者LC帶通濾波器把帶外抑制做到40dB以上這樣折疊進來的噪聲才不會影響靈敏度。2.3 采樣時鐘抖動對信噪比的影響選好了采樣率接下來要關(guān)注的是采樣時鐘的質(zhì)量。ADC的信噪比不僅取決于量化位數(shù)還和采樣時鐘的抖動密切相關(guān)。時鐘抖動會導(dǎo)致采樣時刻偏離理想位置對于高頻信號來說這個偏差會被放大。具體的關(guān)系可以用這個公式估算SNR_jitter -20·log10(2π·f·σ_t)其中f是信號頻率σ_t是時鐘抖動的RMS值。假設(shè)你的中頻信號在140MHz時鐘抖動是1ps RMS那么SNR_jitter -20·log10(2π×140e6×1e-12) ≈ -20·log10(8.8e-4) ≈ 61dB。如果你用的是12位ADC理論SNR大約是74dB但時鐘抖動把實際SNR限制到了61dB。如果時鐘抖動惡化到10psSNR直接掉到41dB12位ADC就浪費了。所以選中頻采樣方案的時候時鐘源的選擇和PCB布局的走線質(zhì)量必須重視。我一般會選相位噪聲指標(biāo)好的晶振或者時鐘芯片比如-150dBc/Hz10kHz偏移這種級別的。PCB上時鐘走線要遠離數(shù)字信號線盡量走差分包地處理。這些細節(jié)看起來不起眼但實測的時候差別很大。3. 數(shù)字下變頻的FPGA實現(xiàn)從混頻到抽取的完整鏈路3.1 數(shù)字混頻把中頻信號搬到零頻ADC采樣之后你拿到的是實信號序列假設(shè)采樣率110MHz信號中心在30MHz。數(shù)字下變頻的第一步是混頻也就是把這個30MHz的信號搬到零頻。做法很簡單把ADC數(shù)據(jù)分別乘以cos(2π·30e6·n/110e6)和-sin(2π·30e6·n/110e6)得到I路和Q路。在FPGA里實現(xiàn)這個乘法通常用查找表或者CORDIC算法生成正余弦值。查找表的做法是把一個周期的正余弦波形量化成N個點存到ROM里然后用一個相位累加器控制讀取地址。相位累加器的位寬決定了頻率分辨率比如32位累加器時鐘110MHz頻率分辨率就是110e6/2^32 ≈ 0.0256Hz完全夠用。這里有個實際的問題NCO數(shù)控振蕩器的輸出頻率必須和ADC采樣率相干否則混頻之后會有殘余的頻率偏差。所謂相干就是NCO頻率和采樣率之比是有理數(shù)而且最好能整除。比如采樣率110MHzNCO頻率30MHz110/3011/3不是整數(shù)比但相位累加器每3個采樣點走11個周期還是能保證相位連續(xù)。如果NCO頻率是27.5MHz110/27.54正好整除相位累加器每4個點走一個完整周期實現(xiàn)起來更簡單?;祛l之后的信號是復(fù)數(shù)形式I路和Q路各一路。這時候信號的頻譜已經(jīng)從30MHz搬到了零頻附近正頻率部分在0到10MHz負頻率部分在-10到0MHz。但注意由于輸入是實信號I路和Q路是相關(guān)的不是獨立的。真正要得到獨立的I/Q還需要后面的低通濾波和抽取。3.2 抽取濾波降采樣率同時保留有用信號混頻之后信號帶寬還是20MHz但采樣率還是110MHz數(shù)據(jù)率太高后續(xù)處理吃不消。這時候需要抽取也就是每隔M個點取一個把采樣率降到110/M MHz。但直接抽取會出問題如果抽取后的采樣率不滿足奈奎斯特條件信號會混疊。所以在抽取之前必須先低通濾波把信號帶寬限制到新的奈奎斯特頻率以內(nèi)。假設(shè)我要把采樣率降到27.5MHz抽取因子M4。新的奈奎斯特頻率是13.75MHz而信號帶寬是20MHz從-10到10MHz超過了13.75MHz。所以不能直接抽4倍得先濾波把帶寬限制到13.75MHz以內(nèi)。但這樣會損失信號帶寬不行。那怎么辦答案是用多級抽取先濾掉一部分抽一次再濾再抽。實際工程中常用的結(jié)構(gòu)是CIC濾波器加半帶濾波器再加FIR濾波器。CIC濾波器適合大倍數(shù)抽取不需要乘法器但通帶不平坦需要后級補償。半帶濾波器系數(shù)對稱有一半是零乘法器用量少適合2倍抽取。FIR濾波器可以做成任意響應(yīng)但資源消耗大一般放在最后一級做精細整形。我做過的一個項目中采樣率110MHz信號帶寬20MHz目標(biāo)是把采樣率降到27.5MHz。方案是第一級CIC抽取2倍采樣率降到55MHz第二級半帶濾波器抽取2倍降到27.5MHz。CIC的通帶衰減在10MHz處大約是0.5dB半帶濾波器在10MHz處也有約0.5dB衰減加起來1dB左右可以接受。如果對通帶平坦度要求更高可以在最后加一個小的補償FIR。3.3 多相濾波結(jié)構(gòu)資源優(yōu)化的關(guān)鍵技巧抽取濾波器的直接實現(xiàn)有個問題如果先濾波再抽取濾波器在每個采樣點都要算一遍但抽取之后只保留M個點中的一個意味著M-1個點的計算被浪費了。多相濾波結(jié)構(gòu)就是來解決這個問題的。多相濾波的思路是把濾波器的系數(shù)按照抽取因子M分成M組每組系數(shù)對應(yīng)一個相位。輸入數(shù)據(jù)也按照M的節(jié)奏分配給不同的相位分支每個分支只計算自己那一路的卷積最后把M個分支的輸出按順序拼接起來。這樣計算量降到了原來的1/M資源消耗大幅降低。具體實現(xiàn)的時候假設(shè)濾波器有N個抽頭抽取因子M那么每個多相分支有N/M個抽頭。輸入數(shù)據(jù)以M為周期輪流進入各個分支每個分支的輸出就是該分支系數(shù)和對應(yīng)輸入數(shù)據(jù)的卷積。最后用一個M選一的并串轉(zhuǎn)換把各路輸出合成一路。這個結(jié)構(gòu)在FPGA里實現(xiàn)起來很自然因為FPGA本來就擅長并行處理。我一般會用移位寄存器組來緩存輸入數(shù)據(jù)然后用M個并行的乘加單元同時計算各分支的輸出。如果資源緊張也可以只用一個乘加單元分時復(fù)用但那樣時鐘頻率得跑得更高。4. 實測中容易踩的坑與排查思路4.1 頻譜出現(xiàn)鏡像I/Q不平衡的排查數(shù)字下變頻之后理想情況下正頻率和負頻率應(yīng)該完全分開頻譜上只看到一邊。但實際調(diào)試的時候經(jīng)常會在另一邊看到一個鏡像分量幅度可能只比主信號低20到30dB。這個鏡像就是I/Q不平衡造成的。I/Q不平衡的來源有幾個一是NCO產(chǎn)生的正余弦幅度不一致二是I路和Q路的濾波器系數(shù)有差異三是混頻之后的增益不一致。排查的時候可以逐級看先在混頻輸出接一個頻譜儀或者用FPGA的ILA抓數(shù)據(jù)做FFT看I路和Q路的幅度是否一致然后看濾波器的頻率響應(yīng)是否對稱最后看NCO的查找表精度是否夠。解決I/Q不平衡的辦法最直接的是提高NCO查找表的精度和濾波器的對稱性。如果硬件已經(jīng)定了也可以在數(shù)字域做校正比如用一個復(fù)數(shù)濾波器來補償幅度和相位誤差。我一般會在設(shè)計階段就把NCO的查找表做到16位以上濾波器系數(shù)用對稱結(jié)構(gòu)這樣鏡像抑制能做到50dB以上。4.2 輸出頻譜出現(xiàn)雜散時鐘泄漏與量化噪聲另一個常見問題是輸出頻譜上有莫名其妙的雜散。有一次我調(diào)一個鏈路發(fā)現(xiàn)輸出在某個特定頻率上總有一個小尖峰換了采樣率就消失換回來又出現(xiàn)。后來查了半天發(fā)現(xiàn)是采樣時鐘的諧波和NCO頻率混頻產(chǎn)生的。這種雜散的根源是時鐘泄漏。ADC的采樣時鐘會通過電源或者地平面耦合到模擬輸入端和信號一起被采樣。如果時鐘頻率的某個諧波剛好落在信號帶內(nèi)就會產(chǎn)生固定的雜散。解決辦法一是改善時鐘的屏蔽和濾波二是在數(shù)字域用陷波器把已知的雜散頻率濾掉。量化噪聲也是雜散的來源之一。ADC的量化誤差不是白噪聲而是和輸入信號相關(guān)的確定性誤差會產(chǎn)生諧波失真。如果輸入信號幅度太接近滿量程諧波失真會惡化。我一般會把輸入信號幅度控制在滿量程的-6dB到-12dB之間留足夠的余量。4.3 抽取濾波器通帶邊緣衰減過大抽取濾波器的通帶邊緣衰減是個容易被忽視的問題。CIC濾波器的頻率響應(yīng)是sinc函數(shù)在通帶邊緣衰減很明顯。如果信號帶寬剛好到通帶邊緣衰減可能達到3dB甚至更多導(dǎo)致信號幅度不一致。解決這個問題有兩個思路一是讓濾波器的通帶比信號帶寬寬一些比如信號帶寬20MHz濾波器通帶做到25MHz這樣20MHz處的衰減就很小了二是加補償濾波器把CIC的sinc衰減補回來。補償濾波器的系數(shù)可以用MATLAB的firls函數(shù)設(shè)計讓它的頻率響應(yīng)和CIC的衰減相反。我一般會先用MATLAB把整個抽取鏈路的頻率響應(yīng)仿真一遍看看通帶波動和阻帶衰減是否滿足要求。如果通帶波動超過0.5dB就加補償如果阻帶衰減不夠就增加濾波器階數(shù)或者換更高級的濾波器結(jié)構(gòu)。5. 從仿真到上板我的調(diào)試流程與經(jīng)驗5.1 MATLAB仿真先把算法跑通再寫RTL我見過不少人直接上手寫Verilog結(jié)果調(diào)了半天發(fā)現(xiàn)算法本身就有問題。我的習(xí)慣是先在MATLAB里把整個鏈路仿真一遍包括信號生成、帶通采樣、數(shù)字混頻、抽取濾波最后看頻譜和星座圖是否正常。MATLAB仿真的好處是可以快速試錯改個參數(shù)幾秒鐘就能看到結(jié)果比在FPGA里改代碼再綜合快得多。仿真的時候要注意幾點一是采樣率要設(shè)成和實際一致二是要加入噪聲和時鐘抖動模型三是要用定點數(shù)仿真而不是浮點數(shù)因為FPGA里是定點運算。定點數(shù)的位寬選擇很關(guān)鍵位寬不夠會導(dǎo)致量化噪聲大位寬太大浪費資源。我一般會先用浮點仿真確認算法正確然后逐步降低位寬看性能惡化到什么程度找到一個平衡點。5.2 FPGA上板調(diào)試ILA抓數(shù)據(jù)做FFT算法仿真通過之后接下來是寫RTL、綜合、上板。上板之后第一件事是用ILA抓ADC的原始數(shù)據(jù)做一次FFT看看頻譜對不對。如果頻譜和MATLAB仿真不一致那說明ADC配置或者時鐘有問題。確認ADC數(shù)據(jù)正確之后再逐級抓混頻輸出、濾波輸出看每一級的頻譜是否符合預(yù)期。ILA抓數(shù)據(jù)的深度有限一般只能抓幾千個點做FFT的頻率分辨率不夠高。如果需要更精細的頻譜分析可以把數(shù)據(jù)通過UART或者以太網(wǎng)傳到上位機用MATLAB或者Python做離線分析。我一般會在FPGA里加一個數(shù)據(jù)緩存模塊把需要分析的數(shù)據(jù)存到RAM里然后慢慢往外傳。5.3 資源與時序的平衡數(shù)字下變頻鏈路在FPGA里占的資源不少尤其是FIR濾波器乘法器用量很大。如果FPGA資源緊張可以考慮幾個優(yōu)化方向一是用時分復(fù)用的方式共享乘法器二是用CSD編碼或者分布式算法減少乘法器數(shù)量三是降低濾波器階數(shù)或者用更高效的濾波器結(jié)構(gòu)。時序方面高速采樣率下比如110MHz以上乘加運算的流水線設(shè)計很關(guān)鍵。我一般會把乘法和加法分成多級流水確保每級之間的邏輯延遲不超過時鐘周期。如果時序不滿足可以插入額外的寄存器但會增加延遲。延遲增加會影響整個鏈路的實時性需要權(quán)衡。6. 幾個值得關(guān)注的擴展方向6.1 多通道幅相一致性校準(zhǔn)如果你做的是相控陣或者多通道接收機數(shù)字下變頻之后還需要關(guān)注各通道之間的幅相一致性。不同通道的ADC、混頻器、濾波器不可能完全一致會導(dǎo)致波束形成的時候旁瓣升高。校準(zhǔn)的方法是在每個通道注入一個已知的參考信號測量各通道的幅度和相位差異然后在數(shù)字域補償。6.2 自適應(yīng)濾波在數(shù)字下變頻中的應(yīng)用如果干擾信號很強而且頻率會變化固定系數(shù)的濾波器就不夠用了。這時候可以用自適應(yīng)濾波比如LMS算法讓濾波器系數(shù)根據(jù)輸入信號自動調(diào)整把干擾抑制掉。自適應(yīng)濾波的計算量比固定濾波大不少但在FPGA里用并行結(jié)構(gòu)實現(xiàn)也是可行的。6.3 高采樣率下的JESD204B接口當(dāng)采樣率超過200MHz的時候傳統(tǒng)的并行LVDS接口走線太多PCB布局困難。JESD204B接口用高速串行鏈路傳輸ADC數(shù)據(jù)線數(shù)少同步機制完善適合高采樣率多通道的應(yīng)用。但JESD204B的調(diào)試比LVDS復(fù)雜需要配置鏈路參數(shù)、做同步測試上手門檻高一些。我在實際項目里用JESD204B的時候最頭疼的是鏈路同步問題。有時候鏈路能建立但數(shù)據(jù)不對查半天發(fā)現(xiàn)是SYSREF信號的時序不滿足要求。后來學(xué)乖了每次上電都先讀JESD204B的狀態(tài)寄存器確認鏈路同步、幀同步、多幀同步都正常了再往下走。這個習(xí)慣幫我省了不少調(diào)試時間。最后分享一個小技巧數(shù)字下變頻鏈路里的NCO頻率、抽取因子、濾波器系數(shù)這些參數(shù)最好做成寄存器可配置的而不是寫死在RTL里。這樣調(diào)試的時候可以通過上位機動態(tài)修改不用每次都重新綜合。我一般會用一個SPI或者UART接口來配置這些參數(shù)配合上位機軟件調(diào)試效率能提高好幾倍。