[noway]建议不要直接抄[/noway]

系统实现流程图

image-20220925153202844

子函数

1. 信源序列生成子函数

输入:M为码元位数,N为符号长度。

输出:1行,N列的取值范围为[0,7]的矩阵。

方法:利用randi([0, 2^M-1], 1, N)函数产生1行,N列的取值范围为[0,7]的矩阵。

1
2
3
4
5
function sourse_signal = generate_Source(M, N)
% 产生一个1*length的随机矩阵,元素取值均匀分布在[0,1]
% source_signal用来存储Mbit码元信号
sourse_signal = randi([02^M-1], 1, N);
end

2. Mbit格雷码表子函数

输入:M为码元位数。

输出:Mbit 的格雷码对照表(M行,2^M列的0,1矩阵)。

方法:对[1,2^M]进行遍历:通过dec2bin()、double()和boolean()函数将十进制数转为二进制数,再通过二进制数转格雷码规律将自然二进制数转为格雷码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function gray_table = Gray_Table(M)
gray_table = zeros(M, 2^M);
for i = 1 : 2^M
    % 十进制转二进制
    bin_str = dec2bin(i-1, M);   %将十进制数据转为字符
    bin_num = double(boolean(bin_str-'0')); %将字符转成逻辑量,强制转为double型
    % 格雷编码
    for j = 1 : M
        if j == 1
            gray_table(ji) = bin_num(j);
        else
            gray_table(ji) = xor(bin_num(j-1), bin_num(j));
        end
    end
end
end

3. 信源符号序列格雷编码子函数

输入:source_signal为产生的信源符号序列,M为码元位数,N为符号长度。

输出:M行,N列的0,1矩阵。

方法:通过自己编写好的的Mbit 格雷码表生成函数Gray_Table(M)生成格雷码表,将序列的符号值+1作为索引,得到符号对应的格雷码。

1
2
3
4
5
6
7
8
9
function gray_signal = code_Gray(source_signal, M, N)
gray_signal = zeros(M, N);
%% 预设M bits 格雷码表
gray_table = Gray_Table(M);
%% 根据格雷码表编码
for i = 1 : N
    gray_signal(:,i) = gray_table(:,source_signal(i)+1);
end
end

4. 格雷码映射子函数

输入:gray_signal为经过格雷编码的信源序列,M为码元位数,N为符号长度。

输出:dec_nums为格雷码解码得到的符号序列,mapping_signal为2行,N列的坐标矩阵。

方法:现将之前得到格雷编码的信源序列解码为自然二进制数,再转为十进制数,通过正交基投影得到星座图坐标矩阵。

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
function [dec_nums, mapping_signal] = map_Gray(gray_signal, M, N)
mapping_signal = zeros(2, N);
temp = zeros(M, N);
dec_nums = zeros(1, N);
%% 将格雷码解码为自然顺序二进制数
for i = 1 : N
    for j = 1 : M
        if j == 1
            temp(ji) =  gray_signal(ji);
        elseif j == 2
            temp(ji) = xor(gray_signal(j-1i), gray_signal(ji));
        else
            temp(ji) = xor(temp(j-1i), gray_signal(ji));
        end
    end
end
%% 将二进制数转为十进制数,方便映射
for i = 1 : N
    for j = 1 : M
        dec_nums(i) = dec_nums(i) + temp(ji) * 2^(M - j);
    end
end
%% 通过符号整数映射
for i = 1 : N
    mapping_signal(1i) = cos(dec_nums(i)*pi/(2^(M-1)));
    mapping_signal(2i) = sin(dec_nums(i)*pi/(2^(M-1)));
end

5. 噪声序列生成子函数

输入:N为符号长度,噪声方差sigma

输出:2行,N列的矩阵

方法:通过噪声方差,计算得出两路正交的零均值高斯噪声序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
% 产生两路正交的零均值高斯噪声序列
function noise = generate_Noise(N, sigma)
nc = zeros(1, N);
ns = zeros(1, N);
for i = 1 : N
    u = rand;
    z = sigma*sqrt(2 * log(1 / (1 - u)));
    u = rand;
    % 得到正交的零均值高斯噪声序列
    nc(i) = z * cos(2 * pi * u);
    ns(i) = z * sin(2 * pi * u);
end
% 返回一个与发射序列同行的矩阵
% 方便将噪声与信号叠加
noise(1,:) = nc;
noise(2,:) = ns;
end

6. MPSK的零方差噪声信号星座图生成子函数

输入:M为码元位数

输出:MPSK 的零方差噪声信号星座图(2行,2^M列的矩阵)

方法:对[1,2^M]进行遍历:通过正交基完成在星座图上的投影

1
2
3
4
5
6
7
function constellation_table = Constellation_Table(M)
constellation_table = zeros(2,2^M);
for  i = 1 : 2^M
    constellation_table(1i) = cos((i-1)*pi/(2^(M-1)));
    constellation_table(2i) = sin((i-1)*pi/(2^(M-1)));
