f10@t's blog

MATLAB - Wireless Communication Onramp

字数统计: 2.6k阅读时长: 10 min
2022/01/20

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

  1. 单理想通道&噪声通道通信模拟
  2. 多径理想&噪声模拟,OFDM机制模拟

(ps:之前一直认为Matlab没啥用&&没好好学的我对不起对不起对不起。

模拟基本数字通信链路

模拟发送方和接收方

要模拟的过程如上图所示,这里使用16-QAM进行调制和解调,如下是代码和步骤。

首先第一步我们需要一个信源,即产生信号的源,这里即是由一系列的0,1比特串组成,在matlab中其实就是一个向量。所以我们可以使用randi函数来实现该功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
% 创建一个信源,使用randi %
srcBits = randi([0, 1], 20000, 1);
% 使用16-QAM进行调制和解调 %
modOrder = 16;
modOut = qammod(srcBits, modOrder, "InputType", "bit");
% 查看星座图 %
scatterplot(modOut);

% 这里的信道假设是理想信道 %
chanOut = modOut;

% 解调 %
demodOut = qamdemod(chanOut, modOrder, "OutputType", "bit");
% 检查 %
check = isequal(srcBits, demodOut);

我们可以得到下面的理想的星座图:

image-20220120110708105

这是最理想的星座图,各个点之间的间隔越大,他们的性能越好。最终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
% 创建一个信源,使用randi %
srcBits = randi([0, 1], 20000, 1);
% 使用16-QAM进行调制和解调 %
modOrder = 16;
modOut = qammod(srcBits, modOrder, "InputType", "bit", ...
"UnitAveragePower", true);
% 查看星座图 %
scatterplot(modOut);
title("Without Noise")

% 加性高斯白噪声 %
SNR = 15; % dB
chanOut = awgn(modOut, SNR);
% 查看星座图 %
scatterplot(chanOut);
title("AWGN")

% 解调 %
demodOut = qamdemod(chanOut, modOrder, "OutputType", "bit", ...
"UnitAveragePower", true);
% 检查 %
check = isequal(srcBits, demodOut);

此时我们再对比一下,噪声的影响就出来了。只有在原来理想(ideal)位置(左图位置)上的点才会被解调为正常的比特,而不在理想位置上、发生了偏移的点则就会发生解调错误。

image-20220120112520154

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

image-20220120113335035

当然看星座图是一种方法了,我们接下来量化一下,使用比特错误率(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
% 创建一个信源,使用randi %
numBits = 20000;
srcBits = randi([0, 1], numBits, 1);
% 使用16-QAM进行调制和解调 %
modOrder = 16;
modOut = qammod(srcBits, modOrder, "InputType", "bit", ...
"UnitAveragePower", true);
% 查看星座图 %
scatterplot(modOut);
title("Without Noise")

% 加性高斯白噪声 %
SNR = 15; % dB
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.RaisedCosineTransmitFiltercomm.RaisedCosineReceiveFilter,然后我们对比一下加了过滤器后的误码率。代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
% 创建一个信源,使用randi %
numBits = 20000;
srcBits = randi([0, 1], numBits, 1);
% 使用16-QAM进行调制和解调 %
modOrder = 16;
modOut = qammod(srcBits, modOrder, "InputType", "bit", ...
"UnitAveragePower", true);
% 添加升余弦过滤器 %
txFilt = comm.RaisedCosineTransmitFilter;
% 通过过滤器 %
txFiltOut = txFilt(modOut);

% 加性高斯白噪声 注意,这里降低了SNR%
SNR = 7; % db
% measured 代表根据SNR缩放噪声功率
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)

结果如下:

image-20220120141841020

其中黄色的部分是没有通过噪声通道前的样子,蓝色是通过噪声通道后的样子,

由于滤波器是存在延迟的,其长度为滤波器的一半,其单位为符号,所以在计算误码率之前,我们需要对原始的数据和解调前的数据进行对齐,在上面添加如下具体代码:

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
% 创建一个信源,使用randi %
numBits = 20000;
srcBits = randi([0, 1], numBits, 1);
% 使用16-QAM进行调制和解调 %
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];

% stem 可以查看 %
% stem(mpChan) %

% apply the filter to signal %
mpChanOut = filter(mpChan, 1, txFiltOut);

% BER %
if exist("mpChanOut","var")
SNR = 15; % dB
chanOut = awgn(mpChanOut,SNR,"measured");

