思路:
函数:
归一化:
- [-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);
读取音频
信道译码
参数和函数
参数介绍
- 函数
- audioread(path) %读取音频
- sound(n_audio, fs) % 播放
- mod(x,2) % 取模运算
- kron() % 扩采样
- conv() % 时域上卷积
- awgn() % 高斯白噪声
- 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: 信道编码:(7,4)汉明码
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用于存储(7,4)汉明码编码后的码元,其每一列存储一个码组
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); %播放接收端最终还原的语音信号