commnication toolbox 学习记录四:turbo码编码器对象,以及turbo码入门
开始前 最好看看以下博客 掌握一些基础知识
[1] 一个比较简洁的turbo 的基础知识(CSDN)Turbo码(Turbo Codes)-纸上谈芯
[2] 关于卷积码(包括RSC)、trellis 结构的一些基础知识(CSDN)卷积码matlab实现之ploy2trellis函数
原文链接 :matlab comm.TurboEncoder 的帮助文档
一、turbo码编码器对象
在matlab R2012a 版本以上中 communication toolbox 引入了turbo码编码函数, 准确来说是一个matlab系统对象, 即comm.TurboEncoder
创建 turbo码编码器对象的语法如下:
turboenc = comm.TurboEncoder
turboenc = comm.TurboEncoder(Name,Value)
turboenc = comm.TurboEncoder(trellis,interlvrindices)
注意:对于创建对象的第二种方式,输入参数叫做 属性名(property name)-值(value)对,这种方式等价于,objectname.property=value
, 创建的所有对象实例 将拥有这些设定过的属性值,一般不可再更改。
comm.TurboEncoder 对象的 属性(property)有以下几种
TrellisStructure
trellis 结构
后接 trilles对象,用来构建卷积码编解码器 默认值 为poly2trellis(4,[13 15],13) 的RSC码InterleaverIndicesSource
交织列器索引来源
后面接的值只能是:’Property’ (默认)| ‘Input port’.- 当设定为’Property’时, 对象将使用 你自己指定的交织索引
- 当设定为’Input port’时,即’InterleaverIndices’ 属性值 可以在创建的对象里面作为函数的参数一样更改
如创建了 TurboEncoder对象 turboenc, 就可以使用encodedData = turboenc(data,intrlvrIndices);
这种方式调用对象实例。!!!
InterleaverIndices
交织器索引
他是InterleaverIndicesSource
的依赖项,必须将InterleaverIndicesSource
值设为’Property’
后面接的值是 交织器索引序列- 默认为
(64:-1:1).
即倒序,之所以是64 ,默认64位输入比特 - 当自己设定时,注意索引 只能是 1:L 随机重排,L是输入码长 可以用
randperm( )
函数实现
- 默认为
- 总结一下 交织器索引 。设定交织器索引有三种方式:
- 默认方式: 其中InterleaverIndicesSource=’Property’ (默认),且InterleaverIndices=
(64:-1:1).
(默认),当然这种方式应该要求输入码长位 64 - 自定义方式(从对象属性输入):其中InterleaverIndicesSource=’Property’ (默认),InterleaverIndices= 自设交织器序列,这种方式,生成的交织器索引对象实例 都将有一个固定的交织器序列,不可再更改
- 自定义方式(从对象实例,以函数参数输入):InterleaverIndicesSource=’Input port’(默认),不用设置InterleaverIndices, 创建对象实例后,将自设交织器序列 作为函数参数引入,可以随时更改
- 默认方式: 其中InterleaverIndicesSource=’Property’ (默认),且InterleaverIndices=
OutputIndicesSource
输出索引来源
后面只能是 ‘Auto’ (默认) | ‘Property’ | ‘Input port’- 当设定为’Auto’时 该对象计算 删除第二个分量码的系统流(系统码部分),但 包括所有尾位(反馈位)的输出索引。
后两个用法和之前的InterleaverIndicesSource
一样
- 当设定为’Auto’时 该对象计算 删除第二个分量码的系统流(系统码部分),但 包括所有尾位(反馈位)的输出索引。
OutputIndices
输出索引
同理,他是OutputIndicesSource
的依赖项
后面接的值是 输出索引序列- 默认为
getTurboIOIndices(64,2,3)
- 也可以自己设定 。但最大长度不得超过 ( L + mLen ) × N × 2 的完全编码长度,其中L是输入块长度, mLen是内存长度,N 是组成编码器的编码流数。
- 默认为
使用 语法
codeword = turboenc(message) % 默认方式
codeword = turboenc(message,interlvrindices) % 当InterleaverIndicesSource 为Input port 时
codeword = turboenc(message,interlvrindices,outindices) % 当InterleaverIndicesSource 为Input port 、OutputIndicesSource 为Input port 时
1.1、一些基本使用说明
turbo 编码器使用并行级联卷积编码方案来编码二进制输入信号。总体而言,编码器由两个码率为$1/N$的分量码编码器(一般是RSC编码器)和一个内部交织器组成。如图。
再次强调一下Turbo码编码器对象中一个重要属性
- OutputIndicesSource属性:指定用于符号删余(puncturing:一般译为删余、或者打孔 )和重复(repetition)的输出索引的来源。
- 设置该属性为’Auto’时(也即默认情况),对象 会计算输出索引, 全长完整输出情况下,
编码器输出位数为:$M=L×(2N-1)+2×numTails $ ,码率为$R=L/M$其中:- 1、$L$是 输入码字的长度
- 2、$numTails= log2(TrellisStructure.numStates)×N$ 即RSC编码器的反馈比特部分
- 设置该属性为’Input port’ 或者 ‘Property’时,对象 使用自行指定的输出索引运行(也就是你要自行编写输出索引),输出索引是相对于完全编码输出指定的(这一点看不懂的话可以继续往下看2.2小节的例子)。 输出的位数等于你提供的输出索引的向量长度。这种情况下的码率也得自行计算。
- 设置该属性为’Auto’时(也即默认情况),对象 会计算输出索引, 全长完整输出情况下,
二、turbo码编码 举例
2.1、默认方式 编码(默认码率约为1/3)
如图为默认参数下,turbo码的编码结构图
上下各一个码率为1/2的RSC编码器、注意由于是系统反馈卷积码,最终还有“反馈部分” (编码器输入完输入序列之后,图中的开关会闭合,经过系统自反馈,编码器状态会归零,这有利于解码端MAP解码时后向迭代)反馈长度为(约束长度-1),该图中=4-1=3
输入序列为$C_k$,输出序列是(注意,输出序列逐比特按照下面的顺序循环依次输出)
- 1、上面的RSC编码器$X_k$部分(系统码部分)(加3位反馈部分)、
- 2、上面的RSC编码器$Z_k$部分(校验码部分)(加3位反馈部分)
- 3、下面RSC编码器系统码部分不要,跳过!!! (要3位反馈部分)
- 4、下面的RSC编码器$Z_k^*$部分(校验码部分)(加3位反馈部分)
即输出
$X_1、Z_1、X_1(skip)、Z_1^;X_2、Z_2、X_2(skip)、Z_2^;…… $
如当输入一个长度为64位的信息序列,最终编码后长度为 $64×3 +3×4=192+12=204$
rng default
turboenc = comm.TurboEncoder;
frameLen = 64; % Frame length
data = randi([0 1],frameLen,1);
encData = turboenc(data);
codewordLen = length(encData);
codingrate = frameLen/codewordLen % 64/204= 0.3137
2.2 对比 全长turbo 码 以及 删余 turbo码
下面是 代码:
初始化参数
blkLen = 10;
trellis = poly2trellis(4,[13 15],13);
n = log2(trellis.numOutputSymbols); % 输出比符号 比特数
mLen = log2(trellis.numStates); % 感觉这里应该是“记忆长度”,不应该用 寄存器个数,不多对一个但输入的卷积码来说没影响
全长编码输出
和2.1 默认方式相比,
- 1、输出时把 下面的RSC 编码器 的系统位也加上了
- 2、自定义了”内交织器”
那么给定 10 个输入比特 , 反馈长度 =4-1=3
那么全长输出位数: (10+3)×4=52
fullOut = (1:(mLen+blkLen)*2*n)'; %
outLen = length(fullOut);%计算全长
netRate = blkLen/outLen;% 整体码率 10/52= 0.192307692307692
data = randi([0 1],blkLen,1);
intIndices = randperm(blkLen);% 内交织 产生一组 0到blkLen-1 不重复的数字
turboEnc = comm.TurboEncoder('TrellisStructure',trellis);
turboEnc.InterleaverIndices = intIndices;
turboEnc.OutputIndicesSource = 'Property';
turboEnc.OutputIndices = fullOut; % 输出序列 全长输出
encMsg = turboEnc(data);
disp(['Turbo coding rate: ' num2str(netRate)]) %isequal(encOutLen,outLen) % Check lengths
encOutLen = length(encMsg) % Display encoded length =52
isequal(encOutLen,outLen) % Check lengths =1 true
删余编码输出
这个代码用删余的方式实现了默认参数下的 turbo码 ,即删去 第二个RSC的系统码部分
puncOut = getTurboIOIndices(blkLen,n,mLen); % 得到输出索引(第二个RSC输出的系统位不要)相较于在“全长输入下的”输出索引
outLen = length(puncOut);
netRate = blkLen/outLen;
data = randi([0 1],blkLen,1);
intIndices = randperm(blkLen);
turboEnc = comm.TurboEncoder('TrellisStructure',trellis);
turboEnc.InterleaverIndices = intIndices;
turboEnc.OutputIndicesSource = 'Property';
turboEnc.OutputIndices = puncOut; % 删余后的输出索引
encMsg = turboEnc(data); % Encode
disp(['Turbo coding rate: ' num2str(netRate)]) % 0.25641
encOutLen = length(encMsg) % Display encoded length =39
isequal(encOutLen, outLen) % Check lengths =true
全长输出、删余输出的 输出索引 对比
fullOut'
ans = 1×52
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
puncOut'
ans = 1×39
1 2 4 5 6 8 9 10 12 13 14 16 17 18 20 21 22 24 25 26 28 29 30 32 33 34 36 37 38 40 41 42 44 45 46 48 49 50 52
对比二者 输出索引可以看出
每个 4 位元组的第3位 (如 {1,2,3,4}中的3、{5,6,7,8}中的7)从全长turbo码中删除,以生成删余 turbo码输出。删除的该第三输出比特流。对应于下面的RSC编码器的系统比特流。 这与我在2.1 中说的 默认方式编码一样
2.3 一些仿真实例
2.3.1、仿真实例:通过 BPSK 调制 AWGN 通道发送和接收 Turbo 编码数据
使用 turbo 编码和解码模拟 AWGN 通道上 BPSK 数据的传输和接收。
配置
modOrd = 2; % Modulation order
bps = log2(modOrd); % Bits per symbol
EbNo = 1; % Energy per bit to noise power spectral density ratio in dB
EsNo = EbNo + 10*log10(bps); % Energy per symbol to noise power spectral density ratio in dB
L = 256; % Input packet length in bits
trellis = poly2trellis(4,[13 15 17],13);
numiter = 4; % 迭代次数!
n = log2(trellis.numOutputSymbols);
numTails = log2(trellis.numStates)*n;
M = L*(2*n - 1) + 2*numTails; % Output codeword packet length
rate = L/M; % Coding rate
snrdB = EsNo + 10*log10(rate); % Signal to noise ratio in dB
noiseVar = 1./(10.^(snrdB/10)); % Noise variance
rng default
intrlvrIndices = randperm(L); % 内交织序列
% turbo 编码译码器对象
turboenc = comm.TurboEncoder(trellis,intrlvrIndices);
turbodec = comm.TurboDecoder(trellis,intrlvrIndices,numiter);
% BPSK 调制解调器对象
bpskmod = comm.BPSKModulator;
bpskdemod = comm.BPSKDemodulator('DecisionMethod','Log-likelihood ratio', ...
'Variance',noiseVar);
% 信道对象、误比特计数器
awgnchan = comm.AWGNChannel('NoiseMethod','Variance','Variance',noiseVar);
errrate = comm.ErrorRate;
仿真主体(帧处理循环)
帧处理循环执行这些步骤。
- 生成二进制数据。
- Turbo对数据进行编码。
- 调制编码数据。
- 将调制信号通过 AWGN 通道。
- 通过使用 LLR 来解调有噪声的信号以输出软比特。
- 对解调数据进行 Turbo 解码。由于来自解调器的位映射与 turbo 解码器预期的映射相反,解码器输入必须使用解调信号的相反数
- 计算误差统计
for frmIdx = 1:100
data = randi([0 1],L,1);
encodedData = turboenc(data);
modSignal = bpskmod(encodedData);
receivedSignal = awgnchan(modSignal);
demodSignal = bpskdemod(receivedSignal);
receivedBits = turbodec(-demodSignal);%由于来自解调器的位映射与 turbo 解码器预期的映射相反,解码器输入必须使用解调信号的相反数
errorStats = errrate(data,receivedBits);
end
fprintf('Bit error rate = %5.2e\nNumber of errors = %d\nTotal bits = %d\n', errorStats)
输出:
Bit error rate = 2.34e-04
Number of errors = 6
Total bits = 25600
2.3.2、 对 AWGN 信道中的 16-QAM 信号执行 Turbo 编码
通过在 AWGN 信道中使用 16-QAM 信号和 Turbo 码来模拟端到端通信链路。
在帧处理循环中,数据包大小随机选择为 500、1000 或 1500 位。由于数据包大小不同,交织器索引作为其关联系统对象的输入参数提供给 turbo 编码器和解码器。将 Turbo 编码的误码率结果与未编码的误码率结果进行比较。
配置
modOrder = 16; % Modulation order
bps = log2(modOrder); % Bits per symbol
EbNo = (2:0.5:4); % Energy per bit to noise power spectral density ratio in dB
EsNo = EbNo + 10*log10(bps); % Energy per symbol to noise power spectral density ratio in dB
rng(1963);
% turbo 编解码对象 (其中 解码器对象全部指定为 4 次)
turboEnc = comm.TurboEncoder('InterleaverIndicesSource','Input port'); % 采用'Input port'方式,则后续可以用函数式形式调用 交织索引
turboDec = comm.TurboDecoder('InterleaverIndicesSource','Input port','NumIterations',4);
trellis = poly2trellis(4,[13 15 17],13);
n = log2(turboEnc.TrellisStructure.numOutputSymbols);
numTails = log2(turboEnc.TrellisStructure.numStates)*n;
% 误比特记录对象
errRate = comm.ErrorRate;
仿真主体(帧处理循环)
帧处理循环执行这些步骤。
- 选择一个随机数据包长度,生成随机二进制数据。
- 计算输出码字长度和编码率。
- 计算信噪比 (SNR) 和噪声方差。
- 生成交织器索引。
- Turbo对数据进行编码。
- 应用 16-QAM 调制,并标准化平均信号功率。
- 将调制信号通过 AWGN 通道。
- 使用LLR方法解调噪声信号,输出软比特,并归一化平均信号功率。
- Turbo 解码数据。由于来自解调器的位映射顺序与 turbo 解码器预期的映射顺序相反,因此解码器输入必须使用解调信号的相反数。
- 计算误差统计。
ber = zeros(1,length(EbNo)); for k = 1:length(EbNo) % numFrames = 100; errorStats = zeros(1,3); %for pktIdx = 1:numFrames L = 500*randi([1 3],1,1); % Packet length in bits M = L*(2*n - 1) + 2*numTails; % Output codeword packet length rate = L/M; % Coding rate for current packet snrdB = EsNo(k) + 10*log10(rate); % Signal to noise ratio in dB noiseVar = 1./(10.^(snrdB/10)); % Noise variance while errorStats(2) < 100 && errorStats(3) < 1e7 data = randi([0 1],L,1); intrlvrIndices = randperm(L); encodedData = turboEnc(data,intrlvrIndices); modSignal = qammod(encodedData,modOrder, ... 'InputType','bit','UnitAveragePower',true); rxSignal = awgn(modSignal,snrdB); demodSignal = qamdemod(rxSignal,modOrder,'OutputType','llr', ... 'UnitAveragePower',true,'NoiseVariance',noiseVar); rxBits = turboDec(-demodSignal,intrlvrIndices); % Demodulated signal is negated 由于来自解调器的位映射顺序与 turbo 解码器预期的映射顺序相反,因此解码器输入必须使用解调信号的相反数。 errorStats = errRate(data,rxBits); end % Save the BER data and reset the bit error rate object ber(k) = errorStats(1); reset(errRate) end
作图
semilogy(EbNo,ber,'-o') grid xlabel('Eb/No (dB)') ylabel('Bit Error Rate') uncodedBER = berawgn(EbNo,'qam',modOrder); % Estimate of uncoded BER hold on semilogy(EbNo,uncodedBER) legend('Turbo','Uncoded','location','sw')