【通信原理】【实验】实验五:信道编码译码思路

思路:
在这里插入图片描述函数:
在这里插入图片描述

归一化:
  • [-1, 1]

方法1(通用公式):

step1:(x-min)/(max-min);取值范围变成了[0,1]
step2:(x-min)/(max-min)(b-a);取值范围变成了[0,b-a]
step3:(x-min)/(max-min)
(b-a)+a;取值范围变成了[a,b]
代入>a = -1,b = 1;
化简
2 * (x-min)/(max-min) -1;

  • [0, 1]

方法1(通用公式):

step:1(x-min)/(max-min);取值范围变成了[0,1]
step2:(x-min)/(max-min)(b-a);取值范围变成了[0,b-a]
step3:(x-min)/(max-min)
(b-a)+a;取值范围变成了[a,b]
代入 a = 0,b = 1;
化简:
(x-min)/(max-min);

读取音频

信道译码



参数和函数

参数介绍

  • 函数
  1. audioread(path) %读取音频
  2. sound(n_audio, fs) % 播放
  3. mod(x,2) % 取模运算
  4. kron() % 扩采样
  5. conv() % 时域上卷积
  6. awgn() % 高斯白噪声
  7. audioplayer(),play() % 这两个函数配合使用读取音频
  • 参数

代码:


clear all;       %清空所有变量
clc;       %清空command window所有记录
 
%step 1:读取语言信号,并进行归一化处理
[audio, fs] = audioread( 'test_speech.wav' );   %读取语音信号,fs为语音信号的采样频率
len_speech = length( audio );   %计算语言信号的采样点个数
%对该语音信号进行归一化处理,使其取值在[-1,1]的范围内
normal = -1 + 2 * (audio - min(audio)) / (max(audio) - min(audio));
a = audioplayer( normal, fs);  play(a);  %播放语音,此时是归一化后的语言信号,发生变化的只是声音的大小(幅度),语言内容未改变
 
%画出发送端的归一化后的语音信号
figure(1);
subplot(2,1,1);  plot(normal);
axis([0 len_speech-1 -1 1]);
title('发送方语音信号的时域波形');   
subplot(2,1,2);  plot((0:len_speech -1) / len_speech * fs, abs(fft(normal)));
ylim([0 1000]);       %取归一化后的频谱
title('发送方语言信号频域波形');
 
%step 2:信源编码,即A律13折线非均匀PCM编码
scrsignal = round( 2048 * normal );  %将语音信号采样值转化为非均匀PCM编码的最小量化间隔的整数倍
code = zeros( len_speech, 8 );  %初始化code矩阵,用来存储PCM编码结果,每行8个元素即为一个13折线编码
code( : ,1 ) = ( scrsignal > 0 );   %极性码
scrsignal_abs = abs(scrsignal);
for i = 1 : len_speech
    if scrsignal_abs(i) >= 0 && scrsignal_abs(i) < 16
        code(i, 2:4) = zeros(1, 3);     %段落码
        step = 1;      %段内量化间隔
        start_point = 0;     %段落起始点
    elseif scrsignal_abs( i ) >= 16 && scrsignal_abs( i ) < 32
        code(i, 2:4) = [0, 0, 1];
        step = 1;
        start_point = 16;
    elseif scrsignal_abs( i ) >= 32 && scrsignal_abs( i ) < 64
        code(i, 2:4) = [0, 1, 0];
        step = 2;
        start_point = 32;
    elseif scrsignal_abs( i ) >= 64 && scrsignal_abs( i ) < 128
        code(i, 2:4) = [0, 1, 1];
        step = 4;
        start_point = 64;
    elseif scrsignal_abs( i ) >= 128 && scrsignal_abs( i ) < 256
        code(i, 2:4) = [1, 0, 0];
        step = 8;
        start_point = 128;
    elseif scrsignal_abs( i ) >= 256 && scrsignal_abs( i ) < 512
        code(i, 2:4) = [1, 0, 1];
        step = 16;
        start_point = 256;
    elseif scrsignal_abs( i ) >= 512 && scrsignal_abs( i ) < 1024
        code(i, 2:4) = [1, 1, 0];
        step = 32;
        start_point = 512;
    else
        code(i, 2:4) = ones(1, 3);
        step = 64;
        start_point = 1024;
    end
    if scrsignal_abs( i ) == 2048      %因为2048节点特殊,因此需要单独处理
        code(i, 5:8) = ones(1 ,4);
    else
        %计算采样值落在某一段的哪一个小段内
        code(i, 5:8) = dec2bin( floor((scrsignal_abs( i ) - start_point) / step),4) -48;
        %dec2bin函数:将十进制数转换为二进制,输出ascii字符串,48对应0
    end