end
end

7. 星座图生成子函数

输入:dec_nums为之前解码时得到的信源的符号序列,r为接收信号,N为码元个数

方法:通过dec_nums和r的对照关系,将相同符号的接收序列映射为同一颜色,r的第1行作为x坐标,第2行作为y坐标,使用plot绘制星座图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function draw_Constellation(dec_nums, r, N)
%% 绘制星座图
figure("name""星座图")
color = 'rybgkcmg';
for i = 1 : N
    plot(r(1i), r(2i), "*"'Color', color(dec_nums(i)+1));
    hold on;
end
hold off
axis([-22-22])
% 参考线绘制
line([-22], [00] , "color""red")
line([00], [2-2], "color""red")
title("星座图")
end

8. 最大投影准则判决子函数

输入:r为接收信号,M为码元位数,N为符号长度。

输出:M行,N列的0,1矩阵(判决得到的是信号的格雷编码)。

方法:通过先前编写好的Gray_Table(M)和Constellation_Table(M)函数,生成Mbit 格雷码对照表和MPSK的零方差噪声信号星座图,遍历r每一列与零方差噪声信号星座图矩阵的每一列的投影,得到的最大投影对应的零方差噪声信号星座的索引,通过索引判断序列对应的符号,最后对判决得到的索引从格雷码表中得到序列对应的格雷码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function c = judge_Max_Projection(r, M, N)
%% 预设M bits 格雷码表
gray_table = Gray_Table(M);
%% 预设星座图表
constellation_table = Constellation_Table(M);
% 用来接收向量积
d = zeros(12^M);
% 用来接收判决输出的信号
c = zeros(M, N);
for i = 1 : N
    for j = 1 : 2^M
    d(j) =  constellation_table(:,j)' * r(:,i);
    end
    % 通过max函数得到最大向量积的索引
    % 从而确定信道输出码元在哪个方向投影最大
    [~,m] = max(d);
    % 得到最大投影索引值后
    % 通过索引根据原序列给判决输出赋相应的序列值
    c(:,i) = gray_table(:,m);
end
end

9. 最小距离准则判决子函数

输入:r为接收信号,M为码元位数,N为符号长度

输出:M行,N列的0,1矩阵(判决得到的是信号的格雷编码)

方法:通过先前编写好的Gray_Table(M)和Constellation_Table(M)函数,生成Mbit 格雷码对照表和MPSK的零方差噪声信号星座图,遍历r每一列与零方差噪声信号星座图每一坐标的距离,得到的最小距离对应的零方差噪声信号星座的索引,通过索引判断序列对应的符号,最后对判决得到的索引从格雷码表中得到序列对应的格雷码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function c = judge_Min_Distance(r, M, N)
%% 预设M bits 格雷码表
gray_table = Gray_Table(M);
%% 预设星座图表
constellation_table = Constellation_Table(M);
% 最小距离判决
% 用来接收两点距离
d = zeros(12^M);
% 用来接收判决输出的信号
c = zeros(M, N);
for i = 1 : N
    for j = 1 : 2^M
    d(j) =  (r(1,i) - constellation_table(1,j))^2 + (r(2,i) - constellation_table(2,j))^2;
    end
    % 通过min函数得到最小距离的索引
    % 从而确定信道输出码元在离哪个原码元最近
    [~,m] = min(d);
    % 得到最小距离索引值后
    % 通过索引根据原序列给判决输出赋相应的序列值
    c(:,i) = gray_table(:,m);
end
end

10. 误比特率和误符号率统计子函数

输入:gray_signal为发送信号的格雷码,gray_signal_rec为判决输出信号的格雷码,M为码元位数,符号长度为N

输出:error_bits_rat为误比特率,error_sym_rat为误符号率

方法:通过对发射端的序列格雷码与接收端判决后的序列格雷码遍历,判断相同位置的比特是否相同,如果不同,则误比特数+1,若在一个符号内出现误比特,则误符号数+1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function [error_bits_rat, error_syms_rat] = stat_Error(gray_signal, gray_signal_rec, M, N)
% 初始化误比特数为0
error_bits = 0;
% 初始化误码数为0
error_syms = 0;
% symbol用于记录是否误码
symbol = 0;
for i = 1 : N
    for j = 1 : M
        if ~isequal(gray_signal(ji), gray_signal_rec(ji))
            error_bits = error_bits + 1;
            symbol = 1;
        end
    end
    % 一个码元误比特诊断完后,若symbol = 1则误码数加1
    if symbol == 1
        error_syms = error_syms + 1;
        symbol = 0;
    end
end
error_bits_rat = error_bits/(M*N);
error_syms_rat = error_syms/N;
end

测试脚本(主程序)