rxFiltOut = rxFilt(chanOut);
scatterplot(rxFiltOut)
title("Receive Filter Output")
demodOut = qamdemod(rxFiltOut,modOrder,"OutputType","bit", ...
"UnitAveragePower",true);

% Calculate the BER
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

image-20220122135303062

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

image-20220122135829367

其中蓝色代表多径通道的输出,黄色是调制后的输出,可以从结果看到,多径通道输出后中间有明显的凹陷,扭曲了原信号的波形,这是因为频率选择性多径(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
% 16-QAM
modOrder = 16;
bitsPerSymbol = log2(modOrder);

% multipath channel
mpChan = [0.8; zeros(7,1); -0.5; zeros(7,1); 0.34];
SNR = 15;

% number of subcarriers
numCarr = 8192;
numBits = numCarr * bitsPerSymbol;
srcBits = randi([0,1],numBits,1);
qamModOut = qammod(srcBits,modOrder,"InputType","bit",...
"UnitAveragePower",true);

% 设定前缀长度
cycPrefLen = 32;
% OFDM调制
ofdmModOut = ofdmmod(qamModOut, numCarr, cycPrefLen);

% 多路径+AWGN
mpChanOut = filter(mpChan,1,ofdmModOut);
chanOut = awgn(mpChanOut,SNR,"measured");

% OFDM解调
ofdmDemodOut = ofdmdemod(chanOut, numCarr, cycPrefLen);

% 均衡器
mpChanFreq = fftshift(fft(mpChan, numCarr));
eqOut = ofdmDemodOut ./ mpChanFreq;
scatterplot(eqOut);

% 16-QAM解码
qamDemodOut = qamdemod(eqOut,modOrder,"OutputType","bit",...
"UnitAveragePower",true);

% 计算BER
numBitErrors = nnz(srcBits~=qamDemodOut);
BER = numBitErrors/numBits;

image-20220122160032483

从实验结果来看,使用了OFDM技术的情况下,多径效应的影响被大大减弱了。

添加防护带

为了防止信号之间的相互干扰,在实际的OFDM系统中往往需要防护带的设计(如下图所示),同时去除直流部分以便在没有直流的信号上使用。上述操作同样可以使用ofdmmod函数完成

33 OFDM subcarriers. Left four and right four subcarriers are guard bands, center subcarrier is null DC.

代码如下:

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
% 16-QAM
modOrder = 16;
bitsPerSymbol = log2(modOrder);
% multipath channel
mpChan = [0.8; zeros(7,1); -0.5; zeros(7,1); 0.34];
SNR = 15;
% number of subcarriers
numCarr = 8192;
% cycPrefLen
cycPrefLen = 32;

% indices of left and right band Guard
numGBCarr = numCarr/16;
leftBg = 1:numGBCarr;
rightBg = (numCarr - numGBCarr + 1):numCarr;
dcIdx = numCarr/2 + 1;
nullIdx = [leftBg dcIdx rightBg]';

% data carries
numDataCarr = numCarr - length(nullIdx);
numDataBits = numDataCarr * bitsPerSymbol;

% 生成源数据
srcBits = randi([0,1], numDataBits, 1);
% 16-QAM编码
qamModOut = qammod(srcBits, modOrder, "InputType", "bit",...
"UnitAveragePower", true);

% ofdm编码
ofdmModOut = ofdmmod(qamModOut, numCarr, cycPrefLen, nullIdx);

% 通过AWGN的多径通道
mpChanOut = filter(mpChan,1,ofdmModOut);
chanOut = awgn(mpChanOut,SNR,"measured");

% ofdm解调
ofdmDemodOut = ofdmdemod(chanOut, numCarr, cycPrefLen, cycPrefLen, nullIdx);
% 均衡信号
mpChanFreq = fftshift(fft(mpChan, numCarr));
mpChanFreq(nullIdx) = [];
eqOut = ofdmDemodOut ./ mpChanFreq;
scatterplot(eqOut);

% 16-QAM解码
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)

image-20220122215533105

image-20220122215549567

CATALOG
  1. 1. 模拟基本数字通信链路
    1. 1.1. 模拟发送方和接收方
    2. 1.2. 模拟加性高斯白噪声通道
    3. 1.3. 计算误比特率
    4. 1.4. 模拟滤波器
  2. 2. 模拟多径通信链路
    1. 2.1. 基本建模以及问题
    2. 2.2. 引入OFDM
    3. 2.3. 添加防护带