end
code = code';
line_code = (code(:))';  %将code矩阵按每一行排列,拉长为一个行向量line_code
 
%step 3: 信道编码:(74)汉明码
n = 7;
m = 4;
len_speech = length( line_code );
Q = [ 1,1,1; 1,1,0; 1,0,1; 0,1,1];   %校验矩阵Q
G = [ eye(m) , Q];       %生成矩阵G
H = [Q', eye(n - m)];      %监督矩阵H
 
%每m个信息码元为一组,进行信道编码,矩阵channel_data用于存储(74)汉明码编码后的码元,其每一列存储一个码组
channel_data = zeros(n, len_speech / m);  
 
for i = 1:len_speech / m
   %矩阵channel_data的每一列用来存储一个码组,[a6,a5,a4,a3,a2,a1,a0]=[a6,a5,a4,a3]G 
   %mod函数用于模2加
    channel_data( : ,i) = (mod(line_code( (i-1)*m + 1 : i*m) * G, 2 )).';
end
%将channel_data矩阵按每一列排列,拉长为一个行向量channel_data1
channel_data1 = channel_data(:)';
 
 
%step 4: 发送端基带选择码型、脉冲成型
channel_data1 = 2 * channel_data1 - 1; %向量channel_data1中的元素都是0/1,将它转换为双极性码-1/+1序列
 
fb = 1000;    %发送端符号速率fb
fs1 = 16000;  %发送滤波器采样频率fs1,注意与信源编码中语音信号的采样频率fs区分开
oversamp = fs1 / fb;   %过采样率fs1 / fb
delay = 5;    %时延为5
alpha = 0.25;       %滚降系数
h_sqrt = rcosine(fb, fs1, 'fir/sqrt', alpha, delay);  %h_sqrt是平方根升余弦滤波器
sendsignal_oversamp = kron(channel_data1,[1,zeros(1,oversamp -1)]); %发送符号过采样
sendshaped = conv(sendsignal_oversamp,h_sqrt);  %发送端脉冲成型,时域卷积运算
 
%step 5:发送端2PSK调制
fc = 4000;   %fc是载波频率
N = 0 : length(sendshaped) - 1;
carrierWave = cos(2 * pi * fc * N/fs1);   %carrierWave是载波,N/fs1是采样时间点
modemWave = sendshaped .* carrierWave;   %调制
 
%step 6:信道传输
snr = -5;    %信道受高斯白噪声影响,信噪比分别取-10dB、-5dB、0dB、5dB
modemWave1 = awgn(modemWave, snr, 'measured' , 'db');
fprintf('信道的信噪比为 %d',snr); fprintf('dB\n');
 
%step 7: 接收端2PSK相干解调
%乘法器
carrierWave1 = cos(2 * pi * fc * N/fs1);   %接收端相干载波,与发送端载波同频同相,不会发送倒pi现象
demoWave = modemWave1 .* carrierWave1;
 
%step8:接收端匹配载波
recMatched = conv(demoWave, conj(h_sqrt));
 
%step9:接收端同步、抽样、判决
synPosi = delay * oversamp * 2 + 1;  %发送端滤波器,接收端滤波器均产生延迟delay,所以产生了delay*2*oversamp个样本点的延迟
new_len = length(channel_data1);  %所有码组的总的码元个数为new_len = 56000*8/4*7
symPosi = synPosi + (0:oversamp: (new_len-1)*oversamp);
recSignal = recMatched(symPosi);    %对于匹配滤波后的信号recMatched,去掉开头的延迟,且对信号进行抽样
 
recBit = zeros(1, new_len);  %recBit是一个行向量,用来存储接收端判决得到的序列
for i = 1:new_len
    if recSignal(i) > 0   %2PSK判决阀值为0
        recBit(i) = 1;
    else recBit(i) = 0;   %恢复出0/1序列
    end
end
 
%step 10:信道译码
 
%译码表 
%s1s2s3=001,十进制1,错码位置在a0,即第7%s1s2s3=010,十进制2,错码位置在a1,即第6%s1s2s3=100,十进制4,错码位置在a2,即第5%s1s2s3=011,十进制3,错码位置在a3,即第4%s1s2s3=101,十进制5,错码位置在a4,即第3%s1s2s3=110,十进制6,错码位置在a5,即第2%s1s2s3=111,十进制7,错码位置在a6,即第1位
syn_tab = [7 6 4 5 3 2 1];  %用来确定错码的位置
 
outData = zeros(n, new_len/n);  %每n个码元为一组进行译码,矩阵outData用于存储信道译码后的结果,它的每一列存储一个码组
for i = 1:new_len/n        %new_len/n码组个数
    recBit_current = recBit( (i-1)*n+1 : i * n); %每n个码元为一组进行译码
    syn = mod(recBit_current * H' , 2);  %计算校正子[s1s2s3]=[a6,a5,a4,a3,a2,a1,a0]H'   注意模2加
    syn_de = bi2de(syn, 'left-msb');   %把二进制的校正子转化为十进制,因为二进制是从左到右,所以函数bit2be中要声明'left-msb'
    outData( : , i ) = recBit_current;
    if syn_de ~= 0    %s1s2s3为000表示无错码,除此之外都表示有错码
        pos_de = syn_tab(syn_de);     %确定错码的位置
        outData(pos_de, i ) = 1 - recBit_current(pos_de);  %纠正错码,即0纠正成1,把1纠正成0
    end
end
outData( m+1:n , : ) = [];  %去掉所有的监督码元,只留下信息码元
outData1 = outData(:)' ;      %拉长成一个向量
 
%计算信道编码 译码的误码率,衡量信道译码的性能
error_channelcode = sum( abs(line_code - outData1 ) ) / length(line_code);
fprintf('信道编码-译码的误码率为 %8.6f\n',error_channelcode);
 
 
%step 11: 接收端A律非均匀PCM译码
len1 = length( outData1 ) / 8;   %8个码元转换为一个量化译码值
slot_start = [0, 2.^(4:10) ];  %slot_start用来存储每一段落的起始电平
step_series = [ 1 1 2 4 8 16 32 64];   %step_series用来存储每一段落的段内量化间隔
plus_minus = zeros(1, len1);  %plus_minus用于存储采样值的极性
decode_out = zeros(1, len1);
for i = 1:length(outData1) / 8
    temp = outData1(( i-1 )*8 + 1 : i * 8);
    plus_minus( i ) = temp(1);       %极性
    temp1 = sum( temp( 2:4 ) .* (2.^(2:-1:0)));  %采样值所在的段落码
    temp2 = sum( temp( 5:8 ) .* (2.^(3:-1:0)));  %采样值所在的段落码
    decode_out(i) = slot_start( temp1 + 1) + step_series( temp1 + 1 ) * temp2;  %取每小段的起始电平为译码电平
end
decode_out = decode_out .* (2 * plus_minus - 1) / 2048;   %带上正负号
 
%衡量信源编码-译码的性能
figure(2); subplot(2,1,1); plot(normal); ylim([-1 1]); title('发送方原始语言信号');
subplot(2,1,2); plot(decode_out); ylim([-1 1]); title('接收方还原的语音信号');
b = audioplayer(decode_out, fs ); 
play(b);       %播放接收端最终还原的语音信号
  • 7
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jucway

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值