現(xiàn))
簡介這是一份面向通信方向初學(xué)者與有一定開發(fā)經(jīng)驗(yàn)的工程師的Matlab源碼包用于計(jì)算QPSK調(diào)制下誤碼率隨信噪比變化的仿真運(yùn)行即可直接得到誤碼率-信噪比波形免去自行搭建仿真環(huán)境的麻煩。包內(nèi)共2個(gè)文件一個(gè).m腳本完整實(shí)現(xiàn)信號生成、加噪、解調(diào)與誤碼率統(tǒng)計(jì)代碼注釋詳盡方便逐行閱讀另一個(gè)docx文檔給出了算法補(bǔ)充說明可作為擴(kuò)展學(xué)習(xí)資料。壓縮包整體僅13KB輕量精簡尤其適合快速下載學(xué)習(xí)也可用于課程設(shè)計(jì)或畢業(yè)設(shè)計(jì)中的通信仿真部分。目前已有854人學(xué)習(xí)瀏覽經(jīng)過達(dá)摩老生親測校正質(zhì)量可靠值得信任。通過這份資源讀者既能獲得可直接運(yùn)行的QPSK誤碼率計(jì)算程序也能從注釋與文檔中理解仿真設(shè)計(jì)的完整思路掌握誤碼率性能分析方法減少自主摸索的時(shí)間成本。1. 拿到“matlab計(jì)算QPSK誤碼率隨信噪比變化的程序源碼”時(shí)先想清楚這三件事做QPSK誤碼率隨信噪比變化的仿真是通信方向?qū)W生和工程師繞不開的一道基礎(chǔ)題。你手里的這個(gè)matlab程序源碼目標(biāo)不外乎是畫出一條誤碼率曲線讓它從高誤碼區(qū)一路降到低誤碼區(qū)并且跟理論值貼在一起但它真正考你的是信噪比怎么在仿真里換算、噪聲怎么加、統(tǒng)計(jì)多少次才算數(shù)。它適合剛開題需要跑通通信仿真流程的在校學(xué)生也適合要做鏈路預(yù)算或評估編碼增益的射頻工程師。這篇筆記不假裝見過某個(gè)具體壓縮包的內(nèi)容而是把這一類程序背后最常見、最可靠的實(shí)現(xiàn)方案完整講透從調(diào)制映射到噪聲模型從主循環(huán)到避坑按你會實(shí)際動手的順序來。2. QPSK仿真為什么繞不開信噪比換算Eb/N0與SNR的差異與理論基礎(chǔ)2.1 QPSK調(diào)制與星座映射比特怎么變成I/Q兩路符號QPSK的全稱是Quadrature Phase Shift Keying一次傳輸兩個(gè)比特對應(yīng)四個(gè)相位狀態(tài)。最常見的星座圖是把四個(gè)點(diǎn)放在單位圓的四個(gè)象限上實(shí)部叫I路虛部叫Q路每一路的幅度都是±1/√2這樣每個(gè)符號的平均功率剛好是1。做仿真時(shí)第一步永遠(yuǎn)是把一串隨機(jī)的 0/1 比特流切成長度為 2 的塊再按映射表把每一塊變成一個(gè)復(fù)數(shù)符號。這個(gè)切分和映射過程看起來簡單但新手最容易在“比特順序”上翻車。matlab 里常見做法是先reshape成兩列再用bi2de把每一行轉(zhuǎn)成十進(jìn)制索引這里要特別注意left-msb和right-msb的選擇它決定 01 和 10 映射到哪個(gè)符號。我一般會用格雷映射也就是相鄰相位只差一個(gè)比特的映射因?yàn)樵诟咝旁氡认伦畛R姷腻e誤是誤判成相鄰符號格雷映射能讓這類錯誤盡量只引起一個(gè)比特錯誤實(shí)測誤碼率也更接近理論值。M 4; % QPSK 階數(shù) k log2(M); % 每符號比特?cái)?shù) 2 nBits 100000; % 總仿真比特?cái)?shù) data randi([0 1], nBits, 1); % 隨機(jī)二進(jìn)制信源 bitMatrix reshape(data, k, []); % 每行是一個(gè)兩比特組 symbolIdx bi2de(bitMatrix, left-msb); % 比特對 - 0~3 十進(jìn)制索引這里reshape把長度為nBits的列向量變成nBits/2行 2 列的矩陣每一行對應(yīng)一個(gè) QPSK 符號。bi2de(..., left-msb)表示左邊的比特是高位于是 00→0、01→1、10→2、11→3。選left-msb還是right-msb會影響星座圖上四點(diǎn)的順序但對后續(xù)誤碼率結(jié)果沒有本質(zhì)影響只要你發(fā)射和接收用同一套就行真正的坑在于后續(xù)de2bi轉(zhuǎn)回比特時(shí)也必須用同一個(gè)方向否則解調(diào)出來的比特流會完全錯亂曲線直接飄到天上。這一層還要注意不同的 matlab 版本對pskmod的默認(rèn)映射行為不完全一樣較新版本默認(rèn)走格雷映射老版本則可能是自然映射。如果你后續(xù)要用手寫判決而不是pskdemod就得保證自己的映射表和調(diào)制時(shí)用的完全一致否則會出現(xiàn)“星座點(diǎn)明明長得一模一樣誤碼率卻對不上理論曲線”的怪現(xiàn)象。這個(gè)細(xì)節(jié)在第四章我會專門展開。2.2 AWGN信道下的噪聲模型Eb/N0與SNR的換算公式誤碼率曲線的橫坐標(biāo)到底用 SNR 還是 Eb/N0是這一類源碼里分歧最大的地方。做通信的人習(xí)慣用 Eb/N0因?yàn)樗颜{(diào)制階數(shù)的影響剝離開來對比不同調(diào)制方式時(shí)更公平但 matlab 的awgn函數(shù)只接受功率比 SNR所以你必須自己完成換算。QPSK 里每個(gè)符號攜帶 2 個(gè)比特符號功率歸一化為 1 時(shí)每比特能量 Eb Es/k 1/2。于是SNR_linear EbN0_linear * k SNR_dB EbN0_dB 10*log10(k) EbN0_dB 3.0103這個(gè) 3dB 的偏移量是 QPSK 仿真的標(biāo)志性數(shù)字。如果你把 EbN0_dB 直接當(dāng)成awgn的 SNR 參數(shù)傳進(jìn)去實(shí)測誤碼率會比理論值偏大約 3dB——也就是曲線整體往左移看起來你“做出了更好的誤碼率曲線”實(shí)際上只是噪聲加少了。反過來如果有人拿 BPSKk1沒有這 3dB 偏移的代碼直接改成 QPSK不改換算就會得到完全錯誤的絕對信噪比指標(biāo)。判斷一段代碼是否靠譜第一眼就應(yīng)該看它有沒有做這個(gè)10*log10(k)的補(bǔ)償。EbN0_dB 6; % 目標(biāo)每比特信噪比 snr_dB EbN0_dB 10*log10(k); % 換算成符號信噪比 rxSig awgn(txSig, snr_dB, measured);awgn的第三個(gè)參數(shù)measured表示先實(shí)測信號功率再加噪聲這能避免因?yàn)V波器或歸一化殘留導(dǎo)致的功率誤差如果你的調(diào)制信號已經(jīng)嚴(yán)格歸一化也可以省略這個(gè)參數(shù)直接按默認(rèn)的 0dB 信號功率加噪。但要注意awgn的 SNR 定義是信號功率與噪聲功率之比不是信號幅度與噪聲幅度之比所以當(dāng)你手寫噪聲時(shí)每一維噪聲功率應(yīng)該是 N0/2而不是 N0。這個(gè)“2”是第四章第一個(gè)大坑的來源。2.3 理論誤碼率公式用erfc把Q函數(shù)落到matlab里有了星座映射和噪聲模型接下來需要一條理論曲線作為基準(zhǔn)。QPSK 在 AWGN 信道下、采用格雷映射時(shí)誤碼率理論值可以寫成BER 0.5 * erfc(sqrt(EbN0_lin))這里 EbN0_lin 是線性值不是 dB 值。很多人會把 dB 值直接代進(jìn)去算出來的理論曲線完全不對。注意這里用的是誤碼率 BER不是誤符號率 SERQPSK 的誤符號率理論值是erfc(sqrt(EbN0_lin))的高階修正形式約等于 BER 的兩倍。拿 SER 的理論值去對比仿真 BER曲線會始終高出一截怎么調(diào)噪聲模型都救不回來。EbN0_dB 0:8; EbN0_lin 10.^(EbN0_dB/10); ber_theory 0.5 * erfc(sqrt(EbN0_lin)); semilogy(EbN0_dB, ber_theory, k-, LineWidth, 1.5); hold on;matlab 里erfc是內(nèi)置函數(shù)不需要額外裝工具箱qfunc也存在于通信工具箱里兩者差一個(gè)系數(shù)qfunc(x) 0.5*erfc(x/sqrt(2))。理論上這兩條路寫出來的數(shù)值是一樣的但qfunc在部分老版本里對輸入?yún)?shù)的向量化處理有邊界限制我建議直接用erfc少一層環(huán)境依賴。上面這段代碼把 0 到 8dB 的理論曲線算出來了后面仿真的實(shí)測點(diǎn)如果要和它對比橫坐標(biāo)必須也是 EbN0而不是建模時(shí)的符號 SNR。這一節(jié)最后還要強(qiáng)調(diào)一個(gè)概念Eb/N0 和信噪比 SNR 不是一回事前者是每比特能量對噪聲功率譜密度的比后者是信號功率對噪聲功率的比。兩者之間差了10*log10(k)還差了采樣率相關(guān)的因子——如果你后面引入過采樣、匹配濾波或者升余弦脈沖成型SNR 表達(dá)式里還會多一項(xiàng)-10*log10(nSamp)。做基帶等效仿真的話我一般建議直接用 EbN0 作為主變量全程換算到符號 SNR 去加噪這樣理論曲線和實(shí)測點(diǎn)天然對齊。3. 在matlab里搭起QPSK誤碼率仿真的主循環(huán)信號生成、加噪、判決、統(tǒng)計(jì)3.1 用通信工具箱快速跑通第一版pskmod awgn 組合如果你機(jī)器上裝了 Communications Toolbox最快的一條路是用pskmod、awgn、pskdemod三個(gè)函數(shù)搭主循環(huán)。這個(gè)組合的好處是不用自己寫星座映射和最近鄰判決代碼短、出錯面窄特別適合先驗(yàn)證整體思路。第一版我一般寫成下面這樣clear; clc; M 4; k log2(M); nBits 5e5; % 不要一上來就跑到1e7先小規(guī)模驗(yàn)證 EbN0_dB 0:2:10; % 偶數(shù)格點(diǎn)先跑通再加密 ber_mc zeros(size(EbN0_dB)); for idx 1:length(EbN0_dB) data randi([0 1], nBits, 1); symIdx bi2de(reshape(data, k, []), left-msb); txSig pskmod(symIdx, M, pi/M, gray); % 格雷映射、相位偏移 pi/4 snr_dB EbN0_dB(idx) 10*log10(k); rxSig awgn(txSig, snr_dB, measured); rxSym pskdemod(rxSig, M, pi/M, gray); rxBits reshape(de2bi(rxSym(:), k, left-msb), [], 1); ber_mc(idx) mean(rxBits ~ data); end這一段里pskmod的第三個(gè)參數(shù)pi/M是相位偏移讓四個(gè)星座點(diǎn)位于 45°、135°、225°、315°這是 QPSK 教科書里最常見的畫法。第四個(gè)參數(shù)gray指定星座映射順序?yàn)楦窭子成洹e2bi(rxSym(:), k, left-msb)返回nSymbols行 2 列的矩陣轉(zhuǎn)置后按列reshape成 1D 比特流目的是把每個(gè)符號的兩位比特按順序排列回去。這行轉(zhuǎn)置加reshape的順序是所有腳本能否對齊的關(guān)鍵建議自己用很小的nBits比如 8單步調(diào)試確認(rèn)映射無誤。mean(rxBits ~ data)是誤碼率的樸素估計(jì)它默認(rèn)你的比特流沒有對齊延遲。如果實(shí)際系統(tǒng)中存在傳播延遲或?yàn)V波器群延遲你需要先做相關(guān)對齊再比較否則誤碼率會假性偏高但在基帶等效的單點(diǎn)仿真里發(fā)射和接收都是理想同步的所以這個(gè)簡單寫法沒問題。3.2 不用工具箱的手寫版映射、加噪、判決全流程很多工程機(jī)沒有通信工具箱或者你想徹底搞清楚每一步在算什么那就手寫整個(gè)鏈路。手寫版更能暴露對噪聲功率譜密度 N0 的理解是否到位我建議至少完整寫一遍即使最后跑通版本用的是工具箱函數(shù)。下面的代碼是完整的手寫版 QPSK 仿真clear; clc; M 4; k 2; constellation [11i, -11i, -1-1i, 1-1i] / sqrt(2); grayMap [0 1 3 2]; % 格雷映射: 00-0, 01-1, 11-3, 10-2 nBits 1e6; EbN0_dB 0:2:10; ber zeros(size(EbN0_dB)); for idx 1:length(EbN0_dB) EbN0_lin 10^(EbN0_dB(idx)/10); N0 1 / (k * EbN0_lin); % 歸一化條件下 Eb 1/k noiseVar N0 / 2; % 實(shí)部虛部各占一半噪聲功率 data randi([0 1], nBits, 1); symIdx bi2de(reshape(data, k, []), left-msb); txSig constellation(grayMap(symIdx1)).; noise sqrt(noiseVar) * (randn(size(txSig)) 1i*randn(size(txSig))); rxSig txSig noise; rxSym zeros(size(txSig)); for n 1:length(txSig) [~, minIdx] min(abs(rxSig(n) - constellation)); rxSym(n) grayMap(minIdx); % 映射回十進(jìn)制索引 end rxBits reshape(de2bi(rxSym(:), k, left-msb), [], 1); ber(idx) mean(rxBits ~ data); end這里的核心是噪聲功率計(jì)算。因?yàn)樾亲c(diǎn)歸一化到單位功率符號能量 Es1每比特能量 Eb Es/k 1/k于是 N0 Eb / EbN0_lin 1/(k·EbN0_lin)。高斯白噪聲在 I、Q 兩路各占一半功率所以每路噪聲方差是 N0/2幅度標(biāo)準(zhǔn)差是sqrt(N0/2)。randn(...) 1i*randn(...)產(chǎn)生復(fù)高斯噪聲實(shí)部虛部獨(dú)立同分布這正是 AWGN 的復(fù)基帶等價(jià)形式。很多手寫代碼忘記給實(shí)部虛部分別乘sqrt(0.5)結(jié)果總噪聲功率變成 N0 而不是 N0/2實(shí)測曲線會整體右移 3dB。判決部分用暴力最近鄰遍歷。constellation只有 4 個(gè)點(diǎn)這個(gè)循環(huán)開銷可以忽略但如果你后面擴(kuò)展到 16QAM 或 64QAM建議用knnsearch或者把星座點(diǎn)拆成實(shí)部虛部單獨(dú)判決否則循環(huán)會拖慢整個(gè)仿真。格雷映射在這里體現(xiàn)為grayMap(symIdx1)完成從索引到星座點(diǎn)的查表判決時(shí)又把最近的星座點(diǎn)通過grayMap(minIdx)映射回索引保證收發(fā)一致。grayMap的選擇會影響理論 BER 公式——只有格雷映射下0.5*erfc(sqrt(EbN0))才嚴(yán)格成立。3.3 把主循環(huán)包裝成腳本數(shù)據(jù)長度、信噪比范圍、隨機(jī)種子怎么定跑通單點(diǎn)仿真后要把它擴(kuò)展成一條完整的曲線就需要考慮三個(gè)全局參數(shù)仿真比特?cái)?shù)、信噪比范圍、是否固定隨機(jī)種子。固定隨機(jī)種子用rng(0)放在腳本開頭能讓每次運(yùn)行結(jié)果可復(fù)現(xiàn)——這個(gè)習(xí)慣在調(diào)參階段非常重要否則你每次看到的曲線都是新一批隨機(jī)數(shù)無法判斷改動是否有效。rng(0); % 固定隨機(jī)種子保證可復(fù)現(xiàn) EbN0_dB 0:1:12; % 加密橫坐標(biāo)但高信噪比區(qū)要加仿真量 nBitsMin 1e5; % 低信噪比區(qū)的基礎(chǔ)樣本數(shù) nBitsMax 2e7; % 高信噪比區(qū)的最大樣本數(shù) ber zeros(size(EbN0_dB)); for idx 1:length(EbN0_dB) if EbN0_dB(idx) 6 nBits nBitsMin; else nBits nBitsMax; end % ... 主仿真鏈路同 3.1 或 3.2復(fù)用同一份代碼... ber(idx) sum(errBits) / nBits; end逐點(diǎn)分配nBits的動機(jī)是誤碼率的統(tǒng)計(jì)精度。誤碼率的相對方差大約正比于1/sqrt(N_errors)在高信噪比區(qū)比如 10dB 以上誤碼率可能只有 1e-6如果還用 1e5 個(gè)比特整個(gè)仿真過程一個(gè)誤碼都碰不到曲線的尾部就會變成 0在 log 坐標(biāo)上直接掉出圖外。常見做法是先跑一遍粗曲線觀察誤碼率在哪個(gè) EbN0 區(qū)間低于 1e-4然后只對尾段增加樣本數(shù)。我自己的習(xí)慣是低信噪比區(qū)用 1e5每上升 2dB 提高一倍樣本量最多跑到 2e7 就打住——再往上不是不能跑而是單次仿真耗時(shí)會從秒級變成分鐘級且系統(tǒng)誤差比如awgn的measured估計(jì)誤差會開始主導(dǎo)加樣本的錢包邊際收益很低。主循環(huán)的寫法上for循環(huán)逐 dB 掃描最直觀也最容易加打印進(jìn)度。也可以用arrayfun或parfor并行化但 QPSK 單次仿真本身很快并行化的收益要到大規(guī)模蒙特卡洛掃描時(shí)才體現(xiàn)。我更建議先把串行版跑通再用parfor替換最外層的for作為優(yōu)化手段不要在調(diào)試階段引入并行。4. 常見避坑與排查誤碼率曲線不平滑、信噪比偏3dB、判決方向不一致4.1 加噪功率算錯實(shí)測BER與理論曲線差3dB怎么排查現(xiàn)象仿真出的誤碼率曲線形態(tài)和理論曲線完全一致斜率一樣但整體向左或向右平移約 3dB高信噪比區(qū)尤其明顯。原因幾乎總是噪聲功率多加了或少加了一半。用awgn時(shí)把 EbN0 直接傳進(jìn)去少了10*log10(k)的換算噪聲偏小曲線左移手寫噪聲時(shí)把 N0 當(dāng)成總方差而不是每維方差噪聲偏大曲線右移。排查辦法很簡單在固定 EbN06dB 處打印當(dāng)前理論的 BER 和實(shí)測 BER如果相差正好接近 3dB 對應(yīng)的數(shù)量級就先檢查換算式里的 k再檢查噪聲方差有沒有多乘 2。EbN0_test 6; EbN0_lin 10^(EbN0_test/10); ber_theory_test 0.5 * erfc(sqrt(EbN0_lin)); % 理論值約為 0.0024實(shí)測若明顯小于它大概率是噪聲加少了這個(gè) 3dB 偏移的隱蔽之處在于它不改變曲線的形狀只改變橫坐標(biāo)的偏移所以如果你只畫 semilogy 圖、不對照理論值肉眼很難發(fā)現(xiàn)。我見過不少人拿著一條“看起來很好”的曲線發(fā)到報(bào)告里結(jié)果評審老師一對照理論曲線就發(fā)現(xiàn)整體平移了。務(wù)必在圖上同時(shí)畫ber_theory和ber_mc并且兩者用同一橫坐標(biāo)變量才能暴露這類問題。4.2 高信噪比下誤碼數(shù)為0統(tǒng)計(jì)窗口不夠與曲線斷裂現(xiàn)象仿真曲線在 EbN0 超過某個(gè)點(diǎn)之后誤碼率變成 0semilogy 圖上曲線突然掉到圖外。這不是系統(tǒng)做了什么神奇優(yōu)化純粹是統(tǒng)計(jì)樣本不夠。在誤碼率 1e-5 以下想要測到一個(gè)誤碼平均需要 1e5 個(gè)比特如果誤碼率為 1e-6你還用 1e6 個(gè)比特那么“剛好一個(gè)誤碼都沒出現(xiàn)”的概率約等于 37%任何一次仿真都可能撞上。解決思路不是無腦加樣本而是設(shè)一個(gè)最小誤碼數(shù)目標(biāo)。targetErrors 100; % 至少統(tǒng)計(jì)到 100 個(gè)誤碼 while errTotal targetErrors % 繼續(xù)生成新一批數(shù)據(jù)累加誤碼數(shù)與總比特?cái)?shù) % 每批之間共用同一 EbN0 end ber_est errTotal / nBitsTotal;“等夠誤碼數(shù)再?!北取肮潭ㄅ芏嗌賯€(gè)比特”在統(tǒng)計(jì)上更穩(wěn)因?yàn)樗WC了相對估計(jì)誤差大致在 1/sqrt(100)10% 以內(nèi)。代價(jià)是仿真時(shí)間不可控所以在循環(huán)里要加最大迭代次數(shù)防止在誤碼率 1e-8 這種極端條件下跑到天荒地老。另一個(gè)折中方案是按誤碼率量級分級設(shè)nBits像我在 3.3 里寫的那樣大部分場景都夠用。還有一個(gè)和零誤碼同源的現(xiàn)象低信噪比區(qū) BER 曲線抖動大。原因是誤碼事件相關(guān)性較強(qiáng)尤其在比特級統(tǒng)計(jì)時(shí)誤碼往往成串出現(xiàn)。解決辦法可以是增大隨機(jī)種子重?cái)S次數(shù)把多次獨(dú)立仿真的誤碼數(shù)合并再算不要只跑一次就下結(jié)論。rng換不同種子跑 5 次取平均誤碼率曲線的光滑度會有明顯改善。4.3 接收端映射方向不一致星座點(diǎn)對了但全錯現(xiàn)象星座圖看起來四相位置完全正確解調(diào)的星座點(diǎn)與發(fā)射點(diǎn)重疊但逐比特對比時(shí)誤碼率高達(dá) 50%。原因是grayMap的使用在發(fā)射和接收兩端不對稱。比如發(fā)射端用pskmod(symIdx, M, pi/M, gray)接收端卻用pskdemod(rxSig, M, pi/M, gray)這兩個(gè)版本對同樣的復(fù)數(shù)信號解出的符號索引與你的de2bi解釋方式是否一致取決于 matlab 內(nèi)部映射表的方向。更常見的是手寫映射表時(shí)grayMap [0 1 3 2]與pskmod內(nèi)置的格雷順序不同導(dǎo)致某一象限的判決結(jié)果被映射錯。排查方法把發(fā)射的符號索引和接收判決的符號索引直接畫出來對比不要只比較最終的比特流。在nBits8的極小規(guī)模下打印symIdx和rxSym逐項(xiàng)核對。如果只有部分符號錯通常是某一列的比特位順序反了如果全部錯通常是映射表整體錯位。這里最穩(wěn)的寫法是收發(fā)共用同一個(gè)映射表常量不要在兩處分別定義。4.4 實(shí)部虛部交換一種只在復(fù)數(shù)信道上出現(xiàn)的隱蔽錯誤現(xiàn)象誤碼率曲線在高信噪比區(qū)域比理論高出大約一倍且不隨 EbN0 增加而趨于和理論重合而是始終保留一個(gè)固定的差距。原因發(fā)射時(shí)用txSig constellation(idx).如果寫成constellation(idx)而沒有轉(zhuǎn)置向量方向不對接收端判決時(shí)又恰好按行向量處理導(dǎo)致符號順序錯位。這種方向錯誤在低信噪比時(shí)被噪聲掩蓋誤碼率看起來還在理論附近一旦信噪比升高噪聲不再是主導(dǎo)因素系統(tǒng)性的符號錯亂就會顯露出來。% 錯誤寫法txSig 是行向量還是列向量會被后續(xù)加法廣播規(guī)則悄悄改變 txSig constellation(symIdx); % 可能變成行向量 noise sqrt(noiseVar) * randn(1, length(symIdx)); % 行噪聲 % 正確寫法統(tǒng)一為列向量 txSig constellation(symIdx).; noise sqrt(noiseVar) * (randn(length(symIdx), 1) 1i*randn(length(symIdx), 1));這類問題用size()逐一檢查就能發(fā)現(xiàn)但新手往往只盯著誤碼率數(shù)字忽略了中間變量的維度。我建議在每步操作后加一行assert(size(txSig,1) size(noise,1))讓維度錯誤在第一時(shí)間爆出來而不是等你對著曲線猜半天。這一條算是血淚經(jīng)驗(yàn)matlab 的隱式擴(kuò)展讓很多形狀問題被掩蓋等到最終結(jié)果異常時(shí)排查成本遠(yuǎn)高于一開始的防御性檢查。5. 用三條驗(yàn)證線路確認(rèn)仿真沒白跑從單點(diǎn)數(shù)值到整條曲線擬合5.1 先驗(yàn)單點(diǎn)再驗(yàn)曲線最后驗(yàn)斜率很多同學(xué)把仿真代碼一跑完看到一條下降的曲線就直接截圖放到報(bào)告里。這個(gè)習(xí)慣隱患很大因?yàn)檎`碼率曲線只要大方向?qū)α思?xì)節(jié)錯誤很難看出來。我給自己的驗(yàn)證流程是三層第一層選一個(gè)中等信噪比點(diǎn)比如 EbN06dB把理論 BER 算出來實(shí)測值在它上下 20% 以內(nèi)才算通過第二層把 0dB 到 4dB 區(qū)間內(nèi)的實(shí)測曲線和理論曲線畫在同一張圖上允許的偏差是每點(diǎn)都在同一數(shù)量級第三層檢查曲線斜率高信噪比區(qū)每增加 1dB誤碼率應(yīng)顯著下降如果某一段變成平緩甚至回升說明有系統(tǒng)錯誤或仿真點(diǎn)數(shù)不夠。EbN0_check 6; ber_theory_check 0.5 * erfc(sqrt(10^(EbN0_check/10))); ber_mc_check ber(EbN0_dB EbN0_check); fprintf(theory %.4e, simulated %.4e\n, ber_theory_check, ber_mc_check);這層驗(yàn)證本質(zhì)上是在檢驗(yàn)“理論模型”與“仿真模型”的邊界條件是否一致。理論公式假定理想同步、無定時(shí)誤差、AWGN 信道如果你的仿真里加入成型濾波、載波同步或多徑信道理論曲線就不再適用這時(shí)候?qū)Ρ葘ο笠獡Q成更接近實(shí)際系統(tǒng)的鏈路級模型。對于沒有工具箱的純手寫仿真我建議至少保留理論曲線作為 sanity check不要直接拿別人的鏈路預(yù)算當(dāng)基準(zhǔn)。5.2 參數(shù)調(diào)優(yōu)仿真點(diǎn)數(shù)、信噪比步長、重復(fù)次數(shù)怎么取舍做蒙特卡洛 BER 仿真本質(zhì)是用計(jì)算時(shí)間換統(tǒng)計(jì)精度。下面這張參數(shù)表是我跑 QPSK 時(shí)常用的起點(diǎn)按信號處理鏈路復(fù)雜度和機(jī)器性能調(diào)整參數(shù)低配起點(diǎn)標(biāo)準(zhǔn)配置說明每點(diǎn)仿真比特?cái)?shù)1e51e6高信噪比區(qū)至少 1e7EbN0 范圍0:2:120:1:14步長 1dB 夠畫曲線0.5dB 用于精細(xì)對比隨機(jī)種子rng(0)rng(0) 5 次重復(fù)重復(fù)次數(shù)多用于低信噪比區(qū)平滑目標(biāo)最小誤碼數(shù)50100保證相對誤差低于 10%信噪比步長從 2dB 細(xì)化到 1dB會直接影響高信噪比區(qū)的曲率表現(xiàn)但代價(jià)是總點(diǎn)數(shù)翻倍。如果不確定某個(gè)區(qū)間是否需要加密可以先跑 2dB 粗曲線找到曲線拐點(diǎn)通常是誤碼率從 1e-2 到 1e-5 那段再單獨(dú)加密這個(gè)區(qū)間。樣本數(shù)的分配上一個(gè)容易被忽略的點(diǎn)是EbN00dB 附近 BER 約 0.08用 1e5 個(gè)比特測試能得到約 8000 個(gè)誤碼統(tǒng)計(jì)已經(jīng)很穩(wěn)而 EbN010dB 附近 BER 約 4e-6需要 2.5e7 個(gè)比特才能得到 100 個(gè)誤碼。所以把大部分計(jì)算預(yù)算投給高信噪比區(qū)永遠(yuǎn)是合算的。5.3 圖上驗(yàn)證semilogy坐標(biāo)系下的視覺檢查清單仿真結(jié)果的呈現(xiàn)方式也會影響排查效率。誤碼率曲線必須用semilogy或loglog在線性坐標(biāo)下 1e-2 和 1e-5 看起來幾乎都是零無法判斷趨勢。畫圖時(shí)把理論曲線畫成實(shí)線黑線仿真點(diǎn)在圖上用圓圈標(biāo)出不要用點(diǎn)線連接起來——仿真點(diǎn)是樣本估計(jì)不是連續(xù)函數(shù)用虛線連反而會誤導(dǎo)觀察。檢查時(shí)重點(diǎn)看三處曲線末端是否出現(xiàn)平臺期、曲線是否與理論曲線交叉、低信噪比區(qū)是否出現(xiàn)系統(tǒng)性偏移。出現(xiàn)平臺期是零誤碼交叉意味著某個(gè)區(qū)段內(nèi)模型偏差方向反轉(zhuǎn)常見于映射錯亂或殘余符號間干擾系統(tǒng)性偏移則幾乎總是功率換算問題。semilogy(EbN0_dB, ber_theory, k-, LineWidth, 1.5); hold on; semilogy(EbN0_dB, ber_mc, b-o, MarkerSize, 6); grid on; xlabel(Eb/N0 (dB)); ylabel(BER); legend(Theory, Simulation, Location, southwest);圖本身也是最早能暴露問題的地方如果你的實(shí)測點(diǎn)在 0 到 4dB 區(qū)間比理論點(diǎn)低很多誤碼率更小第一反應(yīng)不應(yīng)該是高興而是幾乎可以斷定噪聲少加了——這是一個(gè)“看起來太好”恰是錯誤信號的高頻場景。反過來實(shí)測明顯差于理論則先檢查接收判決方向、噪聲方差、以及比特流對齊這三大元兇。6. 從“能跑”到“能復(fù)用”把QPSK腳本改造成參數(shù)化仿真函數(shù)驗(yàn)證通過之后下一步是把散亂的腳本改造成一個(gè)參數(shù)化函數(shù)讓它的輸入是調(diào)制階數(shù)、EbN0范圍、目標(biāo)誤碼數(shù)輸出是 BER 向量和耗時(shí)信息。這樣同一套代碼可以復(fù)用于 BPSK、16QAM甚至以后擴(kuò)展 OFDM 子載波仿真。function [ber, EbN0_dB] simulateBER(M, EbN0_dB, doPlot) if nargin 3, doPlot false; end k log2(M); % 星座點(diǎn)和格雷映射表可按 M 生成這里只列 QPSK constellation [11i, -11i, -1-1i, 1-1i] / sqrt(2); grayMap [0 1 3 2]; ber zeros(size(EbN0_dB)); for idx 1:length(EbN0_dB) % 內(nèi)部復(fù)用 3.2 的加噪、判決鏈路 end if doPlot semilogy(EbN0_dB, 0.5*erfc(sqrt(10.^(EbN0_dB/10))), k-); hold on; semilogy(EbN0_dB, ber, b-o); end end函數(shù)化的好處不只是代碼整潔更重要的是把“調(diào)制方式選擇”“噪聲模型”“判決規(guī)則”這三個(gè)變點(diǎn)隔離出來以后換方案時(shí)只需要改星座生成和映射表。我自己最早的 QPSK 腳本就是滿屏全局變量的面條代碼后來在對比 16QAM 時(shí)吃了大虧——改動一個(gè)參數(shù)結(jié)果完全亂了。從那以后我養(yǎng)成的習(xí)慣是任何要跑超過三天的仿真腳本第一天就寫成函數(shù)哪怕參數(shù)少也要讓每個(gè)輸入變量的含義明確。如果你以后要在這個(gè)基礎(chǔ)上做信道編碼對比、加卷積碼或 LDPC還可以把simulateBER里的加噪和判決部分單獨(dú)抽成channelModel和demodulator兩個(gè)子函數(shù)這樣誤碼率統(tǒng)計(jì)邏輯與具體調(diào)制方案解耦?;仡^看QPSK 誤碼率仿真永遠(yuǎn)是通信鏈路仿真里最透明、最不容易出錯的模塊但恰恰因?yàn)楹唵魏芏嗳撕雎粤讼到y(tǒng)化驗(yàn)證。從固定隨機(jī)種子開始到逐點(diǎn)核對樣本量再到最后曲線與理論的吻合每一步都能篩出幾類不同的問題。希望這份操作路徑能幫你少走幾趟彎路也希望你那版源碼跑出來的第一條曲線就是一條跟理論貼得漂亮、可信度經(jīng)得起追問的曲線。本文還有配套的精品資源點(diǎn)擊獲取