2023年12月28日,本文编辑完成,但没有发布,因为还要不断增加内容。之前已经讲基础仿真代码分享了,所以这次发布技术难度大的内容了。2024年7月,暑假在家整理卷积码编译码程序,正式和大家分享!本文超级长,请耐心看完,本人在文末给出了代码下载链接!
之前分享的代码!这次内容在哪呢?新增一个文件夹!
维特比译码是一种高效的最优译码算法,广泛应用于数字通信和信道编码中。它主要用于译码卷积码和某些类型的码,例如Trellis码。
维特比译码算法的原理可以概括如下:
状态机模型:维特比算法基于有限状态机模型来描述卷积码。卷积码的编码过程可以用一个状态转移图来表示,每个节点表示一个状态,每条边表示从一个状态转移到另一个状态的可能性,边上标注着相应的输出符号。
路径度量:在译码过程中,算法 会为每条可能的路径计算一个度量值,这个度量值通常是路径的累积误差。对于每个节点(状态),算法 会保留到达该节点的最优路径(即误差最小的路径)。
前向递推:维特比算法通过前向递推的方法,从起始状态开始,逐步处理接收到的符号。对于每个接收到的符号,算法 会更新每个节点的最优路径及其度量值。具体来说,对于当前时刻的每个状态,算法 会考虑所有可能从前一时刻的状态转移到当前状态的路径,选择度量值最小的路径作为当前状态的最优路径。
回溯路径:在处理完所有接收到的符号后,算法 会从终止状态开始,沿着各个状态的最优路径回溯,最终得到最优的输入序列。这个序列就是译码得到的结果。
误差度量的计算:误差度量通常使用汉明距离或欧氏距离来计算接收到的符号与期望输出符号之间的差异。汉明距离适用于离散符号,而欧氏距离则适用于连续信号。
维特比译码的主要优势在于它能以相对较低的复杂度实现最优译码,因此在实际应用中得到了广泛使用。它的复杂度与码的状态数呈线性关系,而不是指数关系,这使得它在处理较长的码序列时仍然具有可操作性。2024年了,我们可以请人工智能写个仿真程序,看看效果吧?
可以正确运行!那么能不能用自编的函数来代替vitdec函数呢?再来看看AI给出的代码?
% BPSK demodulation
rxBits = rxSignal > 0;
% Custom Viterbi decoding
decodedBits = custom_vitdec(rxBits, trellis, dataLength);
% 自编函数
% Calculate Bit Error Rate (BER)
numErrors = sum(infoBits ~= decodedBits);
ber = numErrors / dataLength;
% Display results
fprintf('Number of bit errors: %d\n', numErrors);
fprintf('Bit Error Rate (BER): %f\n', ber);
% Plot results
figure;
subplot(3,1,1);
stem(infoBits, 'filled');
title('Original Information Bits');
xlabel('Bit Index');
ylabel('Value');
subplot(3,1,2);
stem(decodedBits, 'filled');
title('Decoded Bits');
xlabel('Bit Index');
ylabel('Value');
subplot(3,1,3);
stem(infoBits ~= decodedBits, 'filled');
title('Bit Errors');
xlabel('Bit Index');
ylabel('Error (1 = error, 0 = no error)');
% Custom Viterbi Decoder Function
function decodedBits = custom_vitdec(rxBits, trellis, dataLength)
numStates = 2^(trellis.numInputSymbols - 1);
% Number of states in trellis
numBranches = trellis.numOutputSymbols;
% Number of branches from each state
pathMetric = inf(numStates, dataLength + 1);
% Path metric array
pathMetric(1, 1) = 0; % Initialize the starting state
% Survivor path and traceback
survivorPath = zeros(numStates, dataLength + 1);
traceback = zeros(numStates, dataLength);
% Perform Viterbi algorithm
for bitIdx = 1:dataLength
for state = 1:numStates
for branch = 1:numBranches
nextState = trellis.nextStates(state, branch) + 1;
branchMetric = sum(rxBits((bitIdx-1)*n+1:bitIdx*n) ~= trellis.outputs(state, branch));
newMetric = pathMetric(state, bitIdx) + branchMetric;
if newMetric < pathMetric(nextState, bitIdx + 1)
pathMetric(nextState, bitIdx + 1) = newMetric;
survivorPath(nextState, bitIdx + 1) = state;
traceback(nextState, bitIdx) = branch - 1;
end
end
end
end
% Traceback to find the best path
[~, bestState] = min(pathMetric(:, end));
decodedBits = zeros(dataLength, 1);
for bitIdx = dataLength:-1:1
decodedBits(bitIdx) = traceback(bestState, bitIdx);
bestState = survivorPath(bestState, bitIdx + 1);
end
end
程序出错了,不过大家可以根据编译提示进行相关改动,也可以参考本人写的代码进行对应修改!后面还会补充SOVA算法的仿真内容。这里先简单介绍一下这个算法。
SOVA(Soft Output Viterbi Algorithm)是一种软输出维特比算法。与传统的硬判决维特比算法不同,SOVA在输出译码比特的同时,还输出了这些比特的置信度信息。这使得SOVA在某些应用中具有更好的性能,特别是与其他信道编码技术(如Turbo码)结合使用时。SOVA的主要特点和工作原理如下所述。
软输出:
SOVA不仅给出每个比特的最可能值(0或1),还给出每个比特是0或1的置信度,这通常用对数似然比(LLR, Log-Likelihood Ratio)来表示。LLR是接收到的比特是1的概率和比特是0的概率之比的对数。
路径度量和状态度量:
SOVA与传统的维特比算法一样,使用路径度量和状态度量来寻找最优路径。然而,在每一步,SOVA不仅更新路径度量,还更新与每个路径关联的比特置信度。
更新置信度:
在计算路径度量时,SOVA同时计算每个路径的比特置信度。当两条路径汇合时,SOVA将两个路径的置信度进行比较和更新,以反映不同路径对比特判决的影响。
回溯过程:
SOVA在找到最优路径后,通过回溯过程生成译码比特序列和相应的置信度信息。
输出形式:传统的维特比算法是硬判决的,只输出比特值;而SOVA输出比特值和置信度。
性能:由于包含了软判决信息,SOVA在处理噪声和干扰时通常性能更好,误码率更低。
复杂度:SOVA的计算复杂度略高于传统维特比算法,因为它需要计算和维护置信度信息。
SOVA被广泛用于Turbo码的译码器中。在Turbo码译码过程中,SOVA提供的软输出信息可以用于后续的迭代译码,从而提高整体系统的性能。后续自然也会介绍和讲解Turbo码编译码的过程。