首页/文章/ 详情

代码分享之卷积码译码仿真

精品
作者优秀平台推荐
详细信息
文章亮点
作者优秀
优秀教师/博士学历/特邀专家/独家讲师
平台推荐
内容稀缺
1月前浏览2076

2023年12月28日,本文编辑完成,但没有发布,因为还要不断增加内容。之前已经讲基础仿真代码分享了,所以这次发布技术难度大的内容了。2024年7月,暑假在家整理卷积码编译码程序,正式和大家分享!本文超级长,请耐心看完,本人在文末给出了代码下载链接!

之前分享的代码!这次内容在哪呢?新增一个文件夹!

《卷积码编译码》目录里面有什么呢?

网络上独一份!程序也记载着本人当年写代码的过程,看注释就知道了!
程序为十几年前所写,运行前请将程序中的randint函数更换为randi函数!看到这些代码会想到之前一起工作的同事小罗,他本科毕业于浙江大学,非常聪明,不知后来有没有继续读研。当年工作期间我只短暂的带了他几个月,后续就是他一个人独自写算法程序,过程肯定走的艰辛。早期让一个本科生开始写物理层程序,再有天赋也是一种折磨啊。只能怪当初我没有能力留他在身边跟着我学习,于是让其独自去北京发展。人的一生存在着多个剧本,自己也不知道哪个剧本是正确的。

回顾基础知识仿真!

理论仿真有基带仿真和中频仿真之分。如果只是进行误码性能的分析,那么基带仿真就已足够。当你需要扩充捕获和跟踪等内容的时候,那时中频仿真必不可少。在《通信原理》课本中,中频信号往往被称为带通信号。叫法不一样,内容一致。
基带仿真仿真时间会明显小于带通仿真!
通信理论是基础,在通信领域搞研发的人必须熟知。但很多到了工作岗位的人依旧会发现还有很多基础性的知识需要补。当年的我就遇到这个情况,于是依旧要回到最初的课本进行学习。所以我回到学校后,希望学生们在本科和研究生阶段就能强化学习这方面的知识。学习过程中有代码借鉴可以加快学习速度,也可以深化了解。时间就是金钱,希望此次分享的代码能够起到这种作用。以前在企业研发的代码也会逐步公布,希望这样的公布能够让同行有所促进和提高,甘为人梯!
2023年11月30日,正式开启本人的代码分享之旅,希望能够给广大同仁助力。
2023年12月,以此代码给学生讲课,增进她们对通信原理的理解。
之前分享了哪些代码呢?超过五十个程序,涉及多种数字调制方式、多进制调制等多方面知识。我敢保证肯定有你喜欢的款!这次分享的卷积码译码程序会让学物理层算法的学生或者同行们更加激动!当年天利通公司的研发人员绞尽脑汁的想得到这份源代码,都被我一一回绝了。当年很多公司都靠组装成品芯片研制产品,这样的企业只能挣快钱。没有核心技术的积累,很难走向最终的胜利。

通信仿真的基石!

在家回顾代码!
讲解代码的过程也是学习的过程。再来看看本人写的BPSK的仿真程序!有产品开发经验的人写的代码自带规范这个光环!!!这部分内容之前已经分享过!

模块框图!

学习了《通信原理》,大家会看到下面的框图。那么这样的框图如何理解呢?如果没有仿真程序的帮助,那么大家很难消化框图中的各个模块,于是就会把工科学成了文科!知识就变成了记忆。这是我长期教学的感受,估计也是很多通信类、电子类专业学生的共同困惑吧!
大家要细看程序中的每一句,代码中没有废话!所以请仔细都懂每句代码!很多语句看似懂了,但是涉及的理论基础也许你根本不清楚!框图里面有这么多滤波器啊?和数字信号处理结合如此紧密吗?是的,通信原理和数字信号处理不分家!
时孔子教课是跟弟 子对话、辩论,在授课之余也会有读书和思考。老师如此,学生是不是更应如此。希望大学生们的阅读时间不能少,其次还能有交流。看到公众 号文章的留言这么少,我其实挺心焦的,真希望能有多一些读者来提问。
QPSK代码的复杂度增加了!这典型的多进制调制的代表!还引入了锁相环!简单的编码也加入了!这些内容也已经分享过了!

怎么算是仿真入门?

当你能看懂相干解调的代码时,恭喜你,通信领域算是真正入门了!路漫漫其修远兮,能找到同行的人确实不容易。如果路上还能有人搀扶你,那就请多加珍惜。
给学生讲解代码!
授业需要解惑,也需要学生能提惑!如果没有交流,那么很多知识估计是囫囵吞枣。对于日后想在算法方面有所建树的人而言,需要搞清楚基带仿真的每一个知识点!BPSK和QPSK毕竟是调制方式的典型代表!
代码展示!
本文也给出了本次分享的代码涉及到公 众号内多个系列的文章的链接,希望大家有了代码以后,可以结合文章一起来消化,这样会学得快一些。经典的代码不仅给人知识,也会教你去思考问题。正所谓旧书不厌百回读,熟读深思子自知。
大家看了代码后,印象最深的应该是信噪比进行等效换算的过程。早年学习时,这方面问题是我在仿真过程中一直关注的,也确实困扰了我好长时间。因为做产品的人都会想知道研发出来的产品性能如何,那最好的比对参照物就是理论码率,所以在写好算法的时候总是想看看误码性能到多少?在实际测试的时候,你会根据仪器的设置来产生噪声,仿真的时候呢?只有去模拟。那么产生的噪声性能如何?到底信噪比是多少?我在程序中给出两种加噪方式,一种是产生随机白噪声,还有一种是用自带的函数awgn 函数来进行加噪,后者曾经给我带来很多的困惑。这个困惑要靠实际的经验及仿真的过程来解答。在这里我提醒大家看程序的时候要把这块作为重点知识好好学习一下。为此特地写了几篇文章来讲解信噪比换算过程!
一个系列!慢慢品味!还特地录制了视频课程,在仿真秀网站上可以观看!

