與避坑)
簡介面向通信原理與數(shù)字調(diào)制課程學(xué)習(xí)者的16QAM仿真代碼包聚焦星座圖繪制與誤碼率評估兩個核心實驗環(huán)節(jié)適合需要理解QAM映射、解調(diào)判決與AWGN信道性能的本科生或自學(xué)者動手復(fù)現(xiàn)。包內(nèi)共8個文件均為MATLAB的.m腳本與函數(shù)壓縮包約3KB體量輕便卻覆蓋了從隨機二進制序列生成、串并轉(zhuǎn)換、16QAM調(diào)制、星座點可視化、最佳接收解調(diào)到BER統(tǒng)計的完整鏈路函數(shù)職責(zé)拆分清晰便于按模塊閱讀和二次修改。已有1927人學(xué)習(xí)下載說明其在課程實驗與入門仿真中具有一定參考價值。讀者可據(jù)此搭建端到端仿真流程觀察16個星座點在理想與含噪條件下的分布差異并通過改變信噪比得到誤碼率曲線進而理解幅度相位聯(lián)合調(diào)制與最大似然檢測的關(guān)系代碼結(jié)構(gòu)也可作為自建通信鏈路仿真框架的起點。1. 16QAM 星座圖仿真與誤碼率仿真這套 MATLAB 腳本到底替你算了什么第一次在 MATLAB 里畫 16QAM 星座圖很多人都會撞上同一個畫面16 個點倒是出來了要么全擠在 ±0.3 附近糊成一團要么整體轉(zhuǎn)了 45 度再一看誤碼率曲線跟理論值整整差著 10 dB怎么調(diào) SNR 都對不上。這套「16QAM 星座圖仿真及誤碼率仿真」的 MATLAB 腳本處理的就是這一段最容易翻車的鏈路Gray 映射星座生成、平均功率歸一化、按 Eb/N0 加復(fù)高斯噪聲、最小歐氏距離判決最后把仿真 BER 和理論 erfc 曲線疊在同一張 semilogy 圖上。它不是什么大工程就是一組能獨立跑起來的 .m 文件但鏈路是完整的比特進來符號出去噪聲加上去判決回來誤碼數(shù)出來。做通信原理課設(shè)的、剛接觸鏈路級仿真想找一副能改的底子的、準備在它上面接瑞利衰落或者 OFDM 的都適合從這兒起步。代碼量不大可每一個參數(shù)怎么來的、每一行為什么要這么寫恰恰是新手最容易糊過去的地方。2. 鏈路骨架一條從比特到誤碼計數(shù)的 16QAM 仿真通路2.1 文件劃分與主腳本的調(diào)用順序這份資源一般拆成兩個入口腳本加一組函數(shù)邏輯上跟真實鏈路的模塊劃分一一對應(yīng)。目錄大概長這樣qam16_sim/ ├── main_qam16_ber.m % 主腳本: 掃 Eb/N0, 出 BER 曲線 ├── main_qam16_const.m % 主腳本: 單個 SNR 下的星座圖 ├── qam16_mod.m % 比特 - 復(fù)符號 (Gray 映射) ├── qam16_demod.m % 復(fù)符號 - 比特 (硬判決) ├── add_awgn.m % 按 Eb/N0 加復(fù)高斯噪聲 ├── theory_ber16qam.m % Gray 16QAM 理論誤碼率 └── plot_constellation.m % 星座圖繪制調(diào)用順序是一條直線沒有任何分支randi產(chǎn)生比特流 →qam16_mod映射成復(fù)符號 →add_awgn按當前 Eb/N0 疊加噪聲 →qam16_demod判決回比特 → 跟發(fā)送比特逐位比對mean(rx ~ tx)就是這一點的 BER。拆成多個文件而不是一個大腳本好處在調(diào)試階段就顯出來了。改 SNR 范圍、改符號數(shù)這類操作重跑主腳本就行只想看星座圖形狀時直接調(diào)main_qam16_const.m不用陪著蒙特卡洛循環(huán)跑幾十秒。我一般在寫這類仿真時都會把「畫圖的」和「算數(shù)的」分開因為調(diào)參階段你會反復(fù)畫圖但不想反復(fù)重算。真正要留意的是數(shù)據(jù)的方向約定。qam16_mod輸出列向量qam16_demod也按列向量處理中間加噪保持同尺寸。一旦某一處不小心轉(zhuǎn)置成行向量mean(a ~ b)就可能因為維度廣播算出一個看著像模像樣、其實是錯的誤碼率——這種 bug 最陰因為程序不報錯曲線也照畫。2.2 參數(shù)表M、k、Eb/N0 與蒙特卡洛符號數(shù)仿真里所有「玄學(xué)」都藏在參數(shù)定義里先把這張表釘死后面看代碼才不會迷路。參數(shù)變量名典型取值含義與取值依據(jù)調(diào)制階數(shù)M164×4 方形星座M 取 2 的偶數(shù)次冪才方便方形映射每符號比特數(shù)k4log2(M)決定比特流分組的長度符號數(shù)Nsym2e5 ~ 1e6每個 SNR 點獨立生成見 2.4信噪比掃描EbN0_dB0:2:16步長 2 dB 足夠看清曲線拐點噪聲方差N01/(k·EbN0)前提是符號功率已歸一化為 1判決電平表lut[-3 -1 3 1]未歸一化尺度下的 4PAM 電平歸一化因子—sqrt(10)16QAM 平均符號功率的平方根k log2(M)這一行別寫成硬編碼 4否則你哪天想擴到 64QAM 時得回頭把每個文件里的 4 全改一遍。用log2(M)寫改成M 64時只有映射表要重寫。EbN0_dB從 0 開始而不是從 -5 開始是因為 16QAM 在 0 dB 時的理論 BER 已經(jīng)在 1.4e-1 量級再往下掃就是一片 0.3~0.5 的平線沒有信息量。掃到 16 dB 時理論值約 1e-8仿真要到這個量級得跑上千萬符號所以實際腳本常常把上限壓到 12~14 dB曲線能做到 1e-5 就夠交差了。2.3 歸一化與 Es/N0 到 Eb/N0 的換算這是整套仿真里最容易翻車的一步也是絕大多數(shù)「曲線平移」問題的根源。16QAM 未歸一化的標準星座I 路和 Q 路各取{-3, -1, 1, 3}四個電平。每路平均平方值是(9119)/4 5兩路加起來平均符號能量Es 10。也就是說如果你直接拿I 1j*Q當發(fā)送符號那它的平均功率是 10 而不是 1。而add_awgn里算噪聲方差時通常的寫法是假定Es 1N0 1 / (k * EbN0_lin); % 符號功率 1 時成立一旦發(fā)送符號的實際功率是 10等效信噪比就被抬高了 10 dB仿真曲線會整體往左平移 10 dB看上去「比理論還好」——這不是算法厲害是賬算錯了。所以調(diào)制函數(shù)最后一定要有這一句sym (I 1j*Q) / sqrt(10); % 把平均符號功率拉回 1sqrt(10)不是隨手寫的魔法數(shù)它是平均符號能量的平方根。同理解調(diào)端拿到r之后要乘回去z r * sqrt(10)把接收符號還原到{-3,-1,1,3}的判決尺度上才能跟lut直接比距離。換算關(guān)系本身也值得在紙上推一遍。Es k · Eb已知Es 1那么Eb 1/k。要求Eb/N0就有Eb/N0 1 / (k · N0) N0 1 / (k · (Eb/N0))這里的Eb/N0是線性值不是 dB所以循環(huán)里必須寫10^(EbN0_dB/10)。忘了這步、直接把 dB 值當線性值代進去曲線會變成一條形狀詭異的東西從 0 dB 到 10 dB 幾乎不動——踩過一次就記住了。復(fù)噪聲的方差還要再分一半復(fù)高斯噪聲n nI j·nQ的總方差是N0實部和虛部各占N0/2。所以生成時是n sqrt(N0/2) * (randn(size(sym)) 1j*randn(size(sym)));寫成sqrt(N0)就相當于每個維度多給了 3 dB仿真結(jié)果又會好 3 dB。這個錯和上一個錯疊加起來正好能湊出一條「完美貼合理論」的假曲線很多人在課設(shè)答辯時才發(fā)現(xiàn)問題。2.4 判決方式硬判決、軟判決與內(nèi)置 qammod 的差別這份腳本用的是硬判決解調(diào)器直接吐 0/1然后逐位比對。好處是簡單、快、誤碼率統(tǒng)計直白不需要額外的譯碼器。但如果你打算在這套東西上接卷積碼或者 LDPC硬判決就會讓編碼增益打折。軟判決輸出的是每個比特的對數(shù)似然比LLR常見做法是 max-log 近似對每個比特找「該比特為 0 的所有星座點里距離最小的」和「該比特為 1 的所有星座點里距離最小的」兩者歐氏距離平方之差再除以N0就是 LLR。16 個點做全搜索也就 16 次距離計算復(fù)雜度完全不是問題。另一條路是直接用 Communications Toolbox 的qammod/qamdemodsym qammod(bits_int, 16, InputType, bit, ... UnitAveragePower, true, PlotConstellation, false); bits_rx qamdemod(r, 16, OutputType, bit, ... UnitAveragePower, true);注意UnitAveragePower這個開關(guān)打開后qammod內(nèi)部就替你做了/sqrt(10)此時add_awgn里按Es 1算噪聲才成立。如果關(guān)掉它默認行為平均功率是 10你得把噪聲方差乘 10。這兩個選項混著用是僅次于歸一化遺漏的第二大坑。自己手寫映射表的價值在于可控想換成星形 16QAM、想人為制造 I/Q 不平衡、想給某些星座點加偏置改一張lut表就完事比跟工具箱的黑匣子較勁舒服得多。3. 核心代碼逐段拆調(diào)制、加噪、判決三段主干3.1 查表法生成 Gray 映射星座Gray 映射的意義很實在相鄰的星座點只差一個比特這樣噪聲把符號推到隔壁點時只錯 1 個比特而不是 2 個。16QAM 的方形星座可以拆成 I、Q 兩路獨立的 4PAM每路用 2 個比特做 Gray 編碼。function sym qam16_mod(bits) % QAM16_MOD Gray 映射的 16QAM 調(diào)制 % bits : 行向量, 元素 0/1, 長度必須是 4 的整數(shù)倍 % sym : 列向量, 復(fù)符號, 平均功率歸一化為 1 k 4; if mod(numel(bits), k) ~ 0 error(比特數(shù) %d 不是 4 的整數(shù)倍, numel(bits)); end b reshape(bits(:), k, []).; % N x 4, 每行是一個符號的 b1 b2 b3 b4 idxI b(:,1)*2 b(:,2); % 00-0 01-1 10-2 11-3 idxQ b(:,3)*2 b(:,4); % Gray 碼 - 4PAM 電平, 索引 1..4 對應(yīng) idx 0..3 % 00 - -3, 01 - -1, 10 - 3, 11 - 1 lut [-3, -1, 3, 1]; I lut(idxI 1).; % 轉(zhuǎn)成列向量 Q lut(idxQ 1).; sym (I 1j*Q) / sqrt(10); % 平均符號功率歸一化為 1 end逐行看。reshape(bits(:), k, [])按列優(yōu)先把比特流切成每 4 個一組轉(zhuǎn)置后每行就是一個符號的[b1 b2 b3 b4]。這里用bits(:)強制成列向量是為了防止調(diào)用方傳進來一個行向量導(dǎo)致reshape的分組順序跟預(yù)期不一致——這種細節(jié)在單獨測試時看不出問題接到長比特流上才會暴露。idxI b(:,1)*2 b(:,2)把兩個比特拼成一個 0~3 的整數(shù)。lut的索引要1因為 MATLAB 從 1 開始。關(guān)鍵在于lut [-3, -1, 3, 1]這個順序按電平排序是-3, -1, 1, 3對應(yīng)的 Gray 碼是00, 01, 11, 10。相鄰電平兩兩比較00/01差 1 位、01/11差 1 位、11/10差 1 位Gray 性質(zhì)成立。如果圖省事寫成lut [-3, -1, 1, 3]自然二進制順序星座圖看著一模一樣但 BER 曲線在中等信噪比會明顯抬高——因為相鄰點可能差 2 個比特。這就是典型的「圖對了、數(shù)不對」。最后/sqrt(10)做歸一化。前面推過四個電平的平方和是 20除以 4 得 5I/Q 兩路共 10。3.2 按 Eb/N0 反推復(fù)噪聲方差function r add_awgn(sym, EbN0_dB, k) % ADD_AWGN 按每比特信噪比 Eb/N0 疊加復(fù)高斯白噪聲 % sym : 平均功率已歸一化為 1 的復(fù)符號 % EbN0_dB : 標量, 單位 dB % k : 每符號比特數(shù), 16QAM 取 4 % r : 與 sym 同尺寸的接收符號 EbN0_lin 10^(EbN0_dB/10); % dB - 線性 N0 1 / (k * EbN0_lin); % 符號功率為 1 時的噪聲功率譜密度 % 復(fù)噪聲總方差 N0, 實部虛部各 N0/2 n sqrt(N0/2) * (randn(size(sym)) 1j*randn(size(sym))); r sym n; end10^(EbN0_dB/10)是 dB 到線性功率的換算注意是除以 10 而不是 20——功率比用 10log幅度比才用 20log。這里傳進來的是功率意義上的Eb/N0所以用 10。N0 1/(k*EbN0_lin)的推導(dǎo)在 2.3 已經(jīng)走過一遍符號功率歸一化為 1Es 1Es/N0 k·Eb/N0于是N0 1/(k·Eb/N0)。如果哪天你把歸一化因子改成別的值這一行必須同步改否則又是幾 dB 的偏差。噪聲生成里sqrt(N0/2)是標準差不是方差。randn產(chǎn)生的是單位方差的標準正態(tài)乘上標準差之后每個維度方差才是N0/2合成復(fù)噪聲的方差是N0。這三個量方差、標準差、單邊功率譜密度在通信仿真里經(jīng)常被混著叫寫代碼時心里要有數(shù)。還有一點randn(size(sym))里的size(sym)是必要的。如果寫成randn(1, N)而sym是列向量MATLAB 的隱式擴展會把它算成N×N矩陣內(nèi)存瞬間爆掉。我在調(diào)試一個Nsym 1e6的腳本時被這個坑過一次任務(wù)管理器里 MATLAB 直接吃到 30 多個 G。3.3 最小歐氏距離判決與比特還原判決是調(diào)制的逆過程但因為 16QAM 是方形星座I 路和 Q 路可以完全獨立判決不需要在 16 個點上做二維搜索。function bits qam16_demod(r) % QAM16_DEMOD 16QAM 硬判決解調(diào) (最小歐氏距離) % r : 接收復(fù)符號, 列向量 % bits : 行向量, 長度 4 * 符號數(shù) lut [-3, -1, 3, 1]; z r(:) * sqrt(10); % 還原到判決尺度 [~, idxI] min(abs(real(z) - lut), [], 2); % 每行取最小距離, 得 1..4 [~, idxQ] min(abs(imag(z) - lut), [], 2); iI idxI - 1; % 回到 0..3 iQ idxQ - 1; b1 floor(iI/2); b2 mod(iI,2); % 高位 / 低位 b3 floor(iQ/2); b4 mod(iQ,2); bits reshape([b1 b2 b3 b4]., 1, []); % 按符號順序拼回比特流 endreal(z)是N×1lut是1×4相減時 MATLAB 的隱式擴展自動得到N×4的距離矩陣min(..., [], 2)沿第二維取最小返回的idxI就是每個符號在 I 路上最接近的電平索引。這一步等價于在{-3,-1,1,3}四個電平里找最近的只不過寫成了向量化的矩陣運算比for循環(huán)快一個數(shù)量級。iI idxI - 1把索引換回 0~3 的整數(shù)然后floor(iI/2)和mod(iI,2)拆出兩個比特。注意這里拆出來的順序必須跟調(diào)制端b(:,1)*2 b(:,2)的拼接順序嚴格對應(yīng)否則比特順序錯位誤碼率永遠卡在 0.5 附近下不去。最后的reshape([b1 b2 b3 b4]., 1, [])值得停一下。[b1 b2 b3 b4]是N×4轉(zhuǎn)置成4×Nreshape按列優(yōu)先展平得到的順序是「符號 1 的 b1 b2 b3 b4符號 2 的 b1 b2 b3 b4……」。這跟調(diào)制端reshape(bits(:), 4, []).的分組方式完全一致一進一出才對得上。這里其實還藏著一個性能點min(abs(real(z) - lut), [], 2)會臨時創(chuàng)建一個N×4的中間矩陣。Nsym 1e6時是 4M 個 double32 MB還好但如果哪天你擴到 256QAM 并且一次跑 1e7 個符號這個中間矩陣就上 G 了。真到那一步改成三次if判斷邊界會更省內(nèi)存。3.4 誤碼統(tǒng)計循環(huán)與理論 erfc 曲線主腳本把上面三段串起來外面套一個 SNR 掃描循環(huán)。M 16; k log2(M); EbN0_dB 0:2:16; Nsym 2e5; ber_sim zeros(size(EbN0_dB)); ber_thr zeros(size(EbN0_dB)); rng(2024); % 固定種子, 結(jié)果可復(fù)現(xiàn) bits_tx randi([0 1], 1, k*Nsym); sym_tx qam16_mod(bits_tx); for ii 1:numel(EbN0_dB) r add_awgn(sym_tx, EbN0_dB(ii), k); bits_rx qam16_demod(r); ber_sim(ii) mean(bits_rx ~ bits_tx); EbN0_lin 10^(EbN0_dB(ii)/10); ber_thr(ii) 3/8 * erfc(sqrt(2/5 * EbN0_lin)); % Gray 16QAM 理論值 end semilogy(EbN0_dB, ber_thr, k-, LineWidth, 1.2); hold on; semilogy(EbN0_dB, ber_sim, bo, MarkerFaceColor, b); grid on; xlabel(E_b/N_0 (dB)); ylabel(BER); legend(理論值, 仿真值, Location, southwest);rng(2024)是后悔藥。通信仿真跑一次幾十秒曲線抖一下你根本分不清是噪聲采樣波動還是代碼改壞了。固定種子之后每次跑出來的數(shù)完全一樣改一行代碼對比前后差異才有意義。種子取什么值無所謂我習(xí)慣用當天的日期。randi([0 1], 1, k*Nsym)一次生成全部比特在循環(huán)外完成。這樣每個 SNR 點用的都是同一組發(fā)送符號曲線上的點之間才有可比性如果在循環(huán)內(nèi)重新生成低信噪比和高信噪比的差異里就混進了隨機性。理論值那一行3/8 * erfc(sqrt(2/5 * EbN0_lin))是 Gray 編碼方形 16QAM 的近似式。推導(dǎo)路徑是符號錯誤率Ps 3·Q(sqrt(4Eb/(5N0)))Gray 映射下Pb ≈ Ps/k再把Q(x) 0.5·erfc(x/√2)代進去化簡就得到3/8·erfc(sqrt(0.4·Eb/N0))。這個式子在Eb/N0 5 dB時跟精確值貼得很緊低信噪比會略微高估看曲線時心里有數(shù)就行。semilogy畫圖時仿真點用bo而不是連線是為了讓讀者一眼看出「這是蒙特卡洛采樣點不是連續(xù)函數(shù)」。3.5 星座圖繪制讓 16 個點分得開星座圖本身信息量不大但它是排查問題最快的工具——曲線不對時先看星座圖形狀八成能定位到是歸一化、相位還是判決尺度的問題。function plot_constellation(sym, ttl) % PLOT_CONSTELLATION 畫接收符號的星座分布并疊加理想點 figure(Color, w); plot(real(sym), imag(sym), b., MarkerSize, 4); hold on; ref_bits dec2bin(0:15, 4). - 0; % 4x16 的 0/1 矩陣 ref_sym qam16_mod(ref_bits(:).); % 16 個理想星座點 plot(real(ref_sym), imag(ref_sym), ro, ... MarkerSize, 9, LineWidth, 1.2); axis equal; grid on; xlabel(同相分量 I); ylabel(正交分量 Q); title(ttl); enddec2bin(0:15, 4)生成 16 個 4 位二進制串轉(zhuǎn)置減0變成數(shù)值矩陣(:).拉成行向量喂給qam16_mod正好得到 16 個理想點。axis equal這一句不能省。不加的話 MATLAB 會按數(shù)據(jù)范圍自動拉伸坐標軸16 個點看起來是長方形的你會誤以為 I/Q 兩路增益不平衡。scatterplot(r)是工具箱里的替代方案一行就能畫出帶密度著色的星座圖做論文插圖挺好看。但它默認按接收符號的實際功率縮放跟手動畫的理想點對不上調(diào)試階段反而添亂。4. 結(jié)果怎么讀星座圖形態(tài)與 BER 曲線的四組對照4.1 星座圖的四種典型形態(tài)跑完之后看到的圖基本逃不出這四類每一種都對應(yīng)一個具體的代碼位置。第一類16 個點聚成 16 團中心落在±0.316、±0.949這些位置也就是3/sqrt(10)和1/sqrt(10)團的大小隨 SNR 變化。這是完全正常的形態(tài)說明歸一化和加噪都對。第二類16 個點聚得挺好但整體落在±1、±3上。這說明調(diào)制函數(shù)里的/sqrt(10)被刪了或者被注釋掉了。此時add_awgn仍然按Es 1算噪聲等效信噪比被抬高 10 dBBER 曲線會平移。第三類點云整體旋轉(zhuǎn)了一個角度比如 45 度或者一個小角度。45 度通常是星座點定義成了「偏移」形式點在±1±j上而不是±1, ±3上等價于換了一套映射小角度旋轉(zhuǎn)一般是加了相位噪聲或者載波頻偏但沒做補償。第四類SNR 很低時點云糊成一整片圓形看不出 16 個團。這是正常的Eb/N0 0 dB時噪聲標準差跟點間距差不多本來就分不開。這時候該看的是 BER 值在 0.14 附近而不是指望星座圖還有結(jié)構(gòu)。調(diào)參時的實用技巧把同一個sym_tx分別用 5 dB、10 dB、15 dB 加噪畫三張圖放一起一眼就能看出點云收縮的過程。這比盯著一堆數(shù)字有說服力。4.2 仿真點與理論線的貼合判據(jù)BER 曲線貼不貼別用眼睛「差不多」來判斷用數(shù)字。中高信噪比區(qū)間Eb/N0 ≥ 8 dB仿真點和理論值的相對誤差控制在 10% 以內(nèi)算是合格。比如理論值 1e-3 時仿真落在 0.9e-3 ~ 1.1e-3 都正常。低信噪比區(qū)間誤差會大一些因為理論式本身是近似加上誤碼率接近 0.5 時統(tǒng)計漲落小、反而穩(wěn)定。如果整條曲線平行偏移是常數(shù)增益問題回去查 2.3 的歸一化和N0/2如果曲線形狀不一樣比如低 SNR 貼得上、高 SNR 翹起來那是判決或映射的問題回去查lut的 Gray 順序和比特拼接順序。還有一個容易忽略的點Nsym 2e5時理論 BER 到 1e-5 就意味著平均只有 2 個錯誤比特統(tǒng)計漲落極大曲線會開始「抖」。我一般會要求每個 SNR 點至少累積 100 個錯誤不夠就自動加大Nsym重跑這比拍腦袋定一個固定值靠譜。4.3 換瑞利信道后曲線為什么「躺平」把 AWGN 換成瑞利衰落是這套腳本最常見的第一次改造。改動很小% 瑞利衰落信道 迫零均衡 h (randn(size(sym_tx)) 1j*randn(size(sym_tx))) / sqrt(2); % CN(0,1) r h .* sym_tx n; % 先過信道 r_eq r ./ h; % 迫零均衡, 把信道搬回去h除以sqrt(2)是為了讓復(fù)信道增益的平均功率為 1這樣Eb/N0的定義才不變。跑完會發(fā)現(xiàn)曲線在高 SNR 段變成一條斜率很緩的直線誤碼率下降得極慢。這不是代碼寫錯了是瑞利衰落的本質(zhì)深衰落發(fā)生時|h|接近 0r./h把噪聲放大了幾十倍這一批符號無論 SNR 多高都會錯。誤碼率曲線的斜率從「指數(shù)下降」變成「線性下降」分集階數(shù)只有 1。迫零均衡還有個數(shù)值陷阱h是復(fù)高斯隨機變量偶爾會采到極小值r./h直接產(chǎn)生一個巨大的數(shù)。實際腳本里通常會加一句保護h(abs(h) 1e-3) 1e-3 * exp(1j*angle(h(abs(h) 1e-3)));或者干脆改用 MMSE 均衡r_eq conj(h).*r ./ (abs(h).^2 N0)用噪聲方差兜底避免除零。4.4 用內(nèi)置 qammod 做交叉驗證自己寫的映射表對不對最省事的驗證方式是跟工具箱對一遍。bits_int bit2int(bits_tx(:), 4); % 每 4 比特轉(zhuǎn)成一個整數(shù) sym_ref qammod(bits_int, 16, InputType, integer, ... UnitAveragePower, true); err max(abs(sym_ref(:). - sym_tx));err應(yīng)該是 0 或者機器精度量級1e-16。如果不是說明lut的 Gray 順序跟工具箱不一致。注意工具箱的整數(shù)到星座點映射有自己的一套約定跟你的lut不一定要逐點相同但誤碼率性能應(yīng)該一致。所以更穩(wěn)妥的驗證是兩邊各自跑一遍完整鏈路看 BER 曲線是否重合。曲線重合但星座點位置不同說明只是映射約定不同不影響結(jié)論曲線不重合那就是有一邊的 Gray 性質(zhì)壞了。我一般在寫完自定義映射后都會做這一步三十秒的事能省掉后面幾個小時的懷疑人生。5. 避坑與排查曲線跑出來了但結(jié)論不對的 5 個現(xiàn)場5.1 仿真 BER 比理論好 3 dB 到 10 dB現(xiàn)象Eb/N0 10 dB時理論值 1.75e-3仿真跑出來 1e-4曲線整體左移。原因歸一化和噪聲方差兩處賬對不上。最常見的是發(fā)送符號沒除sqrt(10)少 10 dB或者復(fù)噪聲按sqrt(N0)生成而不是sqrt(N0/2)多 3 dB。解決在add_awgn里臨時插一句fprintf(Es%.3f, N0%.3e\n, mean(abs(sym).^2), N0);Es必須等于 1。不等就先修歸一化再談曲線。5.2 星座圖整體轉(zhuǎn)了 45 度現(xiàn)象16 個點不在±0.316 / ±0.949上而是落在±0.316±0.316j這種對角位置。原因映射表被改成了偏移形式或者用了qammod的默認配置默認不是UnitAveragePower也不是你手寫的那套 Gray 表兩套映射混用。解決確認lut是[-3 -1 3 1]且sym (I 1j*Q)/sqrt(10)這一行完整。若改用工具箱qammod和qamdemod必須成對使用同一套參數(shù)。5.3 低信噪比處 BER 卡在 0.3 左右下不去現(xiàn)象Eb/N0 0 dB附近 BER 是 0.3掃到 16 dB 掉到 0.25 就不動了。原因比特順序錯位。調(diào)制端按[b1 b2 b3 b4]分組解調(diào)端reshape時順序反了或者floor/mod的高低比特位搞反導(dǎo)致即使符號判決全對比特還是對不上。解決單獨測一次無噪聲回環(huán)——qam16_demod(qam16_mod(bits))應(yīng)該原樣返回bitsisequal為 true。這一條過不了后面全是白跑。5.4 高信噪比點直接從曲線上消失現(xiàn)象semilogy畫出來的仿真曲線在 14 dB 之后斷掉了沒有點。原因那一點的誤碼數(shù)是 0log(0)在 MATLAB 里是-Inf畫不出來。解決不是 bug是符號數(shù)不夠。要么加大Nsym要么在畫圖前把 0 替換成NaN讓曲線斷開而不是掉到 -Inf要么老老實實把 SNR 上限壓到能跑出 100 個錯誤的水平。我傾向于第三種因為硬湊出來的低誤碼率點沒有統(tǒng)計意義。5.5 換個 SNR 重跑結(jié)果每次都不一樣現(xiàn)象同樣參數(shù)跑兩遍Eb/N0 6 dB那點一次是 2.1e-2一次是 2.4e-2。原因沒有固定隨機種子randi本文還有配套的精品資源點擊獲取