1. 星座图测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
N = 1000;    % 信源序列长度
M = 2;  % 码元位数
source_signal = generate_Source(M, N);   % 获取两位二进制随机序列
%% 二进制信源序列经格雷码编码
% gray_signal是经格雷编码后的信号
gray_signal_send = code_Gray(source_signal, M, N);
%% 格雷码映射
% dec_nums是利用格雷码解码出来的十进制数
% mapping_signal是格雷码映射的星座图坐标
[dec_nums, mapping_signal] = map_Gray(gray_signal_send, M, N);
%% 产生两路正交的零均值高斯白噪声序列
sigma = 0.8;   % 噪声方差
noise = generate_Noise(N,sigma);
r = mapping_signal + noise;
%% 绘制星座图
draw_Constellation(dec_nums, r, N);
% 判决输出的是信号的格雷码
% 最大投影判决
% gray_signal_rec = judge_Max_Projection(r, M, N);
% 最小距离准则判决
gray_signal_rec = judge_Min_Distance(r, M, N);

2. 误比特率和误码率测试主程序

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
close all;
clear;
clc;
% 误比特率和误符号率曲线测试程序
% 绘制误比特率和误码率曲线
N = 100000;    % 信源序列长度
M = 2;  % 码元位数
Eb = 1/M;             % 发送信号的比特能量为0.5 
xlen = 16;
SNR = zeros(1, xlen);
error_bits_rat = zeros(1, xlen);
error_bits_the = zeros(1, xlen);
error_syms_rat = zeros(1, xlen);
error_syms_the = zeros(1, xlen);
sigma = zeros(1, xlen);
for i = 1:xlen
    SNR(i) = i - 6;
    N0 = Eb/(10^(SNR(i)/10));  % 给定信噪比求噪声的单边功率谱密度
    sigma(i) = sqrt(N0/2);     % 求方差
    source_signal = generate_Source(M, N);   % 获取M位二进制随机序列
    gray_signal_send = code_Gray(source_signal, M, N);
    [dec_nums, mapping_signal] = map_Gray(gray_signal_send, M, N);    %qpsk映射,gray
    noise = generate_Noise(N,sigma(i));
    r = mapping_signal + noise;              %信号加噪
%     gray_signal_rec = judge_Min_Distance(r, M, N);  %最小欧式距离准则判决,判决输出信号
    gray_signal_rec = judge_Max_Projection(r, M, N);
    [error_bits_rat(i), error_syms_rat(i)] = stat_Error(gray_signal_send, gray_signal_rec, M, N);
    error_bits_the(i) = 0.5*erfc(sqrt(Eb/N0));  %Q函数计算理论误比特率
    error_syms_the(i) = 2 * error_bits_the(i) * (1 - 0.5 * error_bits_the(i));
end
% 处理8PSK误符号率
M = 3;
Eb = 1/M;
error_syms_rat8 = zeros(115);
error_syms_the8 = zeros(115);
% 其他预设保持不变
for i = 1 : xlen
    N0=Eb/(10^(SNR(i)/10));  % 给定信噪比求噪声的单边功率谱密度
    sigma(i)=sqrt(N0/2);     % 求方差
    source_signal =generate_Source(M, N);   % 信源信号 
    gray_signal_send = code_Gray(source_signal, M, N);
    [~, mapping_signal] = map_Gray(gray_signal_send, M, N);    % Mpsk映射,gray
    noise = generate_Noise(N,sigma(i));
    r = mapping_signal + noise;              % 信号加噪
%     gray_signal_rec = judge_Min_Distance(r, M, N);  % 最小欧式距离准则判决,判决输出信号
    gray_signal_rec = judge_Max_Projection(r, M, N);    % 最大投影准则判决,判决输出信号
    [~, error_syms_rat8(i)] = stat_Error(gray_signal_send, gray_signal_rec, M, N);
    error_syms_the8(i) = erfc(sqrt(log2(2^M)*Eb/N0) * sin(pi/(2^M)));
end
% 绘制QPSK误比特率
figure('name''error_bits');
semilogy(SNR, error_bits_rat, 'r-x');         % 画出仿真误比特率曲线,设为红色x
hold on;
semilogy(SNR, error_bits_the, 'r-o');           % 画出理论误比特率曲线,设为红色o
grid on
xlabel('Eb/N0(dB)');
ylabel('误比特率') ;
title('QPSK通信系统的误比特率');
hold off; 
legend({'QPSK仿真误比特率''QPSK理论误比特率'},'Location''southwest')
% 绘制QPSK和8PSK的误符号率
figure('name''error_syms');
semilogy(SNR, error_syms_rat, 'g-x');
hold on;
semilogy(SNR, error_syms_the, 'g-o');
semilogy(SNR, error_syms_rat8, 'r-x');
semilogy(SNR, error_syms_the8, 'r-o');
xlabel('Eb/N0(dB)');
ylabel('误符号率') ;
title('QPSK和8PSK通信系统的误符号率比较');
hold off; 
legend({'QPSK仿真误符号率''QPSK理论误符号率''8PSK仿真误符号率''8PSK理论误符号率'},'Location''southwest')