峰捕獲與數(shù)字鎖相實現(xiàn))
簡介這是一份面向 FPGA 工程師與數(shù)字通信學(xué)習(xí)者的 M 序列同步時鐘提取資料包。內(nèi)容圍繞 M 序列 LFSR 生成原理、位同步電路設(shè)計以及全數(shù)字鎖相環(huán) DPLL 實現(xiàn)展開提供 VHDL 源碼、工程文件、仿真腳本及多篇設(shè)計文檔適合希望在 Cyclone 系列 FPGA 上開展同步時鐘提取實驗的讀者。包內(nèi)共 68 個文件包含 vhdl/vhw 程序文件、prj/ise 工程配置、xwv 仿真波形、pdf/doc 原理文檔以及綜合結(jié)果等壓縮包大小 2.66MB目錄結(jié)構(gòu)完整從源碼、仿真到文檔一應(yīng)俱全。目前已有 498 人學(xué)習(xí)下載。資源不僅給出 63 位 M 序列的 VHDL 實現(xiàn)和 DPLL 設(shè)計文檔還收錄《Cyclone 同步設(shè)計》與《通信系統(tǒng)中位同步電路的 FPGA 設(shè)計與實現(xiàn)》等資料便于讀者對照理論理解工程實現(xiàn)快速上手同步時鐘提取系統(tǒng)。 搞FPGA通信鏈路的人遲早會碰到同步時鐘提取這件事。接收端拿到的數(shù)據(jù)是發(fā)射端經(jīng)過調(diào)制、傳輸、采樣后的一堆離散點采樣時鐘和發(fā)送時鐘必然有偏差怎么把碼元時鐘準確恢復(fù)出來直接決定后級解調(diào)能不能正常工作。我這次的項目里用了m序列作為已知訓(xùn)練序列在FPGA里做了一套“相關(guān)峰捕獲加數(shù)字鎖相跟蹤”的同步提取方案最后恢復(fù)出來的時鐘能夠穩(wěn)定驅(qū)動數(shù)據(jù)采樣和后續(xù)處理模塊。這篇文章就圍繞m序列和FPGA兩個關(guān)鍵詞把同步時鐘提取從原理到實現(xiàn)、從調(diào)試到排障完整梳理一遍。適合剛接觸FPGA通信相關(guān)項目的朋友也適合準備面試時被問到同步原理時能有個清晰完整的思路。1. 項目解讀m序列為什么適合做同步時鐘提取1.1 這個項目到底在解決什么問題通信接收端的第一個大問題不是解調(diào)而是“我該在哪個時刻去采這個碼元”。發(fā)送端碼元速率假設(shè)是1.024Mbps接收端本地有一個122.88MHz的采樣時鐘雖然理論上能對1.024M碼元采出120個點但本地時鐘和發(fā)送時鐘之間總存在頻率偏差和相位偏差直接靠分頻是分不出一個與發(fā)送端完全同相的碼元時鐘的。m序列在這里扮演的角色是“已知的錨點”。發(fā)送端周期性地發(fā)一段m序列接收端本地也產(chǎn)生同樣的一串m序列兩者做滑動相關(guān)在某個時刻相關(guān)值會顯著沖高這個沖高位置就對應(yīng)發(fā)送端m序列的起始邊界。有了這個邊界接收端就能校準本地的時間基準進而把碼元時鐘、幀時鐘一并提取出來。我實際做的場景是前向鏈路里每一幀數(shù)據(jù)頭部插入127位m序列作為同步頭接收端用m序列相關(guān)峰完成幀同步和位同步恢復(fù)出的時鐘再作為整個基帶處理模塊的定時基準。這種方式比盲目做盲定時恢復(fù)要穩(wěn)得多因為它利用的是已知序列的全部能量。1.2 為什么是m序列而不是其它訓(xùn)練序列一開始我也想過直接用單頻導(dǎo)頻或者隨機數(shù)據(jù)頭但對比下來m序列有三個不可替代的優(yōu)點。m序列是偽隨機序列周期為N2^n-1它的自相關(guān)函數(shù)有一個尖銳的主峰完全對齊時相關(guān)值等于N錯開任意一位時相關(guān)值只有-1歸一化后約等于-N分之一這個大數(shù)。這個特性意味著在信噪比很低的情況下接收端依然能通過一段序列的相關(guān)累加把同步點找出來。單頻導(dǎo)頻在頻域上是能量集中的能解決載波同步但沒法精準給出碼元邊界隨機數(shù)據(jù)頭雖然也能做相關(guān)但它的自相關(guān)特性不如m序列穩(wěn)定旁瓣起伏大誤鎖概率高。實現(xiàn)成本也是關(guān)鍵。m序列在FPGA里就是一個線性反饋移位寄存器幾個觸發(fā)器加一個異或門就能產(chǎn)生完全不占資源。對比起來做FFT幅度譜估計或者匹配濾波器組資源開銷和復(fù)雜度都要高一個量級。同步方案自相關(guān)特性抗噪聲能力FPGA實現(xiàn)成本適用場景m序列相關(guān)單峰尖銳旁瓣恒定強相關(guān)增益隨序列長度提升極低LFSR即可突發(fā)同步、幀同步、位定時單頻導(dǎo)頻周期性多峰無法定位碼元一般需窄帶濾波低但需額外鑒相載波同步隨機數(shù)據(jù)頭旁瓣隨機起伏較弱需較長平均中僅適合高信噪比場景Gold序列類似m序列互相關(guān)更優(yōu)強低多用戶區(qū)分場景1.3 方案選型捕獲加跟蹤的雙層結(jié)構(gòu)同步提取不能只靠一次相關(guān)峰判斷就完事。信號有噪聲、有頻偏單次相關(guān)峰的位置會抖動所以實際工程里我習(xí)慣拆成兩個階段捕獲階段和跟蹤階段。捕獲階段用滑動相關(guān)器不停掃描一旦相關(guān)值超過設(shè)定閾值就認為找到了粗同步點。這個階段要求快、覆蓋范圍大哪怕同步點差一兩個采樣點都沒關(guān)系后面會修正。跟蹤階段則切換到定時誤差檢測器用超前滯后門或者數(shù)字鎖相環(huán)對采樣時刻做閉環(huán)微調(diào)讓采樣點始終穩(wěn)定在碼元的最佳判決位置。這兩層結(jié)構(gòu)在FPGA里的體現(xiàn)是捕獲階段有專門的峰值檢測和閾值比較邏輯跟蹤階段有一套誤差計算和環(huán)路濾波器。兩者的切換由一個同步狀態(tài)機管理。我在調(diào)試時的體會是捕獲階段可以做得稍微“激進”一點閾值寧可低一些先把相關(guān)峰抓住再用跟蹤環(huán)去排除錯鎖反過來如果閾值設(shè)太高一幀數(shù)據(jù)都等不到同步脈沖后面全是空轉(zhuǎn)。2. 核心原理與FPGA基礎(chǔ)模塊2.1 m序列生成器一個本原多項式就夠了m序列的本質(zhì)是最大長度線性反饋移位寄存器序列周期是2^n-1。比如n7時周期127。硬件實現(xiàn)非常簡單Verilog里幾十行就能搞定。我項目里用的是本原多項式x^7x^31對應(yīng)反饋抽頭是第7級和第3級異或后送回第1級。// m序列生成器n7本原多項式 x^7x^31周期127 module m_seq_gen #( parameter SEQ_LEN 127, parameter INIT_SEED 7h7f )( input wire clk, input wire rst_n, input wire ce, // 碼元時鐘使能每來一個脈沖輸出一位 output reg m_out ); reg [6:0] shift_reg; wire feedback shift_reg[6] ^ shift_reg[3]; always (posedge clk or negedge rst_n) begin if (!rst_n) begin shift_reg INIT_SEED; end else if (ce) begin shift_reg {shift_reg[5:0], feedback}; end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin m_out 1b0; end else if (ce) begin m_out shift_reg[6]; end end endmodule這里有兩個工程細節(jié)容易踩坑。第一寄存器初值不能是全0全0狀態(tài)下反饋永遠為0序列就“死”了所以復(fù)位時一定要給一個非零種子。第二發(fā)送端和接收端的m序列必須同長度、同多項式、同初相否則相關(guān)峰永遠出不來。2.2 滑動相關(guān)與相關(guān)峰檢測有了本地m序列接下來就是把接收數(shù)據(jù)和它做相關(guān)。接收端ADC采樣后的數(shù)據(jù)是過采樣的假設(shè)每碼元采8個點那么一個127位的m序列一共有1016個采樣點。接收端把本地m序列展開成同樣速率然后在每一個采樣點都和接收數(shù)據(jù)做一次“對齊比較”統(tǒng)計相同與不同的數(shù)量這就是滑動相關(guān)。因為m序列每個碼元內(nèi)的8個采樣點除了過采樣分支不同、符號基本一致相關(guān)計算可以簡化成對8倍過采樣的每個相位分支分別算碼元級相關(guān)然后取能量最大的一路作為同步點。實際工程里為了省資源我通常是按照8個相位分支并行計算相關(guān)每個分支內(nèi)對127位碼元做累加這樣每個采樣時鐘都能得到8個相關(guān)值峰值檢測器只需要比較這8個值選出最大者。相關(guān)運算在FPGA里不復(fù)雜但要注意位寬。127位累加如果接收數(shù)據(jù)是符號位1/-1結(jié)果范圍是-127到127需要一個9位有符號數(shù)如果接收數(shù)據(jù)是多比特幅度還要額外乘以幅度字長。2.3 定時誤差檢測超前滯后門與數(shù)字鎖相捕獲階段確定了粗同步點但采樣時鐘和發(fā)送時鐘之間還有殘余頻偏粗同步點會隨著時間慢慢漂移。跟蹤階段需要一個反饋環(huán)路實時調(diào)整采樣位置。我用的是經(jīng)典超前滯后門Early-Late Gate結(jié)構(gòu)。思路很直觀在最佳采樣點前后各取一個相關(guān)值早門取最佳點前1/8碼元處的相關(guān)值晚門取最佳點后1/8碼元處的相關(guān)值。如果采樣點正好在正中間早門和晚門的能量應(yīng)該相等如果采樣點偏晚了早門相關(guān)值會大于晚門反過來采樣點偏早了晚門會更大。這個差值就是定時誤差信號。誤差信號經(jīng)過一個比例積分環(huán)路濾波器得到頻率控制字驅(qū)動一個NCO產(chǎn)生調(diào)整后的采樣使能脈沖。NCO本質(zhì)就是相位累加器每累加到一個閾值就輸出一個“最佳采樣時刻”的脈沖。環(huán)路穩(wěn)定后這個脈沖的頻率就等于碼元速率相位就鎖定在最佳判決點。這套結(jié)構(gòu)天然適合FPGA沒有浮點運算所有系數(shù)都做定點化乘法用移位代替誤差信號用加減法得到。缺點是捕獲范圍有限所以必須配合前面說的捕獲階段先抓一個大致位置讓跟蹤環(huán)從小到大逐漸收斂而不是一上來就指望鎖相環(huán)自己拉回來。3. 實操在FPGA上跑通一版同步提取3.1 整體數(shù)據(jù)通路與參數(shù)設(shè)計我做的這套系統(tǒng)參數(shù)如下發(fā)送端碼元速率1.024MHz接收端ADC采樣率8.192MHz即8倍過采樣。FPGA內(nèi)部主時鐘122.88MHz等于采樣率的15倍給時序收斂留了足夠余量。m序列采用127位一幀同步頭時長124us捕獲窗口在1幀內(nèi)就能完成搜索。環(huán)路帶寬是調(diào)試中反復(fù)調(diào)整的一個參數(shù)。我初始設(shè)的環(huán)路帶寬約100Hz收斂時間大概幾個毫秒跟蹤穩(wěn)定后定時抖動在十六分之一碼元以內(nèi)。如果環(huán)路帶寬再放寬到500Hz收斂能快一些但恢復(fù)時鐘的抖動明顯變大如果壓到30Hz抖動更小但輸入頻偏大時會出現(xiàn)長時間無法收斂的問題。這個平衡要根據(jù)實際系統(tǒng)容忍度去試。各模塊參數(shù)如下相關(guān)積分窗口1個碼元早門與晚門相位間隔1/4碼元NCO位寬32位環(huán)路濾波器比例系數(shù)取1/64積分系數(shù)取1/1024。系數(shù)用移位實現(xiàn)避免DSP乘法器占用。3.2 FPGA模塊劃分與接口這個同步提取模塊我拆成了五個子模塊接口清晰也方便單獨仿真調(diào)試。下表是模塊劃分和各自職責(zé)。模塊功能輸入輸出m_seq_gen本地m序列產(chǎn)生系統(tǒng)時鐘、復(fù)位、碼元使能本地m序列碼流correlator滑動相關(guān)器按8倍過采樣分8路并行ADC數(shù)據(jù)、本地m序列各相位分支相關(guān)值peak_detect峰值檢測與閾值比較各分支相關(guān)值粗同步脈沖early_late超前滯后定時誤差檢測相關(guān)值、當(dāng)前NCO相位定時誤差信號loop_filter_ncoPI環(huán)路濾波與NCO相位累加定時誤差、同步狀態(tài)最佳采樣時鐘脈沖接口設(shè)計上ADC輸入數(shù)據(jù)我需要先做符號處理。如果ADC輸出是無符號二進制補碼先轉(zhuǎn)換成有符號數(shù)再進相關(guān)器如果是單比特過采樣判決結(jié)果那就直接進同或邏輯。第二種做法資源更少但抗噪性能差我在低信噪比場景下選了多比特方案。3.3 關(guān)鍵代碼相關(guān)器與環(huán)路濾波相關(guān)器是這套系統(tǒng)里最核心也最容易寫錯的模塊。我給出一個簡化但能反映結(jié)構(gòu)的框架// 相關(guān)器框架簡化每路相位分支每個碼元窗口內(nèi)累加相關(guān)值 // adc_data_i 為有符號接收數(shù)據(jù)local_m 為本地m序列極性映射1或-1 reg signed [8:0] corr_acc; wire signed [7:0] prod; assign prod (local_m) ? adc_data_i : -adc_data_i; always (posedge clk or negedge rst_n) begin if (!rst_n) corr_acc 9sd0; else if (bit_ce) begin if (corr_clr) begin corr_acc prod; // 新碼元開始 end else begin corr_acc corr_acc prod; end end end環(huán)路濾波和NCO部分則遵循“誤差進、頻率字出”的方式// 定時誤差檢測與一階環(huán)路示意 // err_early_late 來自超前滯后比較有符號數(shù) // freq_word 為NCO頻率控制字 always (posedge clk or negedge rst_n) begin if (!rst_n) begin freq_word 32d4299; // 對應(yīng)1.024MHz 122.88MHz時鐘 int_acc 32sd0; end else if (update_ce) begin int_acc int_acc (err_early_late 10); freq_word FREQ_BASE (err_early_late 6) int_acc; end end兩句代碼就把同步跟蹤的核心閉環(huán)串起來了。實際工程中要特別注意符號位擴展和算術(shù)移位。我一開始圖省事直接用了邏輯右移誤差信號為負數(shù)時符號位被填0環(huán)路積分方向直接反掉表現(xiàn)為越鎖越偏。后來統(tǒng)一改成算術(shù)右移問題立刻消失。3.4 時序約束與跨時鐘域處理ADC采樣時鐘與FPGA內(nèi)部處理時鐘在板子上往往不是同一個源頭。我這版設(shè)計里ADC采樣時鐘由板上晶振直接供給FPGA內(nèi)部用PLL把122.88MHz主時鐘和采樣時鐘做了相位對齊從根源上避免跨時鐘域采樣數(shù)據(jù)跳變。但如果你的項目里ADC數(shù)據(jù)和FPGA主時鐘確實異步必須加異步FIFO或者至少用雙觸發(fā)器同步后再進相關(guān)器。同步不當(dāng)?shù)暮蠊浅k[蔽相關(guān)峰在某個時鐘沿附近出現(xiàn)亞穩(wěn)態(tài)峰值檢測偶爾漏判同步狀態(tài)機在鎖定和失鎖之間反復(fù)跳。時序約束方面我最常用的兩條是set_input_delay和create_clock。數(shù)據(jù)從ADC引腳進來時約束它的輸入延時約束在采樣時鐘的有效窗口內(nèi)如果接收數(shù)據(jù)是DDR模式還要配套set_input_delay -clock_fall。約束不寫綜合工具默認保守經(jīng)常出現(xiàn)時序違例輕則功能正常但時序報告飄紅重則跑在板上時好時壞定位起來特別痛苦。4. 調(diào)試路上的常見問題與排查記錄4.1 相關(guān)峰抓不住同步脈沖一直不出來這是我在調(diào)試時遇到的第一個問題。邏輯分析儀里本地m序列波形正常但相關(guān)器輸出始終看不到明顯峰值。排查下來有三層原因。第一層是接收數(shù)據(jù)和本地m序列相位差太遠滑動相關(guān)器需要掃完整個周期才能看到峰如果閾值設(shè)得很高或者峰值檢測只看了很短一段窗口就會一直報“未捕獲”。我當(dāng)時把觀測窗口拉長到兩個完整序列周期才看到相關(guān)峰。第二層是ADC采樣極性反了。接收信號經(jīng)過模擬前端可能存在反相0/1翻轉(zhuǎn)后相關(guān)器算出來的峰值變成負的閾值比較器只檢測正值當(dāng)然永遠觸發(fā)。解決方案是相關(guān)器同時計算正相關(guān)和負相關(guān)取絕對值后再比較。第三層是跨時鐘域采樣不穩(wěn)定。這個問題最坑因為現(xiàn)象和參數(shù)不收斂很像。把相關(guān)器輸入數(shù)據(jù)在仿真模型里加了幾納秒的抖動后相關(guān)峰也會偶爾丟失。最后的根治辦法就是前面說的把采樣數(shù)據(jù)和本地時鐘域徹底同步或者把相關(guān)器放在采樣時鐘域內(nèi)獨立跑。4.2 同步能鎖定但恢復(fù)時鐘抖動大鎖倒是鎖上了示波器上看恢復(fù)的碼元時鐘邊沿明顯在晃動。這種問題八成出在跟蹤環(huán)路參數(shù)上。環(huán)路帶寬太寬是首要嫌疑。比例系數(shù)和積分系數(shù)都偏大時定時誤差信號里的高頻噪聲沒有被有效濾除直接反映在NCO輸出上。我當(dāng)時把比例系數(shù)從1/16一路調(diào)到1/64積分系數(shù)從1/256調(diào)到1/1024抖動明顯收斂。其次要檢查誤差檢測本身超前滯后門兩路相關(guān)值做差之前最好各做一個短窗口的平均否則單點噪聲直接進入環(huán)路。另外過采樣率不夠也會導(dǎo)致相位調(diào)整步進過大。8倍過采樣下每個采樣點相當(dāng)于1/8碼元的相位步進如果環(huán)路收斂后依然在一個采樣點左右反復(fù)橫跳恢復(fù)時鐘邊沿就會出現(xiàn)量化抖動。想進一步降低抖動可以增加NCO的相位分辨率用分數(shù)插值而不是直接選離散采樣點。4.3 頻偏過大跟蹤環(huán)追不上常規(guī)晶振的頻偏通常在幾十ppm對1.024M碼元來說只有幾十赫茲偏差跟蹤環(huán)完全能跟上。但如果系統(tǒng)里收發(fā)兩端用的是獨立且精度很差的晶振頻偏到了千分級相關(guān)峰在一幀內(nèi)就會漂移好幾個采樣點跟蹤環(huán)會不斷失鎖重捕。處理辦法是在捕獲階段之后加一個粗頻偏估計。用兩個相鄰m序列周期相關(guān)峰的位置變化量除以周期時長就能估算出殘余頻偏把估算值直接累加到NCO頻率控制字的初始值上。這個操作能顯著縮小跟蹤環(huán)的捕獲范圍需求讓鎖相環(huán)只在很小的殘差范圍內(nèi)微調(diào)。我實測中把這個“粗頻偏校正”邏輯加上后系統(tǒng)容忍的頻偏范圍從幾十ppm擴大到幾百ppm代價只是多算了兩個相關(guān)峰的位置差FPGA里實現(xiàn)成本幾乎可以忽略。4.4 項目評審和面試里最常見的幾個追問m序列相關(guān)做同步這個題看起來工程實現(xiàn)不難但原理層面經(jīng)常被追問得很深。整理幾個我實際遇到過的核問題提前想清楚能在評審和面試時省很多事。m序列的自相關(guān)函數(shù)為什么是尖銳峰本質(zhì)是因為m序列的周期自相關(guān)函數(shù)在零偏移時為N非零偏移時為-1這個數(shù)學(xué)性質(zhì)來自LFSR序列的移位相加特性和平衡性。LFSR為什么不能全0復(fù)位全0狀態(tài)下反饋邏輯恒為0寄存器狀態(tài)永遠不變化序列周期退化為1同步自然失效。早遲門定時誤差檢測的原理是什么它利用的是匹配濾波輸出波形在最佳采樣點附近具有奇對稱特性誤差信號等于早門與晚門的差值這個差值是單調(diào)的可以直接驅(qū)動環(huán)路。數(shù)字鎖相環(huán)的帶寬怎么調(diào)帶寬和比例積分系數(shù)的關(guān)系是Kp越大收斂越快但噪聲越大Ki主要用于消除穩(wěn)態(tài)頻偏兩者配合決定環(huán)路的阻尼特性。這些問題如果能在做項目的時候順手梳理一遍對整體方案理解的深度完全不一樣。我后來帶新人的時候也發(fā)現(xiàn)能把m序列相關(guān)同步講清楚的人對后續(xù)的匹配濾波、環(huán)路設(shè)計、跨時鐘域處理這些基礎(chǔ)模塊都有比較扎實的框架。最后再分享一個我在實際調(diào)試中養(yǎng)成的習(xí)慣同步環(huán)路一上來不要追求一次調(diào)完美。先用零噪聲回環(huán)測試把相關(guān)峰、捕獲閾值、鎖定標志這些節(jié)點全部用邏輯分析儀抓出來確認每一步的行為都符合預(yù)期后再逐步疊加噪聲和頻偏。m序列這套方案的最大優(yōu)勢就是結(jié)構(gòu)簡單、觀測直觀只要相關(guān)峰的波形出來了后面所有問題都有線索可以按圖索驥。本文還有配套的精品資源點擊獲取