失踪人口回归嘿嘿。最近出于实验需求,学习一下如何使用Matlab来模拟无线通信环境,包括通过添加噪声、过滤器等来模拟真实物理世界状态,旨在测试信道的误比特率。包括单链路和多链路的模拟。记录的内容主要来自官网MathWork上的在线免费课程。包括:
- 单理想通道&噪声通道通信模拟
- 多径理想&噪声模拟,OFDM机制模拟
(ps:之前一直认为Matlab没啥用&&没好好学的我对不起对不起对不起。

模拟基本数字通信链路
模拟发送方和接收方

要模拟的过程如上图所示,这里使用16-QAM进行调制和解调,如下是代码和步骤。
首先第一步我们需要一个信源,即产生信号的源,这里即是由一系列的0,1比特串组成,在matlab中其实就是一个向量。所以我们可以使用randi
函数来实现该功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| srcBits = randi([0, 1], 20000, 1);
modOrder = 16; modOut = qammod(srcBits, modOrder, "InputType", "bit");
scatterplot(modOut);
chanOut = modOut;
demodOut = qamdemod(chanOut, modOrder, "OutputType", "bit");
check = isequal(srcBits, demodOut);
|
我们可以得到下面的理想的星座图:

这是最理想的星座图,各个点之间的间隔越大,他们的性能越好。最终check
变量的值也是1,这是因为我们的通道是无噪声的理想通道,现实中肯定不是这样的了。
模拟加性高斯白噪声通道
所以下来我们将通道改为包含了加性高斯白噪声(additive White
Gauss Noise, AWGN)的环境,如下图所示:

我们修改一下代码,设置信号平均功率(Average Power)为1,
并对调制的结果添加高斯白噪声,最终我们看一下两个图的对比。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| srcBits = randi([0, 1], 20000, 1);
modOrder = 16; modOut = qammod(srcBits, modOrder, "InputType", "bit", ... "UnitAveragePower", true);
scatterplot(modOut); title("Without Noise")
SNR = 15; chanOut = awgn(modOut, SNR);
scatterplot(chanOut); title("AWGN")
demodOut = qamdemod(chanOut, modOrder, "OutputType", "bit", ... "UnitAveragePower", true);
check = isequal(srcBits, demodOut);
|
此时我们再对比一下,噪声的影响就出来了。只有在原来理想(ideal)位置(左图位置)上的点才会被解调为正常的比特,而不在理想位置上、发生了偏移的点则就会发生解调错误。

当然,我们可以提高信噪比,来看看效果,下图是SNR分别为30、60、100的结果,可以看到结果是越来越好了。

当然看星座图是一种方法了,我们接下来量化一下,使用比特错误率(Bit
Error Rate, BER)来衡量。
计算误比特率
计算方法很简单,我们只需要使用错误的比特数量除以总比特数就可以了,我们使用~=
符号来获得一个向量,其中1代表运算的两个对象包含的元素不相同,0代表相同,故srcBits ~= demodOut
就可以将错误的比特标记为1,然后我们使用nnz
即non-zero函数来对这些标记进行Counting,最后做比值就可以了。代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| numBits = 20000; srcBits = randi([0, 1], numBits, 1);
modOrder = 16; modOut = qammod(srcBits, modOrder, "InputType", "bit", ... "UnitAveragePower", true);
scatterplot(modOut); title("Without Noise")
SNR = 15; chanOut = awgn(modOut, SNR);
scatterplot(chanOut); title("AWGN")
demodOut = qamdemod(chanOut, modOrder, "OutputType", "bit", ... "UnitAveragePower", true);
numErrorBits = nnz(srcBits ~= demodOut); BER = numErrorBits / numBits;
|
模拟滤波器
为了降低上述出现的误比特率,我们将使用滤波器(filter),加上滤波器的发送方和接收方如下所示,通常上这一对过滤器是匹配使用的。下面实验我们使用一个平方根升余弦过滤器函数来实现功能,具体函数为comm.RaisedCosineTransmitFilter
和comm.RaisedCosineReceiveFilter
,然后我们对比一下加了过滤器后的误码率。代码如下。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| numBits = 20000; srcBits = randi([0, 1], numBits, 1);
modOrder = 16; modOut = qammod(srcBits, modOrder, "InputType", "bit", ... "UnitAveragePower", true);
txFilt = comm.RaisedCosineTransmitFilter;
txFiltOut = txFilt(modOut);
SNR = 7;
chanOut = awgn(txFiltOut, SNR, "measured");
rxFilt = comm.RaisedCosineReceiveFilter;
rxFiltOut = rxFilt(chanOut);
|
我们可以通过功率谱来分析一下通过滤波器后,没有经过噪声通道和经过噪声通道的频谱图,首先我们通过dsp.SpectrumAnalyzer
函数新创建一个频谱分析对象,然后进行分析,在上述代码后面添加如下代码即可:
1 2 3 4
| specAn = dsp.SpectrumAnalyzer(... "NumInputPorts",2, ... "SpectralAverages",50); specAn(txFiltOut,chanOut)
|
结果如下:

其中黄色的部分是没有通过噪声通道前的样子,蓝色是通过噪声通道后的样子,
由于滤波器是存在延迟的,其长度为滤波器的一半,其单位为符号,所以在计算误码率之前,我们需要对原始的数据和解调前的数据进行对齐,在上面添加如下具体代码:
1 2 3 4 5 6
| delayInSymbols = rxFilt.FilterSpanInSymbols/2 + txFilt.FilterSpanInSymbols/2 delayInBits = delayInSymbols * bitsPerSymbol srcAligned = srcBits(1:(end-delayInBits)) demodAligned = demodOut((delayInBits+1):end) numBitErrors = nnz(srcAligned ~= demodAligned) BER = numBitErrors / length(srcAligned)
|
从我自己多次的运行结果来看,在和上一节中SNR=15
对比,这里虽然将SNR降低到了7,但是其误码率反而要比上一节的实验结果将近小了2至倍,这说明滤波器在对抗噪声方面的作用是显著的。
模拟多径通信链路
无线通信如LTE、5G、Wifi本身就是在开放式的环境中以广播的形式进行传输,故为了更好的模拟无线通信环境,我们需要对多径通信链路进行仿真实验。
基本建模以及问题
下面将模拟一个发送方和接收方都是静态情况(不移动)下的多径通信链路,如下图所示:

首先我们使用一个有限脉冲响应过滤器(finite impulse response(FIR)
filter)来代表多路径,通常上是有一个由系数组成的向量:b = [b0 b1 b2 ... bn]
,我们可以认为每一个元素为一个路径,每一个非0系数代表延迟。下面的代码中我们用变量mpChan
来模拟一个多径。依旧采用单数据源发送数据,前面的数据生成过程和最后的BER计算方法和上一节相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| numBits = 20000; srcBits = randi([0, 1], numBits, 1);
modOrder = 16; bitsPerSymbol = log2(modOrder); modOut = qammod(srcBits, modOrder, "InputType", "bit", ... "UnitAveragePower", true);
txFilt = comm.RaisedCosineTransmitFilter; rxFilt = comm.RaisedCosineReceiveFilter;
txFiltOut = txFilt(modOut);
spacing = zeros(7, 1);
mpChan = [0.8; spacing; -0.5; spacing; 0.34];
mpChanOut = filter(mpChan, 1, txFiltOut);
if exist("mpChanOut","var") SNR = 15; chanOut = awgn(mpChanOut,SNR,"measured"); rxFiltOut = rxFilt(chanOut); scatterplot(rxFiltOut) title("Receive Filter Output") demodOut = qamdemod(rxFiltOut,modOrder,"OutputType","bit", ... "UnitAveragePower",true); delayInSymbols = txFilt.FilterSpanInSymbols/2 + ... rxFilt.FilterSpanInSymbols/2; delayInBits = delayInSymbols * bitsPerSymbol; srcAligned = srcBits(1:(end-delayInBits)); demodAligned = demodOut((delayInBits+1):end);
numBitErrors = nnz(srcAligned~=demodAligned); BER = numBitErrors/length(srcAligned); end
|

从实验结果来看,在SNR为15的情况下,误比特率高达20%以上,从星座图来看显然几乎是不可用的传输方案,下面是频谱图:

其中蓝色代表多径通道的输出,黄色是调制后的输出,可以从结果看到,多径通道输出后中间有明显的凹陷,扭曲了原信号的波形,这是因为频率选择性多径(frequency-selective
multipath)导致信道衰减或增益的水平取决于频率。针对这个问题,在wifi、5G、LTE中,我们使用正交频分多路复用技术(orthogonal
frequency-division multiplexing,
OFDM)来解决。所以我们下来模拟该技术。
引入OFDM

这里不展开说具体原理,这里直接使用Matlab的OFDM的实现函数就可以了。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| modOrder = 16; bitsPerSymbol = log2(modOrder);
mpChan = [0.8; zeros(7,1); -0.5; zeros(7,1); 0.34]; SNR = 15;
numCarr = 8192; numBits = numCarr * bitsPerSymbol; srcBits = randi([0,1],numBits,1); qamModOut = qammod(srcBits,modOrder,"InputType","bit",... "UnitAveragePower",true);
cycPrefLen = 32;
ofdmModOut = ofdmmod(qamModOut, numCarr, cycPrefLen);
mpChanOut = filter(mpChan,1,ofdmModOut); chanOut = awgn(mpChanOut,SNR,"measured");
ofdmDemodOut = ofdmdemod(chanOut, numCarr, cycPrefLen);
mpChanFreq = fftshift(fft(mpChan, numCarr)); eqOut = ofdmDemodOut ./ mpChanFreq; scatterplot(eqOut);
qamDemodOut = qamdemod(eqOut,modOrder,"OutputType","bit",... "UnitAveragePower",true);
numBitErrors = nnz(srcBits~=qamDemodOut); BER = numBitErrors/numBits;
|

从实验结果来看,使用了OFDM技术的情况下,多径效应的影响被大大减弱了。
添加防护带
为了防止信号之间的相互干扰,在实际的OFDM系统中往往需要防护带的设计(如下图所示),同时去除直流部分以便在没有直流的信号上使用。上述操作同样可以使用ofdmmod
函数完成

代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| modOrder = 16; bitsPerSymbol = log2(modOrder);
mpChan = [0.8; zeros(7,1); -0.5; zeros(7,1); 0.34]; SNR = 15;
numCarr = 8192;
cycPrefLen = 32;
numGBCarr = numCarr/16; leftBg = 1:numGBCarr; rightBg = (numCarr - numGBCarr + 1):numCarr; dcIdx = numCarr/2 + 1; nullIdx = [leftBg dcIdx rightBg]';
numDataCarr = numCarr - length(nullIdx); numDataBits = numDataCarr * bitsPerSymbol;
srcBits = randi([0,1], numDataBits, 1);
qamModOut = qammod(srcBits, modOrder, "InputType", "bit",... "UnitAveragePower", true);
ofdmModOut = ofdmmod(qamModOut, numCarr, cycPrefLen, nullIdx);
mpChanOut = filter(mpChan,1,ofdmModOut); chanOut = awgn(mpChanOut,SNR,"measured");
ofdmDemodOut = ofdmdemod(chanOut, numCarr, cycPrefLen, cycPrefLen, nullIdx);
mpChanFreq = fftshift(fft(mpChan, numCarr)); mpChanFreq(nullIdx) = []; eqOut = ofdmDemodOut ./ mpChanFreq; scatterplot(eqOut);
qamDemodOut = qamdemod(eqOut, modOrder, "OutputType", "bit",... "UnitAveragePower", true);
numBitErrors = nnz(srcBits~=qamDemodOut); BER = numBitErrors/numDataBits;
specAn = dsp.SpectrumAnalyzer("NumInputPorts",2,"SpectralAverages",50); specAn(ofdmModOut,chanOut)
|