在课堂上依旧给学生讲解原理的重要性!

要想吃透原理,仿真必不可少!也希望我的学生们能在努力程度上超过我!这样才会有更高的成就!真心希望青出于蓝而胜于蓝!网上的年青同行们也要加油哦!
讲课很辛苦,连续讲解一个小时后休息了十分钟!然后呢?继续讲!讲完以后又在想同学们到底消化多少了呢?课后和他们进行交流,发现还是没有理解!那就需要多遍学习了!考研的同学如果要考《通信原理》这门课,不会做仿真那简直就是考记忆解题,难得高分。
反复的讲解,只为学生能真正的消化代码!如果遇到函数不能用的问题,可以百度咨询,看看新版本中用哪个函数来替换?如果你给我留言,我也会回答。公 众号的文章快写满了,我也快退休了,自己平生所写的代码终将全部公布,或多或少对大家起到一些帮助吧。可惜,文章没时间翻译成英文,不然也想让国外的同行收益!马斯克是科技界的杰出人物,也是我的偶像,非常赞同他的共享理念。特斯拉赚钱是应该的,这样才能支撑他把技术公开,没有申请专利来阻碍技术的进步。上一位偶像是乔布斯,他的创新精神一直激励着我。世界需要这样的技术革命者!
之前分享了差分调制、扩频、MSK、GMSK、QAM的理论仿真程序,后续会分享工程实现所用代码,敬请期待!
这三篇文章中的链接已经过期,如果你付费了,请联系我给出最新的下载链接!本文会多次重发,如果你购买了老版本的文章,不要着急,后台发个消息给我,一样可以得到下载链接!本人精力有限,这么多年一直坚持写作和编程,实属不易,也许退休后才能真正的停笔!回想学习通信的这几十年,一路走来确实非常不容易!

致谢!

大家看的上我的代码,我就会分享更多!如果愿意交流,那会给我不断讲课和写文章的动力。在学校讲课久了,教学热情屡受打击,只能在互联网上找回自信了!再次感谢读者给我的鼓励和肯定!本文代码的视频课程可以去仿真秀网站观看。
视频中回顾了自己当年讲调制解调器过程,真心希望大家去看看自认为讲的非常好的课程!仿真秀网站有自己的视频课,欢迎观看!
知识提高内容介绍!
维特比译码知识简介!

维特比译码是一种高效的最优译码算法,广泛应用于数字通信和信道编码中。它主要用于译码卷积码和某些类型的码,例如Trellis码。

维特比译码算法的原理可以概括如下:

  • 状态机模型:维特比算法基于有限状态机模型来描述卷积码。卷积码的编码过程可以用一个状态转移图来表示,每个节点表示一个状态,每条边表示从一个状态转移到另一个状态的可能性,边上标注着相应的输出符号。

  • 路径度量:在译码过程中,算法 会为每条可能的路径计算一个度量值,这个度量值通常是路径的累积误差。对于每个节点(状态),算法 会保留到达该节点的最优路径(即误差最小的路径)。

  • 前向递推:维特比算法通过前向递推的方法,从起始状态开始,逐步处理接收到的符号。对于每个接收到的符号,算法 会更新每个节点的最优路径及其度量值。具体来说,对于当前时刻的每个状态,算法 会考虑所有可能从前一时刻的状态转移到当前状态的路径,选择度量值最小的路径作为当前状态的最优路径。

  • 回溯路径:在处理完所有接收到的符号后,算法 会从终止状态开始,沿着各个状态的最优路径回溯,最终得到最优的输入序列。这个序列就是译码得到的结果。

  • 误差度量的计算:误差度量通常使用汉明距离或欧氏距离来计算接收到的符号与期望输出符号之间的差异。汉明距离适用于离散符号,而欧氏距离则适用于连续信号。

维特比译码的主要优势在于它能以相对较低的复杂度实现最优译码,因此在实际应用中得到了广泛使用。它的复杂度与码的状态数呈线性关系,而不是指数关系,这使得它在处理较长的码序列时仍然具有可操作性。2024年了,我们可以请人工智能写个仿真程序,看看效果吧?

用了MATLAB自带函数,能运行吗?

可以正确运行!那么能不能用自编的函数来代替vitdec函数呢?再来看看AI给出的代码?

看看剩余的代码吧!
% Additive White Gaussian Noise (AWGN) channel
rxSignal = awgn(modulatedSignal, snr, 'measured');

% 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的计算复杂度略高于传统维特比算法,因为它需要计算和维护置信度信息。

SOVA被广泛用于Turbo码的译码器中。在Turbo码译码过程中,SOVA提供的软输出信息可以用于后续的迭代译码,从而提高整体系统的性能。后续自然也会介绍和讲解Turbo码编译码的过程。

期待!
自主性的阅读越来越少,批判的阅读更是昙花一现。我真心希望当代大学生们能在电脑屏幕上进行深层次的阅读,如果时间紧迫,在手机上阅读也是可以的,但千万不要把更多的时间用于刷视频和玩游戏。
给出链接!一天有效!请及时下载,过期不候!
来源:通信工程师专辑
Additive化学电子MATLAB芯片通信UM理论游戏人工智能Origin
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2024-08-07
最近编辑:1月前
算法工匠
博士后 | 高级工程师 诚信做事 认真讲课 传播知识
获赞 386粉丝 2529文章 282课程 39
点赞
收藏
作者推荐
未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习 福利任务 兑换礼品
下载APP
联系我们
帮助与反馈