頻系統(tǒng)中m序列與Walsh碼的正確使用與避坑指南)
簡(jiǎn)介面向無(wú)線通信學(xué)習(xí)者的一份擴(kuò)頻序列專題文檔圍繞m序列、Walsh碼和Gold序列的原理展開(kāi)內(nèi)容包含最長(zhǎng)線性移位寄存器序列的結(jié)構(gòu)、反饋系數(shù)與起始狀態(tài)的影響Walsh碼的Hadamard矩陣生成思路和64階前向鏈路碼分配以及Gold序列由優(yōu)選對(duì)模2加得到的構(gòu)造方法。配套MATLAB函數(shù)代碼演示了從Hadamard矩陣經(jīng)Paley排序到Walsh排序的完整變換便于理解正交擴(kuò)頻碼的編程實(shí)現(xiàn)與矩陣轉(zhuǎn)換過(guò)程。壓縮包內(nèi)為單個(gè)Word文檔體積355KB內(nèi)容緊湊適合通信課程復(fù)習(xí)、CDMA系統(tǒng)原理自學(xué)或擴(kuò)頻碼生成實(shí)驗(yàn)對(duì)照查閱。文檔還特別分析了多徑傳播和小區(qū)間異步導(dǎo)致的非正交問(wèn)題說(shuō)明多址干擾為何不能完全消除有助于理解實(shí)際系統(tǒng)的局限。該份資料目前已有636人學(xué)習(xí)適合需要快速梳理擴(kuò)頻碼概念并希望結(jié)合代碼驗(yàn)證的初學(xué)者也可作為相關(guān)課程報(bào)告的參考素材。1. 擴(kuò)頻系統(tǒng)里的 m 序列和 Walsh 碼選錯(cuò)一次就全盤(pán)翻車第一次搭 CDMA 物理層仿真時(shí)很多人卡在同一個(gè)地方手上明明有 m 序列又有 Walsh 碼都是“擴(kuò)頻序列”到底該用哪個(gè)做用戶區(qū)分我見(jiàn)過(guò)不少新手拍板選了 m 序列結(jié)果兩路用戶數(shù)據(jù)解出來(lái)互相打架誤碼率怎么調(diào)都?jí)翰幌氯ヒ灿蟹催^(guò)來(lái)的拿 Walsh 碼去干同步捕獲相關(guān)峰糊成一片幀頭永遠(yuǎn)找不準(zhǔn)。問(wèn)題的根源不是哪個(gè)序列“更好”而是這兩類碼在擴(kuò)頻系統(tǒng)里負(fù)責(zé)的是完全不同的活m 序列是偽隨機(jī)碼靠尖銳的自相關(guān)峰做定時(shí)同步、擾碼和測(cè)距Walsh 碼是正交碼靠嚴(yán)格正交性把各路信號(hào)在碼域上分開(kāi)。這篇筆記就把它們的生成方式、參數(shù)配置、配合使用和最常見(jiàn)的翻車點(diǎn)一次講透適合做通信物理層仿真、軟件無(wú)線電和課設(shè)的從業(yè)者照著復(fù)現(xiàn)。2. 用本原多項(xiàng)式生成 m 序列抽頭配置和自相關(guān)特性才是真正的門(mén)檻2.1 從 LFSR 到最長(zhǎng)序列為什么周期偏偏是 2 的 n 次方減一m 序列的全稱是“最長(zhǎng)線性反饋移位寄存器序列”工程里最常見(jiàn)的生成載體就是 LFSR。一個(gè) n 級(jí)移位寄存器每個(gè)時(shí)鐘周期把若干級(jí)的異或結(jié)果反饋回輸入端得到的輸出序列就是線性遞歸序列。線性反饋的結(jié)構(gòu)決定了它最多能遍歷 2 的 n 次方減 1 個(gè)非零狀態(tài)——因?yàn)槿?0 狀態(tài)會(huì)永遠(yuǎn)鎖死在 0 上所以必須把它排除掉。能剛好走滿這 2 的 n 次方減 1 個(gè)狀態(tài)的反饋配置對(duì)應(yīng)的特征多項(xiàng)式就是本原多項(xiàng)式。這里有一個(gè)新手最容易搞錯(cuò)的點(diǎn)不是隨便接幾根反饋線就能得到 m 序列。抽頭取自本原多項(xiàng)式才算數(shù)取錯(cuò)了序列周期會(huì)縮短甚至產(chǎn)生多條短周期子序列拼起來(lái)的退化序列。比如 4 階 LFSR本原多項(xiàng)式有 x^4x1 和 x^4x^31 兩個(gè)等價(jià)形式周期都是 15但如果你拿 x^4x^21 這種非本原多項(xiàng)式去搭周期就只有 6頻譜特性完全不對(duì)。生成 m 序列時(shí)的工程約定有兩個(gè)一是初始化寄存器不能是全 0否則異或反饋永遠(yuǎn)輸出 0二是通常把“1”映射為負(fù)電平、“0”映射為正電平來(lái)做雙極性擴(kuò)頻這樣序列的直流分量最小。至于抽頭選哪幾級(jí)常見(jiàn)的做法是查本原多項(xiàng)式表而不是自己試探后面給出可以直接用的配置。2.2 生成 m 序列的最小 Python 實(shí)現(xiàn)抽頭、初始狀態(tài)和周期驗(yàn)證下面這段代碼用整數(shù)位移的方式模擬 LFSR比按位列表操作更快也更好理解反饋過(guò)程def mseq(n, taps, init1, lengthNone): 生成 m 序列雙極性1 - -1, 0 - 1 :param n: LFSR 階數(shù)移位寄存器級(jí)數(shù) :param taps: 反饋抽頭列表如 [4, 3] 表示第 4 級(jí)和第 3 級(jí)參與異或 :param init: 初始狀態(tài)不能為 0默認(rèn)取 1 :param length: 輸出序列長(zhǎng)度默認(rèn) 2^n - 1剛好一個(gè)完整周期 :return: numpy 數(shù)組取值 1 和 -1 import numpy as np if init 0: raise ValueError(初始狀態(tài)不能為 0否則 LFSR 鎖死在全零) if length is None: length (1 n) - 1 if length (1 n) - 1: raise ValueError(長(zhǎng)度不能超過(guò) m 序列最大周期) state init ((1 n) - 1) # 只保留 n 位有效狀態(tài) mask (1 n) - 1 taps_mask 0 for t in taps: taps_mask | (1 (t - 1)) seq np.zeros(length, dtypeint) for i in range(length): seq[i] state 1 # 取最低位作為輸出 fb bin(state taps_mask).count(1) 1 # 抽頭異或結(jié)果 state ((state 1) | (fb (n - 1))) mask return np.where(seq 1, -1.0, 1.0) # 1 - -1, 0 - 1邏輯說(shuō)明函數(shù)在每一個(gè)時(shí)鐘周期先輸出當(dāng)前寄存器的最低位再計(jì)算抽頭位置的異或結(jié)果把反饋值移入最高位。bin(state taps_mask).count(1) 1這行是求抽頭位的奇偶校驗(yàn)等價(jià)于多個(gè)抽頭的異或。參數(shù)說(shuō)明n通常取 5 到 15階數(shù)越高周期越長(zhǎng)但捕獲時(shí)滑動(dòng)搜索的計(jì)算量也越大taps必須配本原多項(xiàng)式的抽頭下面是幾張常用表。這里給出一個(gè)常用抽頭配置表直接照著用不會(huì)出問(wèn)題階數(shù) n周期 2^n - 1本原多項(xiàng)式一種形式抽頭 taps說(shuō)明37x^3x1[3, 1]適合做短幀同步序列415x^4x1[4, 1]仿真驗(yàn)證最常用周期短、算得快531x^5x^21[5, 2]兼顧周期與計(jì)算量7127x^7x1[7, 1]擴(kuò)頻增益已比較可觀101023x^10x^31[10, 3]常用于衛(wèi)星測(cè)距、幀同步碼2.3 自相關(guān)和互相關(guān)m 序列能干什么、不能干什么全看這兩個(gè)指標(biāo)m 序列最值錢的特性是周期自相關(guān)函數(shù)主峰等于序列長(zhǎng)度 N旁瓣恒定為 -1。歸一化之后主峰是 1旁瓣只有負(fù)的 N 分之一。這意味著接收端拿本地 m 序列和接收信號(hào)做滑動(dòng)相關(guān)只要對(duì)齊了就會(huì)出現(xiàn)一個(gè)非常尖銳的峰錯(cuò)開(kāi)哪怕 1 個(gè)碼片就會(huì)掉到旁瓣電平。這個(gè)特性讓它成為同步捕獲和測(cè)距的首選?;ハ嚓P(guān)就沒(méi)這么好看了。不同抽頭配置生成的兩條 m 序列互相關(guān)峰值大約在 2 的 n/2 次方分之一到 1 之間波動(dòng)并不是零。換句話說(shuō)m 序列不能用來(lái)做多用戶正交區(qū)分兩個(gè)用戶如果各拿一條 m 序列同時(shí)發(fā)數(shù)據(jù)解擴(kuò)之后會(huì)殘留約一半功率的互干擾。有人拿 m 序列做 CDMA 用戶碼然后發(fā)現(xiàn)用戶數(shù)一多信噪比急劇惡化就是這個(gè)原因——它本來(lái)就不是干這個(gè)的。驗(yàn)證這兩個(gè)特性的代碼很簡(jiǎn)單直接復(fù)用上面的mseq函數(shù)對(duì)兩條序列分別做循環(huán)相關(guān)再歸一化即可。實(shí)測(cè) 4 階 m 序列周期間自相關(guān)旁瓣就是 -1互相關(guān)則可能出現(xiàn) 3、5 這類非零峰值和理論值對(duì)得上。3. 從 Hadamard 矩陣造出 Walsh 碼說(shuō)要正交代價(jià)是每個(gè)碼片都要對(duì)齊3.1 為什么 Walsh 碼“正交”內(nèi)積為零才是硬指標(biāo)Walsh 碼是一組取值 1 和 -1 的正交序列工程上通過(guò) Hadamard 矩陣的行或列來(lái)取。Hadamard 矩陣的遞歸構(gòu)造規(guī)則是2N 階矩陣由四個(gè) N 階子塊拼成左上、右上、左下都是原矩陣右下是原矩陣取反。這樣構(gòu)造出來(lái)的任意兩行做逐位相乘再求和結(jié)果恒為零用數(shù)學(xué)語(yǔ)言說(shuō)就是行與行之間兩兩正交。正交性有什么工程意義假設(shè)兩路用戶數(shù)據(jù)分別乘上兩條不同的 Walsh 碼疊加在一起發(fā)送接收端只要拿其中一條 Walsh 碼做內(nèi)積另一路信號(hào)的貢獻(xiàn)會(huì)被積分成零等效于那路用戶“不存在”。這就是碼分多址最基本的原理。但注意這個(gè)結(jié)論有一個(gè)隱含前提所有用戶的碼片在接收端必須精確對(duì)齊錯(cuò)半個(gè)碼片正交性就開(kāi)始劣化錯(cuò)一個(gè)碼片基本等于偽正交。所以 Walsh 碼對(duì)同步的要求比 m 序列嚴(yán)苛得多這也是后面避坑章節(jié)重點(diǎn)展開(kāi)的內(nèi)容。3.2 遞歸生成 Walsh 碼的最小實(shí)現(xiàn)行號(hào)、碼長(zhǎng)怎么選生成 Walsh 碼最直接的方式就是遞歸構(gòu)造 Hadamard 矩陣然后按行取序列。下面這段代碼在 Python 里可以一次生成任意 2 的冪次長(zhǎng)度的 Walsh 碼集def hadamard_matrix(order): 遞歸構(gòu)造 Hadamard 矩陣 :param order: 矩陣階數(shù)必須為 2 的冪次如 4/8/16/64 :return: numpy 2D 數(shù)組每行是一條 Walsh 碼 import numpy as np if order 1: return np.array([[1.0]]) half hadamard_matrix(order // 2) top np.hstack([half, half]) bottom np.hstack([half, -half]) return np.vstack([top, bottom])邏輯說(shuō)明代碼遞歸地把小階 Hadamard 矩陣拼成大階矩陣右下角取負(fù)是保證正交性的關(guān)鍵少了這一步拼出來(lái)的矩陣行與行之間就不正交了。參數(shù)說(shuō)明order取 16 時(shí)得到 16 條長(zhǎng)度為 16 的 Walsh 碼能支持 16 個(gè)正交碼道IS-95 前向鏈路用的是 64 階 Walsh 碼對(duì)應(yīng) 64 個(gè)碼道其中一部分留給導(dǎo)頻和控制信道。仿真階段一般從 16 開(kāi)始跑通了再放大到 64因?yàn)?64 階時(shí)滑動(dòng)相關(guān)和矩陣運(yùn)算的規(guī)模會(huì)翻十幾倍。選取 Walsh 碼時(shí)還有一個(gè)約定俗成的坑直接從 Hadamard 矩陣取行得到的是“Hadamard 序”即按遞歸生成順序排列而很多教材和協(xié)議文檔里用的是“Walsh 序”也叫 sequency 序按行內(nèi)符號(hào)翻轉(zhuǎn)次數(shù)從少到多排列。兩種排序本身都正交但工程對(duì)接時(shí)如果發(fā)送端按 Hadamard 序、接收端按 sequency 序配置用戶號(hào)解擴(kuò)出來(lái)就是另一路用戶的數(shù)據(jù)。對(duì)接前先確認(rèn)排序約定這是血淚經(jīng)驗(yàn)。3.3 別忘了雙極性映射0/1 表示下“正交”會(huì)失效一半Walsh 碼的教科書(shū)定義往往寫(xiě)成 0/1 序列但做擴(kuò)頻調(diào)制時(shí)必須映射成 1/-1 雙極性信號(hào)。原因很直接用 0 和 1 做相關(guān)運(yùn)算時(shí)兩條不同 Walsh 碼的內(nèi)積不是零而是出現(xiàn)在 {0, 1} 之間的某個(gè)值并且同一路信號(hào)的自相關(guān)也不等于碼長(zhǎng)而是等于碼長(zhǎng)的一半因?yàn)橹绷鞣至炕煸诶锩?。雙極性映射之后直流分量消失任意兩行內(nèi)積嚴(yán)格為零自相關(guān)等于碼長(zhǎng) N判決閾值也是干凈的零。這個(gè)坑在仿真里經(jīng)常表現(xiàn)為數(shù)據(jù)解出來(lái)了但幅度總是偏小一半或者疊加兩路用戶后解擴(kuò)結(jié)果帶有固定偏置。檢查步驟很簡(jiǎn)單——看發(fā)端映射函數(shù)里是不是用了2*x-1或np.where(x0, -1, 1)做了雙極性轉(zhuǎn)換。4. 集中避坑同步誤差、正交性假象和誤用錯(cuò)配的四個(gè)常見(jiàn)翻車點(diǎn)4.1 解擴(kuò)后殘留大量干擾信號(hào)錯(cuò)了一個(gè)碼片正交性就垮了現(xiàn)象兩路用戶都按正交 Walsh 碼發(fā)送接收端解擴(kuò)某一路后另一路用戶的語(yǔ)音/數(shù)據(jù)串?dāng)_清晰可聞信噪比只比沒(méi)擴(kuò)頻時(shí)好一點(diǎn)點(diǎn)。原因Walsh 碼的正交性建立在所有碼片在接收端精確時(shí)間對(duì)齊的基礎(chǔ)上。收發(fā)兩端時(shí)鐘不同步、或者多徑信道引入時(shí)延都會(huì)讓碼片邊界錯(cuò)位。錯(cuò)位超過(guò) 0.5 個(gè)碼片后兩行 Walsh 碼的相關(guān)值從零變成接近碼長(zhǎng)一半的偽峰正交性名存實(shí)亡。解決在 Walsh 解擴(kuò)之前必須先做碼片級(jí)同步常見(jiàn)做法是用 m 序列做幀頭/導(dǎo)頻捕獲到相關(guān)峰后以此為時(shí)間基準(zhǔn)對(duì)齊碼片再做 Walsh 內(nèi)積。同步精度要控制在正負(fù) 0.2 個(gè)碼片以內(nèi)否則正交性余量會(huì)被消耗殆盡。4.2 用 m 序列區(qū)分多用戶用戶數(shù)一多就集體翻車現(xiàn)象給每個(gè)用戶分配一條不同抽頭的 m 序列仿真空曠信道下單獨(dú)跑一路沒(méi)問(wèn)題加到三路以上誤碼率急劇惡化和信噪比無(wú)關(guān)。原因m 序列是偽隨機(jī)碼不是正交碼。不同 m 序列之間互相關(guān)峰值最大可以達(dá)到接近 1 的水平遠(yuǎn)談不上正交。多用戶疊加后每路用戶收到的都是其他所有用戶的互相關(guān)干擾之和信噪比增長(zhǎng)完全跟不上用戶數(shù)增長(zhǎng)。解決區(qū)分用戶用 Walsh 碼或 OVSF 碼這類正交碼m 序列退回去做幀同步和擾碼。這也是實(shí)際 CDMA 系統(tǒng)的通用架構(gòu)Walsh 碼做信道化m 序列做小區(qū)擾碼和同步。4.3 拿 Walsh 碼做同步捕獲相關(guān)峰永遠(yuǎn)找不準(zhǔn)現(xiàn)象把本地 Walsh 碼和接收信號(hào)做滑動(dòng)相關(guān)主峰不夠尖銳旁邊連著好幾個(gè)大小差不多的旁瓣定時(shí)估計(jì)抖動(dòng)很大幀頭位置判斷錯(cuò)誤頻繁出現(xiàn)。原因Walsh 碼是正交碼設(shè)計(jì)目標(biāo)是行間互相關(guān)為零不是自相關(guān)尖銳。它的周期自相關(guān)旁瓣不是 -1 而是可能達(dá)到相當(dāng)高的值碼長(zhǎng)越長(zhǎng)、旁瓣越多做滑動(dòng)相關(guān)時(shí)根本沒(méi)有“唯一峰”的概念。解決定時(shí)同步交給 m 序列這類 PN 碼Walsh 碼只做解擴(kuò)和用戶區(qū)分。若鏈路預(yù)算實(shí)在緊張也可以用 m 序列做粗同步后再用 Walsh 做碼片級(jí)精同步微調(diào)但主同步手段不能換。4.4 擴(kuò)頻信號(hào)頻譜出現(xiàn)線譜離散峰PN 碼看起來(lái)不夠“隨機(jī)”現(xiàn)象把 m 序列擴(kuò)頻后的信號(hào)送到頻譜儀看到在載頻附近冒出一根根離散的線譜而不是平滑的擴(kuò)頻包絡(luò)能量集中度比理論預(yù)期高。原因m 序列是周期的周期短到一定程度頻譜自然出現(xiàn)間隔為碼速率除以周期長(zhǎng)度的離散譜線。尤其是 4 階、5 階這類短周期 m 序列周期只有 15 或 31譜線間隔非常寬既不利于隱蔽性也容易形成干擾尖峰。解決長(zhǎng)周期化處理。常見(jiàn)做法是拿多個(gè)不同相位的 m 序列加長(zhǎng)合成、或者用 m 序列和 Walsh 碼相乘混合成復(fù)合擴(kuò)頻序列也可以把短 m 序列作為擾碼再疊加在 Walsh 擴(kuò)頻輸出上破壞周期性。工程上如果協(xié)議允許直接把 m 序列階數(shù)提到 10 以上頻譜離散度肉眼可見(jiàn)改善。5. 搭建一條完整的擴(kuò)頻鏈路m 序列定幀頭、Walsh 做碼分用戶區(qū)分5.1 最小仿真鏈路參數(shù)與整體流程把兩條正交 Walsh 碼分配給兩個(gè)用戶數(shù)據(jù)用 BPSK 調(diào)制每符號(hào)用一個(gè) 16 位的 Walsh 碼做擴(kuò)頻幀頭用一條 15 位的 4 階 m 序列插在每幀數(shù)據(jù)前面。接收端先拿本地 m 序列做滑動(dòng)相關(guān)找?guī)瘘c(diǎn)再按對(duì)齊后的碼片邊界做 Walsh 解擴(kuò)恢復(fù)兩個(gè)用戶的數(shù)據(jù)。完整參數(shù)如下。參數(shù)取值說(shuō)明擴(kuò)頻碼Walsh 碼長(zhǎng)度 16支持 16 個(gè)正交碼道仿真取 2 路用戶同步碼m 序列4 階周期 15幀頭捕獲相關(guān)峰旁瓣為 -1數(shù)據(jù)調(diào)制BPSK雙極性 1/-1與擴(kuò)頻碼直接相乘每幀結(jié)構(gòu)m 序列幀頭 8 個(gè)數(shù)據(jù)符號(hào)幀頭長(zhǎng)度短于 Walsh 碼長(zhǎng)方便觀測(cè)捕獲峰信道AWGN無(wú)多徑先排除信道因素單獨(dú)驗(yàn)證碼分正交性用戶數(shù)據(jù)每用戶 8 bit獨(dú)立隨機(jī)兩路數(shù)據(jù)完全獨(dú)立5.2 發(fā)送端幀頭插入與 Walsh 擴(kuò)頻疊加發(fā)送端的核心操作是每個(gè)用戶的數(shù)據(jù)符號(hào)與一條固定分配的 Walsh 碼逐碼片相乘兩路用戶的結(jié)果直接相加得到一幀基帶信號(hào)再在幀頭位置填入 m 序列。下面是完整的發(fā)送端實(shí)現(xiàn)。import numpy as np def tx_frame(m_seq, walsh_mat, user1_bits, user2_bits): 發(fā)送端m 序列作幀頭 兩路用戶 Walsh 擴(kuò)頻疊加 :param m_seq: 4 階 m 序列長(zhǎng)度 15雙極性 :param walsh_mat: 16x16 Walsh 矩陣按行取碼 :param user1_bits: 0/1 數(shù)組長(zhǎng)度 8 :param user2_bits: 0/1 數(shù)組長(zhǎng)度 8 :return: 基帶發(fā)送序列 w1 walsh_mat[0] # 用戶 1 分配第 0 行 w2 walsh_mat[1] # 用戶 2 分配第 1 行 # BPSK 調(diào)制并擴(kuò)頻每個(gè)符號(hào)乘以整條 Walsh 碼 user1_sym np.where(user1_bits 1, 1.0, -1.0) user2_sym np.where(user2_bits 1, 1.0, -1.0) spread1 np.kron(user1_sym, w1) # 符號(hào)序列與 Walsh 碼做 Kronecker 積 spread2 np.kron(user2_sym, w2) data_part spread1 spread2 # 兩路用戶碼域疊加 return np.concatenate([m_seq, data_part])邏輯說(shuō)明np.kron(user_sym, w1)把每個(gè)數(shù)據(jù)符號(hào)擴(kuò)展成 16 個(gè)碼片等效于符號(hào)與 Walsh 碼逐位相乘兩路用戶的擴(kuò)頻結(jié)果直接相加就是碼分疊加后的信號(hào)。幀頭 m 序列拼在數(shù)據(jù)前面共用一個(gè)發(fā)射功率。參數(shù)說(shuō)明walsh_mat[0]和walsh_mat[1]必須取自同一個(gè) Hadamard 矩陣構(gòu)造結(jié)果且行序要按雙方約定好的排序這里的兩個(gè) Walsh 碼在 16 階矩陣下互相關(guān)為零。5.3 接收端滑動(dòng)相關(guān)捕獲幀頭再做 Walsh 解擴(kuò)判決接收端拿到一幀完整信號(hào)后第一步是先找到幀頭起點(diǎn)。具體做法是拿本地 m 序列與接收信號(hào)從第一個(gè)碼片開(kāi)始逐點(diǎn)滑動(dòng)做相關(guān)找到相關(guān)峰的位置這個(gè)位置就是數(shù)據(jù)部分的起始邊界。注意滑動(dòng)步長(zhǎng)是 1 個(gè)碼片所以搜索范圍越長(zhǎng)計(jì)算量越大。def rx_frame(rx, m_seq, walsh_mat, frame_len): 接收端m 序列滑動(dòng)相關(guān)捕獲幀頭 Walsh 解擴(kuò) :param rx: 接收序列已加噪聲 :param m_seq: 本地 m 序列長(zhǎng)度 15 :param walsh_mat: 16x16 Walsh 矩陣 :param frame_len: 發(fā)送幀總長(zhǎng)度 :return: 恢復(fù)的兩路用戶符號(hào) (0/1 數(shù)組) m_len len(m_seq) # 1. 滑動(dòng)相關(guān)捕獲幀頭 corr np.array([ np.dot(rx[i:i m_len], m_seq) for i in range(len(rx) - m_len 1) ]) head_pos int(np.argmax(np.abs(corr))) # 相關(guān)峰位置 幀頭起點(diǎn) # 2. 從幀頭后開(kāi)始截取數(shù)據(jù)區(qū) data_start head_pos m_len data_part rx[data_start:data_start frame_len - m_len] # 3. 按符號(hào)逐個(gè)解擴(kuò)與兩條 Walsh 碼分別內(nèi)積符號(hào)判決 w1, w2 walsh_mat[0], walsh_mat[1] n_sym len(data_part) // 16 sym1, sym2 [], [] for s in range(n_sym): chip data_part[s * 16:(s 1) * 16] r1 np.dot(chip, w1) # 用戶 1 的相關(guān)值 r2 np.dot(chip, w2) sym1.append(1 if r1 0 else 0) sym2.append(1 if r2 0 else 0) return np.array(sym1), np.array(sym2)邏輯說(shuō)明滑動(dòng)相關(guān)用np.dot(rx[i:im_len], m_seq)計(jì)算每個(gè)候選位置的相關(guān)系數(shù)捕獲后取最大值位置作為幀起點(diǎn)。Walsh 解擴(kuò)則是對(duì)每個(gè)符號(hào)片段的 16 個(gè)碼片分別與兩條本地 Walsh 碼做內(nèi)積內(nèi)積結(jié)果大于零判為 1、小于零判為 0。參數(shù)說(shuō)明滑動(dòng)相關(guān)窗口長(zhǎng)度等于 m 序列長(zhǎng)度這里幀頭是 15 位所以窗口步長(zhǎng) 1 遍歷整個(gè)接收幀Walsh 碼長(zhǎng) 16所以數(shù)據(jù)區(qū)長(zhǎng)度必須是 16 的整數(shù)倍否則最后一個(gè)符號(hào)會(huì)截?cái)?。把幀頭捕獲和 Walsh 解擴(kuò)分開(kāi)寫(xiě)是為了排查問(wèn)題時(shí)能獨(dú)立驗(yàn)證同步模塊和解擴(kuò)模塊的好壞。6. 驗(yàn)證鏈路做沒(méi)做對(duì)測(cè)三個(gè)指標(biāo)再用同步容差當(dāng)體檢鏈路搭完后不要急著看誤碼率先做三個(gè)驗(yàn)證任何一個(gè)不過(guò)關(guān)都說(shuō)明前面的實(shí)現(xiàn)有偏差。第一個(gè)驗(yàn)證是 m 序列自相關(guān)峰。把本地 m 序列和自身做循環(huán)相關(guān)主峰應(yīng)為 15旁瓣全部為 -1如果旁瓣有超過(guò) -1 的值說(shuō)明生成的不是本原序列。第二個(gè)驗(yàn)證是 Walsh 正交性把 Walsh 矩陣任意兩行做內(nèi)積全部為零并把第 0 行和第 1 行分別與自身做內(nèi)積確認(rèn)自相關(guān)為 16這步能直接暴露 0/1 映射沒(méi)轉(zhuǎn)雙極性的問(wèn)題。第三個(gè)驗(yàn)證是無(wú)噪聲環(huán)境下解擴(kuò)結(jié)果發(fā)端 8 bit 隨機(jī)數(shù)據(jù)進(jìn)tx_frame接收端rx_frame恢復(fù)后逐一對(duì)比誤碼率必須為 0此時(shí)再逐步把信噪比降到 10 dB、5 dB觀察誤碼率曲線是否符合 BPSK 理論趨勢(shì)。我個(gè)人的習(xí)慣是再補(bǔ)一個(gè)同步容差測(cè)試把接收序列人為向右偏移 1 到 8 個(gè)碼片觀察 Walsh 解擴(kuò)誤碼率從哪個(gè)偏移量開(kāi)始明顯惡化。實(shí)測(cè)下來(lái)偏移 1 個(gè)碼片時(shí)正交性已損失明顯偏移超過(guò) 4 個(gè)碼片基本等于沒(méi)有擴(kuò)頻。這個(gè)測(cè)試能直接告訴你在真實(shí)系統(tǒng)里碼片級(jí)同步的精度紅線在哪里值得每次改完鏈路都跑一遍。等這套流程跑順了再把 Walsh 碼長(zhǎng)升到 64、給每路用戶疊加獨(dú)立的 m 序列擾碼就是一套可以往實(shí)際工程遷移的 CDMA 前端原型了。希望這些踩過(guò)的彎能幫你少走一段。本文還有配套的精品資源點(diǎn)擊獲取