开始前 最好看看以下博客 掌握一些基础知识
[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, 创建对象实例后,将自设交织器序列 作为函数参数引入,可以随时更改
  • OutputIndicesSource 输出索引来源
    后面只能是 ‘Auto’ (默认) | ‘Property’ | ‘Input port’
    • 当设定为’Auto’时 该对象计算 删除第二个分量码的系统流(系统码部分),但 包括所有尾位(反馈位)的输出索引。
      后两个用法和之前的InterleaverIndicesSource一样
  • 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小节的例子)。 输出的位数等于你提供的输出索引的向量长度。这种情况下的码率也得自行计算。

二、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')