原理詳解:從數(shù)字接收機到AD9361工程實現(xiàn))
剛接觸到數(shù)字接收機的時候我一度覺得“同步”兩個字特別玄乎。直到自己用AD9361平臺調(diào)BPSK調(diào)制解調(diào)第一次在解調(diào)鏈路里加入Costas Loop才真正明白它解決的到底是什么問題。BPSK信號本身沒有顯式載波分量接收端要做相干解調(diào)就必須靠Costas環(huán)把本地載波的頻率和相位從信號里“擠”出來。這篇文章我盡量把原理和工程實現(xiàn)都講透適合剛接手同步設(shè)計、或者想在SDR平臺上做BPSK解調(diào)的同學(xué)參考。1. 為什么BPSK接收機離不開載波同步1.1 BPSK的“隱載波”本質(zhì)與同步任務(wù)的由來BPSK的時域表達式寫成下面的形式s(t) A · m(t) · cos(2πf_c t θ_0)其中m(t) ±1是雙極性基帶符號。從頻域看m(t)是隨機數(shù)據(jù)頻譜里不是一條離散譜線載波分量反而被抑制掉了。這種做法有個好處發(fā)射功率全部用在傳送信息上不需要浪費一部分功率去發(fā)送載波導(dǎo)頻。但代價是接收端沒法直接用一個窄帶鎖相環(huán)去鎖定載波因為頻譜里根本沒有“可鎖”的譜線。如果接收機用本地載波cos(2πf_c t θ?)做相干解調(diào)那么混頻并低通后的同相分量是I(t) (A/2) · m(t) · cos(Δθ)其中Δθ θ_0 - θ?。如果想要拿到完整的±A/2電平就必須讓Δθ 0或者2π的整數(shù)倍。也就是說接收機必須把本地載波的相位對齊到發(fā)送端載波相位這個動作就是載波同步。對BPSK這種抑制載波體制來說載波同步幾乎是必答題不是選做題。1.2 頻偏、相偏到底會把解調(diào)結(jié)果毀成什么樣很多初學(xué)的同學(xué)會覺得反正BPSK只有兩個符號差一點點相位問題不大。實際工程里差一點就是災(zāi)難。比如本地載波存在頻率偏差Δf那么解調(diào)輸出端的相位誤差會隨時間線性增長變成Δθ(t) 2πΔf·t Δφ0。當Δθ漂到90°時I分量趨近于0符號判決基本靠猜再漂到180°時解調(diào)結(jié)果整體翻轉(zhuǎn)誤碼率接近100%。這里我列一個快速估算表方便直觀感受失步的影響相位誤差 ΔθI分量幅度接收效果0°A/2最佳判決45°0.354A噪聲容限明顯下降90°0無法判決180°-A/2輸出完全反碼所以設(shè)計目標很清楚在信號到達解調(diào)器之前把剩余頻偏壓低到符號速率的很小比例同時把相偏鎖定在0附近。Costas Loop就是干這個的。1.3 什么時候必須自己寫Costas什么時候可以偷懶如果你的工作流是純MATLAB仿真假設(shè)理想載波同步那確實可以暫時繞過這個問題。但只要你面對的是真實射頻硬件比如AD9361的接收鏈路就一定會遇到本振頻偏和相位漂移。AD9361的RF本振和發(fā)射端本振不可能是絕對同一個頻率源晶振的精度、溫度漂移、多普勒效應(yīng)都會帶來幾百赫茲到幾千赫茲的頻差。這種頻差靠模擬鎖相環(huán)很難處理只能回到數(shù)字基帶用數(shù)字Costas環(huán)來解決。另一種“偷懶”做法是發(fā)送端插入已知導(dǎo)頻序列接收端用導(dǎo)頻估計頻偏和相偏。這在突發(fā)通信里很常用但連續(xù)流業(yè)務(wù)不希望過多占用信道資源或者不想頻繁重傳那么閉環(huán)的Costas環(huán)就是更通用的方案。2. Costas環(huán)的結(jié)構(gòu)與鑒相器是怎么工作的2.1 從經(jīng)典模擬環(huán)到數(shù)字環(huán)路結(jié)構(gòu)先看懂Costas環(huán)的基本結(jié)構(gòu)由兩條支路和一個誤差反饋環(huán)路組成。它的巧妙之處在于利用數(shù)據(jù)符號m2(t) 1這一性質(zhì)把數(shù)據(jù)調(diào)制的影響從誤差信號里消掉只保留相位誤差信息。數(shù)字實現(xiàn)的結(jié)構(gòu)比模擬版更直觀我通常把它拆成5個部分本地NCO數(shù)控振蕩器生成正交的本振信號exp(-j·φ_nco)同相支路 I相乘后低通正交支路 Q相乘后低通鑒相器根據(jù) I、Q 計算相位誤差環(huán)路濾波器對誤差信號進行比例積分處理調(diào)整NCO頻率與相位整個環(huán)路運行的時候NCO的輸出相位不斷逼近接收信號的殘余載波相位I支路上的輸出就是完成載波同步后的基帶信號直接送給符號判決模塊即可。2.2 鑒相器輸出的數(shù)學(xué)推導(dǎo)與工作區(qū)間假設(shè)接收信號經(jīng)過ADC和數(shù)字下變頻后基帶復(fù)信號可以寫成r(k) m(k) · exp(j·(2πΔf·kT Δφ))NCO輸出的本振是exp(-j·φ_nco(k))那么混頻后I Re[r(k) · exp(-j·φ_nco)] m(k) · cos(Δθ(k)) Q Im[r(k) · exp(-j·φ_nco)] m(k) · sin(Δθ(k))這里的Δθ(k)是殘余相位誤差。對BPSK信號一種經(jīng)典“純乘法”鑒相器直接用I·Qerr I · Q m2(k) · cos(Δθ) · sin(Δθ) 0.5 · sin(2Δθ)細心的話會發(fā)現(xiàn)m2(k) 1被自動消掉了數(shù)據(jù)調(diào)制對誤差信號沒有影響。這個式子還說明一個關(guān)鍵特性err在Δθ 0附近近似是Δθ的線性函數(shù)斜率是1所以環(huán)路能穩(wěn)定鎖定在0相位誤差附近。它的鑒相曲線周期是π這意味著它不僅鎖定在0也可能鎖定在π對應(yīng)輸出的正負極性整體反了這就是后面的倒π問題。2.3 實用判決輔助鑒相與增益歸一化純乘法的I·Q鑒相器在理論分析里很標準但工程實現(xiàn)時我通常不直接用。原因是當Q值比較小時I·Q會同時受信號幅度影響AGC沒穩(wěn)的時候環(huán)路增益會變調(diào)試起來很頭疼。更常見的做法是判決輔助鑒相err sign(I) · Q這里用I支路的符號替代了I的幅度。由于m(k) ±1sign(I) m(k)于是err m(k) · [m(k) · sin(Δθ)] sin(Δθ)在鎖定點附近err ≈ Δθ而且環(huán)路增益對輸入幅度不敏感。犧牲一點信噪比極低時的表現(xiàn)換來了工程上的魯棒性。我用這個方案在AD9361平臺實測從-5dB到15dB信噪比范圍內(nèi)環(huán)路收斂表現(xiàn)都比較穩(wěn)定。注意如果信噪比非常低判決結(jié)果本身出錯sign(I)就會變成錯誤符號誤差信號會引入額外擾動環(huán)路抖動會加大。所以判決輔助鑒相更適合在完成粗同步、信噪比還不算太差的階段使用。3. 環(huán)路濾波器與參數(shù)計算這才是工程重點3.1 一階環(huán)為什么不夠用二階環(huán)的傳輸特性Costas環(huán)的性能主要由環(huán)路濾波器決定。最簡單的選擇是一階環(huán)也就是只有比例支路相當于一個一階鎖相環(huán)。一階環(huán)結(jié)構(gòu)簡單但存在一個麻煩它對頻率階躍輸入的穩(wěn)態(tài)相位誤差不為零無法完全消除頻偏。而BPSK接收機里本振頻偏是常態(tài)用一階環(huán)總會留下固定的相位偏移降到I支路上就是固定衰減這是不能接受的。所以工程上最少用二階環(huán)。二階環(huán)的環(huán)路濾波器是一個“比例積分”結(jié)構(gòu)比例支路負責(zé)快速跟蹤相位變化積分支路負責(zé)積累頻率信息最終把本地NCO的頻率徹底對準到信號載波頻率上。它的閉環(huán)傳遞函數(shù)寫成經(jīng)典形式H(s) (2ζωn·s ωn2) / (s2 2ζωn·s ωn2)這里ζ是阻尼系數(shù)ωn是自然角頻率。鎖相環(huán)的大量理論分析都建立在這個二階模型上后續(xù)的所有參數(shù)計算都圍繞ζ和ωn展開。3.2 從噪聲帶寬BL反推環(huán)路系數(shù)的完整計算設(shè)計一個數(shù)字Costas環(huán)一般不會直接給一個ωn而是先給出一個環(huán)路噪聲帶寬BL的目標值。BL的大小直接決定環(huán)路能濾除多少帶外噪聲、以及能跟蹤多大的頻偏。工程經(jīng)驗上對于BPSK接收機BL通常取符號速率的1%到5%之間。取小了環(huán)路輸出干凈但捕獲慢動態(tài)頻偏一大會失鎖取大了跟蹤快但相位噪聲大解調(diào)誤碼率會變差。這是一個取舍問題。標準二階環(huán)中BL與ωn、ζ的關(guān)系是BL (ωn/2) · (ζ 1/(4ζ))反過來就是ωn 2·BL / (ζ 1/(4ζ))接下來需要把連續(xù)域參數(shù)換算到數(shù)字域。我用的是工程上很常見的一種離散化方式在采樣周期T足夠小的時候環(huán)路濾波系數(shù)可以近似寫成C1 2ζωnT / (1 2ζωnT ωn2T2) C2 ωn2T2 / (1 2ζωnT ωn2T2)其中C1是比例支路系數(shù)C2是積分支路系數(shù)。這兩個系數(shù)含義不同C1決定當前相位誤差對NCO相位的直接修正大小C2決定頻率積累的速度。一般C2會比C1小一個數(shù)量級。我舉一個實際算例。某BPSK系統(tǒng)符號率Rs 1MHz環(huán)路更新率等于符號率所以T 1μs。取ζ 0.707BL 5kHz符號率的0.5%于是ωn 2 × 5000 / (0.707 1/(4×0.707)) ≈ 9428 rad/s ωnT ≈ 0.00943 C1 ≈ 0.0131 C2 ≈ 0.0000877這個量級在FPGA定點實現(xiàn)里也很常見C1在0.01量級C2在0.0001量級兩個系數(shù)用定點數(shù)表示時要注意位寬。如果直接用浮點仿真問題不大一旦落到硬件就得小心量化誤差。3.3 一個可直接抄作業(yè)的MATLAB設(shè)計模板我習(xí)慣先用MATLAB把環(huán)路跑通再搬到FPGA。下面這段代碼是一個每符號一次采樣的BPSK Costas環(huán)演示包含了上面推導(dǎo)的參數(shù)計算和環(huán)路更新過程。% BPSK Costas loop demo, 每符號一個采樣點 Fsym 1000; % 符號率 1ksps N 50000; data randi([0 1], N, 1); sym 2*data - 1; % 模擬真實接收殘余頻偏和相偏 df 150; % 頻偏 150Hz phi0 0.6; % 初始相位誤差 t (0:N-1). / Fsym; rx sym .* exp(1j*(2*pi*df*t phi0)); % 環(huán)路參數(shù) BL 20; % 噪聲帶寬, 經(jīng)驗值取符號率的2%以內(nèi) zeta 0.707; wn 2*BL / (zeta 1/(4*zeta)); T 1/Fsym; C1 2*zeta*wn*T / (1 2*zeta*wn*T (wn*T)^2); C2 (wn*T)^2 / (1 2*zeta*wn*T (wn*T)^2); % Costas環(huán)主循環(huán) phi_nco 0; f_nco 0; I_est zeros(N,1); Q_est zeros(N,1); for k 1:N I_est(k) real(rx(k) * exp(-1j*phi_nco)); Q_est(k) imag(rx(k) * exp(-1j*phi_nco)); err sign(I_est(k)) * Q_est(k); % 判決輔助鑒相 f_nco f_nco C2 * err; phi_nco phi_nco C1 * err f_nco; end demod I_est 0; ber mean(demod ~ data);跑完這段代碼解調(diào)誤碼率應(yīng)該是0。你可以試著把df調(diào)高到300Hz以上會發(fā)現(xiàn)環(huán)路捕獲時間變長甚至失鎖。這就是體驗環(huán)路捕獲范圍最直接的辦法。真實工程里環(huán)路更新率不一定是符號率可能是符號率的整數(shù)倍這時T要相應(yīng)地替換成實際工作時鐘周期。3.4 采樣率、符號率與環(huán)路更新率的關(guān)系很多同學(xué)直接把采樣率當成環(huán)路更新率來計算這是一個容易忽略的坑。Costas環(huán)的鑒相器通常放在匹配濾波和符號定時之后也就是每符號才計算一次誤差環(huán)路更新率等于符號率。如果你把環(huán)路放在定時同步之前用高采樣率數(shù)據(jù)直接算誤差那么環(huán)路濾波器系數(shù)要按采樣率來重新算否則環(huán)路帶寬完全不是你以為的值。我在做AD9361BPSK時接收機ADC采樣率配置成30.72MHzFPGA里做抽取后基帶處理速率是7.68MHz。匹配濾波完成后再做符號定時抽取最終每個符號才出一個I和QCostas環(huán)更新率等于1MHz。如果誤把7.68MHz當成環(huán)路更新率算出來的C1、C2會整體偏大環(huán)路很快振蕩。所以建議所有參數(shù)計算都以環(huán)路實際更新率為主而不是籠統(tǒng)地寫“采樣率”。4. 用AD9361做BPSK調(diào)制解調(diào)時Costas環(huán)放在哪里4.1 發(fā)送端基帶波形與AD9361的接口AD9361作為一個射頻收發(fā)器內(nèi)部集成了完整的射頻前端、ADC/DAC和可配置的數(shù)字濾波器。發(fā)送端我們只需要把基帶I/Q數(shù)據(jù)按采樣率喂給它的數(shù)字接口。BPSK的基帶符號是實數(shù)的±A所以I路送符號電平Q路送0即可。如果只做最基礎(chǔ)的BPSK不整形直接發(fā)方波也可以解調(diào)但帶外頻譜不好看。建議在FPGA或者DSP里先做根升余弦濾波比如滾降系數(shù)0.35。這樣做的好處不只是頻譜規(guī)整更重要的是配合接收端的匹配濾波讓符號定時更好做間接降低Costas環(huán)的噪聲壓力。發(fā)送鏈路里有一個容易忽視的操作發(fā)送端最好預(yù)留一定的基帶信號回退避免AD9361內(nèi)部數(shù)字上變頻和DAC飽和。我一般把BPSK符號電平設(shè)置在滿量程的-3dBFS到-6dBFS之間既能用滿動態(tài)范圍又留了余量。4.2 接收鏈路中Costas環(huán)的位置與數(shù)據(jù)流AD9361接收端輸出的基帶I/Q數(shù)據(jù)已經(jīng)是復(fù)基帶信號但其頻率并不為零它包含了收發(fā)本振之間的頻偏以及信道多普勒。數(shù)據(jù)流大致是這樣AD9361 RX - FIFO/接口 - 數(shù)字下變頻(DDC) - 匹配濾波 - 符號定時同步 - Costas環(huán)(載波同步) - 符號判決 - 輸出bit這里要特別強調(diào)順序。工程上最常見的做法是先做符號定時同步再做載波同步。原因是Costas環(huán)通常工作在每個符號一個樣點的數(shù)據(jù)率上如果定時沒有對齊采樣點落在符號邊緣信噪比大幅下降鑒相器誤差信號里會出現(xiàn)大量數(shù)據(jù)間干擾環(huán)路穩(wěn)定性和收斂范圍都會變差。所以先把采樣點對準到每個符號的最佳位置再讓載波環(huán)工作是更穩(wěn)的順序。但也有例外。如果頻偏大到符號定時環(huán)本身都鎖不住比如頻偏超過符號率的幾個百分點那就需要先做一個粗略頻偏估計把頻偏壓到可接受范圍再進定時和細同步。我在AD9361平臺上常用的做法是先用FFT對接收信號做頻譜搬移粗估或者利用前導(dǎo)序列做相關(guān)估計粗頻偏糾正之后再進Costas環(huán)這樣整個鏈路的捕獲概率會高很多。4.3 從仿真到板卡的移植浮點與定點差異MATLAB仿真是浮點FPGA實現(xiàn)是定點這一跳會帶來不少坑。最典型的是環(huán)路積分器的字長。頻率積分項f_nco本身數(shù)值很小但會持續(xù)累積如果字長太短量化誤差會直接表現(xiàn)為環(huán)路鎖定后的相位抖動。我習(xí)慣把NCO相位累加器做到32bit頻率積分項至少24bit環(huán)路誤差信號可以適當截位但積分路徑要保留足夠余量。還有一個需要注意的地方是NCO的溢出設(shè)計。NCO相位本質(zhì)上是模2π的FPGA里可以用一個32bit累加器自然回繞不用顯式處理但相位累加器高位要能覆蓋你期望的頻偏范圍。如果頻偏范圍是±10kHz符號率1MHzNCO每一個符號的最大相位步進是2π×10000/1000000 ≈ 0.0628 rad按每秒1M次更新來算累加器完全能覆蓋不用特殊處理。從仿真到板卡我建議先在Simulink里做定點仿真把量化效應(yīng)先看一遍再上FPGA。直接跳板的后果通常是誤碼率比仿真差很多但又說不清是模擬前端問題還是定點量化問題排查非常痛苦。4.4 雙環(huán)收尾載波環(huán)與符號定時環(huán)怎么配合如果系統(tǒng)中同時存在符號定時環(huán)路和載波Costas環(huán)兩個環(huán)路是耦合的。頻率偏差嚴重時符號定時的采樣點位置會緩慢偏移反過來又會影響載波環(huán)的誤差質(zhì)量。實際調(diào)試時我通常先把符號定時環(huán)單獨調(diào)通給它一個沒有頻偏的信號讓定時環(huán)穩(wěn)定然后把Costas環(huán)加進來觀察載波環(huán)能否收斂。環(huán)路帶寬的搭配也有一點規(guī)律。一般載波環(huán)的帶寬比符號定時環(huán)的帶寬窄一些因為載波相位噪聲對誤碼率的影響更直接需要更緊致的濾波同時它追頻偏的速度可以稍微慢一點。如果兩個環(huán)路的帶寬太接近容易互相牽扯收斂曲線會變得很難看。5. 常見問題排查與調(diào)參心得5.1 鎖不住先分清是頻偏問題還是環(huán)路參數(shù)問題我調(diào)試時見過最多的場景是Costas環(huán)完全鎖不住I支路輸出亂跳。排查第一步不是改C1、C2而是先測接收信號中殘留頻偏到底有多大。用AD9361的捕獲數(shù)據(jù)在MATLAB里看頻譜如果信號峰的偏移量明顯超過環(huán)路捕獲范圍那再怎么調(diào)參數(shù)都沒用。比如符號率1MHz環(huán)路噪聲帶寬只有5kHz實際頻偏卻有20kHz環(huán)路很難直接拉回。這時有兩個方向要么把BL調(diào)大比如到20kHz但代價是相位噪聲增大要么先做粗頻偏糾正把頻偏從20kHz壓到1kHz以內(nèi)再讓窄帶Costas環(huán)細調(diào)。我個人更喜歡后者性能和穩(wěn)定性都更好。成本只是多寫一個掃頻或FFT估計的模塊對大多數(shù)硬件平臺來說都不是難事。5.2 顏色對了但全是反碼倒π問題的工程解法Costas環(huán)的鑒相曲線周期是π這意味著環(huán)路既可以鎖在0相位誤差也可以鎖在π誤差處。鎖定在π時I支路輸出是-A/2和A/2的鏡像判決后所有bit都與發(fā)送端相反誤碼率等于1。這是Costas環(huán)和BPSK載波同步最經(jīng)典的問題學(xué)名叫做相位模糊或倒π。工程上解決這個問題有三個常見方案發(fā)送端使用差分編碼接收端做差分譯碼。即使載波整體翻轉(zhuǎn)相鄰符號的相對極性不變解調(diào)結(jié)果依然正確。發(fā)送幀里插入獨特的同步字接收端檢測到相反極性的同步字時主動翻轉(zhuǎn)輸出極性。對I支路判決后的數(shù)據(jù)流做自相關(guān)或CRC校驗檢測出全反碼后自動翻轉(zhuǎn)輸出。我實際項目中偏好差分編碼同步字同時使用。差分編碼解決連續(xù)隨機數(shù)據(jù)的極性模糊同步字幫助快速判斷是否需要翻轉(zhuǎn)雙保險。雖然差分編碼會帶來約1倍誤碼率的小損失但在硬件環(huán)境中換取穩(wěn)定和簡單非常值得。5.3 相位抖動大、誤碼抬高濾波帶寬與AGC的配合Costas環(huán)鎖定后如果誤碼率依然高于理論值檢查方向通常是兩個一個是環(huán)路帶寬太寬導(dǎo)致相位噪聲注入到I分量另一個是AGC沒有把信號幅度穩(wěn)定在固定電平上導(dǎo)致鑒相器增益波動。環(huán)路帶寬寬的標志是NCO相位觀測值周圍有持續(xù)毛刺帶寬窄則鎖定時間變長。前級AGC在AD9361中是自動增益控制它調(diào)整射頻/模擬增益目標通常把信號幅度穩(wěn)定在ADC滿量程的一定百分比。如果AGC的時間常數(shù)與Costas環(huán)的時間常數(shù)不匹配比如AGC還在調(diào)整增益時信號幅度突變環(huán)路會瞬間出現(xiàn)一個大的相位誤差。我一般建議先把AGC穩(wěn)定后再使能載波同步環(huán)路或者讓環(huán)路一直工作但確認AGC不會頻繁大幅度調(diào)整。還有一個技巧是采用歸一化誤差信號比如把err除以I2 Q2進一步削弱信號幅度對環(huán)路增益的影響。5.4 踩過幾次坑之后的幾條經(jīng)驗最后把一些碎但很關(guān)鍵的經(jīng)驗列出來每一條都是實際項目里付出過代價換來的。不要太相信仿真里的理論誤碼率。硬件鏈路里ADC量化、時鐘抖動、匹配濾波系數(shù)、環(huán)路定點字長每一項都會讓性能打折。我習(xí)慣在仿真里預(yù)留至少1~2dB的裕量。環(huán)路濾波器系數(shù)不要一次改太多。C1和C2之間存在聯(lián)動改動C2對穩(wěn)態(tài)性能影響大改動C1對動態(tài)響應(yīng)影響大。建議先固定ζ單方向掃描BL看誤碼率和鎖定時間的變化趨勢再微調(diào)。NCO頻率沒有限幅的話積分項可能溢出或跑飛。在環(huán)路里加上頻率鉗位比如最大頻偏±10kHz那么每次更新的頻率累計不能超過對應(yīng)步進超了就限幅能有效防止環(huán)路在異常輸入下發(fā)散。調(diào)試時在接收端預(yù)留一個觀測點把NCO相位和環(huán)路誤差實時拉出來看。沒有觀測數(shù)據(jù)直接看星座圖很難定位問題。我經(jīng)常在錯誤場景里把I/Q和NCO相位一起存下來回頭在MATLAB里重放效率比現(xiàn)場猜神秘現(xiàn)象高很多。每次有人問我Costas環(huán)難不難我都會說原理不難難的是把環(huán)路帶寬、濾波器系數(shù)、定點字長這些參數(shù)調(diào)試到彼此舒服。實際項目里先把發(fā)射端頻偏校準到位再用Costas環(huán)吃掉殘余頻偏是省心而且穩(wěn)定的組合。自己在AD9361平臺上跑通一次BPSK調(diào)制解調(diào)之后再去看QPSK、16QAM等更高階調(diào)制里的載波同步很多思路都能遷移過去底層邏輯是一致的。