维特比算法仿真
维特比解码matlab仿真程序

Viterbi encoding and uncoding: (based on hamming distance)Code:%the hamming distance of x and yfunction z=d(x,y)z=0;for i=1:length(x)if x(i)~=y(i)z=z+1;endendfunction x=viterbi_uncoding(a)n=length(a);s1=[0 0 1 1];s2=[1 0 0 1];s3=[1 1 0 0];s4=[0 1 1 0];D1=0;D2=0;D3=0;D4=0;%hamming distance of four route%NO.1 of input codeD1=d([s1(1),s1(2)],[a(1),a(2)]);x1=[0];D2=d([s1(3),s1(4)],[a(1),a(2)]);x2=[1];%NO.2A=x1;B=x2;C=D1;D=D2;D1=C+d([s1(1),s1(2)],[a(3),a(4)]);x1=[A,0];D2=C+d([s1(3),s1(4)],[a(3),a(4)]);x2=[A,1];D3=D+d([s2(1),s2(2)],[a(3),a(4)]);x3=[B,0];D4=D+d([s2(3),s2(4)],[a(3),a(4)]);x4=[B,1];%NO.3-NO.n/2for i=3:n/2A=x1;B=x2;C=x3;D=x4;E=D1;F=D2;G=D3;H=D4;%point1if E+d([s1(1),s1(2)],[a(2*i-1),a(2*i)])<G+d([s3(1),s3(2)],[a(2*i-1),a(2*i)]) D1=E+d([s1(1),s1(2)],[a(2*i-1),a(2*i)]);x1=[A,0];else D1=G+d([s3(1),s3(2)],[a(2*i-1),a(2*i)]);x1=[C,0];end%point2if E+d([s1(3),s1(4)],[a(2*i-1),a(2*i)])<G+d([s3(3),s3(4)],[a(2*i-1),a(2*i)]) D2=E+d([s1(3),s1(4)],[a(2*i-1),a(2*i)]);x2=[A,1];else D2=G+d([s3(3),s3(4)],[a(2*i-1),a(2*i)]);x2=[C,1];end%point3if F+d([s2(1),s2(2)],[a(2*i-1),a(2*i)])<H+d([s4(1),s4(2)],[a(2*i-1),a(2*i)]) D3=F+d([s2(1),s2(2)],[a(2*i-1),a(2*i)]);x3=[B,0];else D3=H+d([s4(1),s4(2)],[a(2*i-1),a(2*i)]);x3=[D,0];end%point4if F+d([s2(3),s2(4)],[a(2*i-1),a(2*i)])<H+d([s4(3),s4(4)],[a(2*i-1),a(2*i)]) D4=F+d([s2(3),s2(4)],[a(2*i-1),a(2*i)]);x4=[B,1];else D4=H+d([s4(3),s4(4)],[a(2*i-1),a(2*i)]);x4=[D,1];endendif D1<=D2&&D1<=D3&&D1<=D4x=x1;endif D2<=D1&&D2<=D3&&D2<=D4x=x2;endif D3<=D1&&D3<=D2&&D3<=D4x=x3;endif D4<=D1&&D4<=D2&&D4<=D3x=x4;endfigure(2);subplot(2,1,1);stem(a);grid on;title('Input Code');subplot(2,1,2);stem(x);grid on;title('Output Code after viterbi uncoding');function x=viterbi_encoding(s)r1=0;r2=0;x=[];for i=1:length(s)x(2*i-1)=mod((s(i)+r1+r2),2);x(2*i)=mod((s(i)+r2),2);r2=r1;r1=s(i);endfigure(1);subplot(2,1,1);stem(s);grid on;title('Input Code');subplot(2,1,2);stem(x);grid on;title('Output Code after viterbi encoding');%by 张鹏2010年10月27日%%clc;clear all;s=randint(1,20); %input codea=viterbi_encoding(s); %viterbi encoding%x=[1 0 1 0 0 0 0 1 1 0 1 0 1 0 1 0 0 1 1 1 0 0 1 1];%x=[0 -1 zeros(1,length(a)-2)]+a; %interferingb=viterbi_uncoding(a); %output code after viterbi uncoding(based on Euclid distance)Code:%Euclid distance of x and yfunction z=od(x,y)z=0;x=2*x-1;y=2*y-1;for i=1:length(x)a=(x(i)-y(i))^2;z=z+a;endfunction x=viterbi_encoding(s)r1=0;r2=0;x=[];for i=1:length(s)x(2*i-1)=mod((s(i)+r1+r2),2);x(2*i)=mod((s(i)+r2),2);r2=r1;r1=s(i);endfigure(1);subplot(2,1,1);stem(s);grid on;title('Input Code');subplot(2,1,2);stem(x);grid on;title('Output Code after viterbi encoding');%by 张鹏2010年10月27日function x=viterbi_o_uncoding(a) %viterbi encoding n=length(a);s1=[0 0 1 1]; %two routes of each points2=[1 0 0 1];s3=[1 1 0 0];s4=[0 1 1 0];D1=0;D2=0;D3=0;D4=0; %hamming distances of four route%NO.1 period of input codeD1=od([s1(1),s1(2)],[a(1),a(2)]);x1=[0]; %the uncoding code of each routeD2=od([s1(3),s1(4)],[a(1),a(2)]);x2=[1];%NO.2A=x1;B=x2;C=D1;D=D2;D1=C+od([s1(1),s1(2)],[a(3),a(4)]);x1=[A,0];D2=C+od([s1(3),s1(4)],[a(3),a(4)]);x2=[A,1];D3=D+od([s2(1),s2(2)],[a(3),a(4)]);x3=[B,0];D4=D+od([s2(3),s2(4)],[a(3),a(4)]);x4=[B,1];%NO.3-NO.n/2for i=3:n/2A=x1;B=x2;C=x3;D=x4;E=D1;F=D2;G=D3;H=D4;%point1if E+od([s1(1),s1(2)],[a(2*i-1),a(2*i)])<G+od([s3(1),s3(2)],[a(2*i-1),a(2*i)]) D1=E+od([s1(1),s1(2)],[a(2*i-1),a(2*i)]);x1=[A,0];else D1=G+od([s3(1),s3(2)],[a(2*i-1),a(2*i)]);x1=[C,0];end%point2if E+od([s1(3),s1(4)],[a(2*i-1),a(2*i)])<G+od([s3(3),s3(4)],[a(2*i-1),a(2*i)]) D2=E+od([s1(3),s1(4)],[a(2*i-1),a(2*i)]);x2=[A,1];else D2=G+od([s3(3),s3(4)],[a(2*i-1),a(2*i)]);x2=[C,1];end%point3if F+od([s2(1),s2(2)],[a(2*i-1),a(2*i)])<H+od([s4(1),s4(2)],[a(2*i-1),a(2*i)]) D3=F+od([s2(1),s2(2)],[a(2*i-1),a(2*i)]);x3=[B,0];else D3=H+od([s4(1),s4(2)],[a(2*i-1),a(2*i)]);x3=[D,0];end%point4if F+od([s2(3),s2(4)],[a(2*i-1),a(2*i)])<H+od([s4(3),s4(4)],[a(2*i-1),a(2*i)]) D4=F+od([s2(3),s2(4)],[a(2*i-1),a(2*i)]);x4=[B,1];else D4=H+od([s4(3),s4(4)],[a(2*i-1),a(2*i)]);x4=[D,1];endend%choose the min hamming distance of four routesif D1<=D2&&D1<=D3&&D1<=D4x=x1;endif D2<=D1&&D2<=D3&&D2<=D4x=x2;endif D3<=D1&&D3<=D2&&D3<=D4x=x3;endif D4<=D1&&D4<=D2&&D4<=D3x=x4;endfigure(2);subplot(2,1,1);stem(a);grid on;title('Input Code');subplot(2,1,2);stem(x);grid on;title('Output Code after viterbi uncoding');%by 张鹏2010年10月27日%%clc;clear all;s=randint(1,20); %input codea=viterbi_encoding(s); %viterbi encoding%x=[1 0 1 0 0 0 0 1 1 0 1 0 1 0 1 0 0 1 1 1 0 0 1 1];%x=[0 -1 zeros(1,length(a)-2)]+a; %interferingb=viterbi_o_uncoding(a); %output code after viterbi uncoding。
[说明]维特比算法
![[说明]维特比算法](https://img.taocdn.com/s3/m/d9389b0afbd6195f312b3169a45177232f60e4b4.png)
基于Viterbi 算法的GMSK 信号解调方法的研究摘要:高斯最小频移键控(GMSK )具有振幅恒定、相位连续、带宽窄、带外衰减大和对邻近信道干扰小的特点。
维特比算法是用来寻找最优路径上观察值所属的类别,本文重点研究了GMSK 信号的维特比相干解调算法—基于最大似然函数检测(MLSD )的Viterbi 相干解调,通过信号状态的具体表示及路径度量的计算,运用MA TLAB 仿真绘制出了信号在不同信噪比下的误码率曲线,总结得出改算法具有良好的抗噪性和抗多径性能。
关键字:高斯最小频移键控;Viterbi 算法;最大似然函数检测;误码率一、引言GMSK 高斯滤波的最小频移键控调制,它是在MSK 调制的基础上发展起来的。
MSK 最小频移键控是调制指数为1/2的二进制CPFSK 连续相位频移键控。
MSK 信号的包络恒定、相位连续,且相位在一个码元周期内变化2。
虽然MSK 的功率谱密度在主瓣外衰减较快,但是仍不能满足移动通信对带外衰减的严格要求,为了使信号的功率谱密度更紧凑,带外辐射更小,频带利用率更高,于是在MSK 调制的基础上提出了GMSK 调制方式,即在MSK 调制之前加上一个高斯前置滤波器,从而改善了信号的功率谱特性,缩小带宽,减少带外辐射小和邻近信道干扰,加快带外衰减,使之能达到带外衰减在60dB 以上的通信要求。
GMSK 调制在移动通信领域得到了广泛的应用,成为了数字通信中很有优势的一种调制方式,GMSK 已经在美国蜂窝数字分组数据系统和欧洲全球通系统中得到应用。
目前GMSK 信号的解调方法有很多。
差分解调,主要指一比特差分解调和二比特差分解调,算法原理简单,但是在多径信道的环境下其误码率都比较高。
因为GMSK 调制具有非线性的特点,具有判决反馈或没有反馈的MMSE 相干检测方法是GMSK 系统的次优解调方法,而基于维特比算法的最大似然函数检测是GMSK 系统的最佳接收机,是一种有发展前景的解调方法。
卷积码的维特比译码原理及仿真

卷积码的维特比译码原理及仿真摘 要 本课程设计主要解决对一个卷积码序列进行维特比(Viterbi)译码输出,并通过Matlab 软件进行设计与仿真,并进行误码率分析。
实验原理QPSK :QPSK 是英文QuadraturePhaseShiftKeying 的缩略语简称,意为正交相移键控,是一种数字调制方式。
四相相移键控信号简称“QPSK ”。
它分为绝对相移和相对相移两种。
卷积码:又称连环码,是由伊莱亚斯(P.elias)于1955年提出来的一种非分组码。
积码将k 个信息比特编成n 个比特,但k 和n 通常很小,特别适合以串行形式进行传输,时延小。
卷积码是在一个滑动的数据比特序列上进行模2和操作,从而生成一个比特码流。
卷积码和分组码的根本区别在于,它不是把信息序列分组后再进行单独编码,而是由连续输入的信息序列得到连续输出的已编码序列。
卷积码具有误码纠错的能力,首先被引入卫星和太空的通信中。
NASA 标准(2,1,6)卷积码生成多项式为: 346134562()1()1g D D D D D g D D D D D=++++=++++其卷积编码器为:图1.1 K=7,码率为1/2的卷积码编码器维特比译码:采用概率译码的基本思想是:把已接收序列与所有可能的发送序列做比较,选择其中码距最小的一个序列作为发送序列。
如果接收到L 组信息比特,每个符号包括v 个比特。
接收到的Lv 比特序列与2L 条路径进行比较,汉明距离最近的那一条路径被选择为最有可能被传输的路劲。
当L 较大时,使得译码器难以实现。
维特比算法则对上述概率译码做了简化,以至成为了一种实用化的概率算法。
它并不是在网格图上一次比较所有可能的2kL 条路径(序列),而是接收一段,计算和比较一段,选择一段最大似然可能的码段,从而达到整个码序列是一个最大似然值得序列。
下面以图2.1的(2,1,3)卷积码编码器所编出的码为例,来说明维特比解码的方法和运作过程。
维特比算法例题

维特比算法例题维特比(Viterbi)算法是一种动态规划算法,常用于隐马尔可夫模型(HMM)中的路径搜索问题。
以下是一个简单的维特比算法的例子:假设有一个简单的HMM,包含两个状态(状态1和状态2),以及两个观测序列(观测1和观测2)。
状态转移概率如下:P(状态1→状态1) = 0.7P(状态1→状态2) = 0.3P(状态2→状态1) = 0.4P(状态2→状态2) = 0.6观测概率如下:P(观测1|状态1) = 0.5P(观测1|状态2) = 0.5P(观测2|状态1) = 0.4P(观测2|状态2) = 0.6现在我们要找出最有可能的状态序列,使得观测序列的概率最大。
首先,我们需要计算每个状态在每个时刻的概率。
这可以通过以下公式计算:P(状态i, t) = P(观测t|状态i) * P(状态i, t-1)其中,P(观测t|状态i)是观测概率,P(状态i, t-1)是上一个时刻的状态概率。
然后,我们需要找出最有可能的状态序列。
这可以通过以下公式计算:P(最优, t) = max P(状态i, t) * P(状态i→状态j)其中,P(最优, t)是在时刻t的最有可能的状态概率,P(状态i, t)是在时刻t的状态i的概率,P(状态i→状态j)是从状态i转移到状态j的概率。
最后,我们可以通过回溯算法找出最有可能的状态序列。
回溯算法是一种通过逐步回溯搜索树来找出最有可能的解的算法。
具体来说,我们从最后一个时刻开始向前回溯,找出最有可能的状态,然后继续向前回溯,直到找到最有可能的初始状态。
以上是一个简单的维特比算法的例子,希望能帮助您理解该算法的基本原理和应用。
维特比算法详解

维特比算法详解维特比算法是一种常用的动态规划算法,主要用于解决概率图模型中的推断问题。
它在自然语言处理、语音识别、机器翻译等领域有着广泛的应用。
本文将详细介绍维特比算法的原理和应用。
维特比算法的核心思想是利用动态规划的思想,通过递推的方式来计算概率图模型中的最优路径。
它主要用于解决隐马尔可夫模型(Hidden Markov Model,HMM)中的解码问题。
隐马尔可夫模型是一种统计模型,它描述了一个由隐藏的马尔可夫链随机生成观测序列的过程。
在隐马尔可夫模型中,我们无法直接观测到隐藏状态,只能观测到与隐藏状态相关的观测值。
在维特比算法中,我们需要求解的是给定一个观测序列,找出最有可能生成该观测序列的隐藏状态序列。
为了简化问题,我们假设隐藏状态是一个离散的随机变量,观测值也是一个离散的随机变量。
我们用S表示隐藏状态的集合,用O表示观测值的集合。
隐马尔可夫模型可以由初始状态概率向量π、状态转移概率矩阵A和观测概率矩阵B来完全描述。
维特比算法的核心是定义一个Viterbi变量δ和一个回溯指针ψ。
其中,δ[t][i]表示在时刻t处于状态i的最大概率,并且生成观测序列O[1:t]的最优路径的概率;ψ[t][i]表示在时刻t处于状态i时,生成观测序列O[1:t]的最优路径上时刻t-1所处状态的索引。
维特比算法的递推公式如下:δ[t][i] = max(δ[t-1][j] * a[j][i] * b[i][o[t]]),其中j∈Sψ[t][i] = argmax(δ[t-1][j] * a[j][i]),其中j∈S根据递推公式,我们可以从t=1开始逐步计算δ和ψ。
在计算过程中,我们需要保存每个时刻t对应的最大概率和回溯指针。
最后,我们可以通过回溯指针找到生成观测序列O[1:T]的最优路径。
维特比算法的时间复杂度为O(TN^2),其中T为观测序列的长度,N为隐藏状态的个数。
由于维特比算法基于动态规划的思想,可以有效地解决具有大规模状态空间的问题。
“维特比”(Viterbi)算法

隐马尔可夫模型中的Viterbi算法2008年1月24日这篇文章简单描述一下Viterbi算法——一年之前我听过它的名字,直到两周之前才花了一点时间研究了个皮毛,在这里做个简单检讨。
先用一句话来简单描述一下:给出一个观测序列o1,o2,o3 …,我们希望找到观测序列背后的隐藏状态序列s1, s2, s3, …;Viterbi以它的发明者名字命名,正是这样一种由动态规划的方法来寻找出现概率最大的隐藏状态序列(被称为Viterbi路径)的算法。
这里需要抄一点有关隐马可夫序列(HMM,Hidden Markov Model)的书页来解释一下观测序列和隐藏状态序列。
首先从最简单的离散Markov过程入手,我们知道,Markov随机过程具有如下的性质:在任意时刻,从当前状态转移到下一个状态的概率与当前状态之前的那些状态没有关系。
所以,我们可以用一个状态转移概率矩阵来描述它。
假设我们有n个离散状态S1, S2,…Sn,我们可以构造一个矩阵A,矩阵中的元素aij表示从当前状态Si下一时刻迁移到Sj状态的概率。
但是在很多情况下,Markov模型中的状态是我们观察不到的。
例如,容器与彩球的模型:有若干个容器,每个容器中按已知比例放入各色的彩球(这样,选择了容器后,我们可以用概率来预测取出各种彩球的可能性);我们做这样的实验,实验者从容器中取彩球——先选择一个容器,再从中抓出某一个球,只给观察者看球的颜色;这样,每次取取出的球的颜色是可以观测到的,即o1, o2,…,但是每次选择哪个容器是不暴露给观察者的,容器的序列就组成了隐藏状态序列S1, S2,…Sn。
这是一个典型的可以用HMM描述的实验。
HMM有几个重要的任务,其中之一就是期望通过观察序列来猜测背后最有可能的隐藏序列。
在上面的例子中,就是找到我们在实验中最有可能选择到的容器序列。
Viterbi正是用来解决这个问题的算法。
HMM另外两个任务是:a) 给定一个HMM,计算一个观测序列出现的可能性;b)已知一个观测序列,HMM参数不定,如何优化这些参数使得观测序列的出现概率最大。
卷积码编码和维特比译码的原理、性能与仿真分析

卷积码编码和维特比译码的原理、性能与仿真分析1.引言卷积码的编码器是由一个有k位输入、n位输出,且具有m位移位寄存器构成的有限状态的有记忆系统,通常称它为时序网络。
编码器的整体约束长度为v,是所有k个移位寄存器的长度之和。
具有这样的编码器的卷积码称作[n,k,v]卷积码。
对于一个(n,1,v)编码器,约束长度v等于存储级数m.卷积码是由k个信息比特编码成n(n>k)比特的码组,编码出的n比特码组值不仅与当前码字中的k个信息比特值有关,而且与其前面v个码组中的v*k个信息比特值有关。
卷积码有三种译码方式:序列译码、门限译码和概率译码。
其中,概率译码根据最大似然译码原理在所有可能路径中求取与接收路径最相似的一条路径,具有最佳的纠错性能,维特比译码是概率译码中极重要的一种方式。
序列译码和门限译码则不一定能找出与接收路径最相似的一条路径。
不同于维特比译码,门限译码与序列译码所需的计算量是可变的且对于给定信息分组的最终判决仅仅基于(m+1)个接收分组,而不是基于整个接收序列。
与维特比译码所使用的对数似然量度不同,序列译码所使用的量度为Fano量度。
在接收序列受扰严重的情况下,序列译码的计算量大于维特比译码所需的固定计算量,虽然序列译码要求的平均计算次数通常小于维特比译码。
在采用并行处理的情况下,维特比译码的速度会优于序列译码。
在同样码率和存储级数的条件下,门限译码的性能比维特比译码低大约3dB.维特比译码的数据输出方式有硬判决及软判决两种方式,本文选取生成多项式为561,753的(2,1,8)卷积码对硬判决的性能进行分析,并依据维特比译码的原理以及卷积码的特性,对卷积码编码和维特比译码过程在加性高斯白噪声(AWGN)信道下进行仿真,并且根据仿真结果对维特比译码(硬判决)的结果进行分析。
由于卷积码的生成可以看做一个马尔科夫过程,因此,不同状态间的转移概率对描述这个过程有极关键的作用。
本文则基于MATLAB对不同状态间的转移概率进行求解,从而更准确地分析维特比译码的性能。
维特比算法(Viterbi)及python实现样例

维特⽐算法(Viterbi)及python实现样例维特⽐算法(Viterbi)维特⽐算法维特⽐算法shiyizhong 动态规划算法⽤于最可能产⽣观测时间序列的-维特⽐路径-隐含状态序列,特别是在马尔可夫信息源上下⽂和隐马尔科夫模型中。
术语“维特⽐路径”和“维特⽐算法”也被⽤于寻找观察结果最有可能解释的相关dongtai 规划算法。
例如在统计句法分析中动态规划可以被⽤于发现最有可能的上下⽂⽆关的派⽣的字符串,有时被称为“维特⽐分析”。
利⽤动态规划寻找最短路径动态规划是运筹学的⼀个分⽀,是求解决策过程最优化的数学⽅法,通常情况下应⽤于最优化的问题,这类问题⼀般有很多可⾏的解,每个解有⼀个值,⽽我们希望从中找到最优的答案。
在计算机科学领域,应⽤动态规划的思想解决的最基本的⼀个问题就是:寻找有向⽆环图(篱笆⽹络)当中两个点之间的最短路径(实际应⽤于地图导航、语⾳识别、分词、机器翻译等等)下⾯举⼀个⽐较简单的例⼦做说明:求S到E的最短路径,如下图(各点之间距离不相同):我们知道,要找到S到E之间最短路径,最容易想到的⽅法就是穷举法。
也就是把所有可能的路径都例举出来。
从S⾛向A层共有4种⾛法,从A层⾛向B层⼜有4种⾛法,从B层⾛向C层⼜有4种⾛法,然后C层⾛向E点只有⼀种选择。
所以最终我们穷举出了4*4*4=64种可能。
显然,这种⽅法必定可⾏,但在实际的应⽤当中,对于数量及其庞⼤的节点数和边数的图,其计算复杂度也将会变得⾮常⼤,⽽计算效率也会随之降低。
因此,这⾥选择适⽤⼀种基于动态规划的⽅式来寻找最佳路径。
所谓动态规划。
其核⼼就是“动态”的概念,把⼤的问题细分为多个⼩的问题,基于每⼀步的结果再去寻找下⼀步的策略,通过每⼀步⾛过之后的局部最优去寻找全局最优,这样解释⽐较抽象,下⾯直接⽤回刚刚的例⼦说明。
如下图:⾸先,我们假设S到E之间存在⼀条最短路径(红⾊),且这条路径经过C2点,那么我们便⼀定能够确定从S到C2的64条(4*4*4=64)⼦路经当中,该⼦路经⼀定最短。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
这篇文章简单描述一下Viterbi算法——一年之前我听过它的名字,直到两周之前才花了一点时间研究了个皮毛,在这里做个简单检讨。
先用一句话来简单描述一下:给出一个观测序列o1,o2,o3 …,我们希望找到观测序列背后的隐藏状态序列s1, s2, s3, …;Viterbi以它的发明者名字命名,正是这样一种由动态规划的方法来寻找出现概率最大的隐藏状态序列(被称为Viterbi路径)的算法。
这里需要抄一点有关隐马可夫序列(HMM,Hidden Markov Model)的书页来解释一下观测序列和隐藏状态序列。
首先从最简单的离散Markov过程入手,我们知道,Markov随机过程具有如下的性质:在任意时刻,从当前状态转移到下一个状态的概率与当前状态之前的那些状态没有关系。
所以,我们可以用一个状态转移概率矩阵来描述它。
假设我们有n个离散状态S1, S2,…Sn,我们可以构造一个矩阵A,矩阵中的元素aij表示从当前状态Si下一时刻迁移到Sj状态的概率。
但是在很多情况下,Markov模型中的状态是我们观察不到的。
例如,容器与彩球的模型:有若干个容器,每个容器中按已知比例放入各色的彩球(这样,选择了容器后,我们可以用概率来预测取出各种彩球的可能性);我们做这样的实验,实验者从容器中取彩球——先选择一个容器,再从中抓出某一个球,只给观察者看球的颜色;这样,每次取取出的球的颜色是可以观测到的,即o1, o2,…,但是每次选择哪个容器是不暴露给观察者的,容器的序列就组成了隐藏状态序列S1, S2,…Sn。
这是一个典型的可以用HMM描述的实验。
HMM有几个重要的任务,其中之一就是期望通过观察序列来猜测背后最有可能的隐藏序列。
在上面的例子中,就是找到我们在实验中最有可能选择到的容器序列。
Viterbi正是用来解决这个问题的算法。
HMM另外两个任务是:a) 给定一个HMM,计算一个观测序列出现的可能性;b)已知一个观测序列,HMM参数不定,如何优化这些参数使得观测序列的出现概率最大。
解决前一个问题可以用与Viberbi结构非常类似的Forward算法来解决(实际上在下面合二为一),而后者可以用Baum-Welch/EM算法来迭代逼近。
从Wiki上抄一个例子来说明Viterbi算法。
假设你有一个朋友在外地,每天你可以通过电话来了解他每天的活动。
他每天只会做三种活动之一——Walk, Shop, Clean。
你的朋友从事哪一种活动的概率与当地的气候有关,这里,我们只考虑两种天气——Rainy, Sunny。
我们知道,天气与运动的关系如下:Rain y Sunn yWalk0.1 0.6 Shop0.4 0.3 Clean0.5 0.1例如,在下雨天出去散步的可能性是0.1。
而天气之前互相转换的关系如下,(从行到列)Rain y Sunn yRainy0.7 0.3Sunny0.4 0.6例如,从今天是晴天而明天就开始下雨的可能性是0.4 。
同时为了求解问题我们假设初始情况:通话开始的第一天的天气有0.6的概率是Rainy,有0.4概率是Sunny。
OK,现在的问题是,如果连续三天,你发现你的朋友的活动是:Walk->Shop->Clean;那么,如何判断你朋友那里这几天的天气是怎样的?解决这个问题的python伪代码如下:def forward_viterbi(obs, states, start_p, trans_p, emit_p):T = {}for state in states:## prob. V. path V. prob.T[state] = (start_p[state], [state],start_p[state])for output in obs:U = {}for next_state in states:total = 0argmax = Nonevalmax = 0for source_state in states:(prob, v_path, v_prob) =T[source_state]p = emit_p[source_state][output] * trans_p[source_state][next_state]prob *= pv_prob *= ptotal += probif v_prob > valmax:argmax = v_path + [next_state]valmax = v_probU[next_state] = (total, argmax, valmax) T = U## apply sum/max to the final states:total = 0argmax = Nonevalmax = 0for state in states:(prob, v_path, v_prob) = T[state]total += probif v_prob > valmax:argmax = v_pathvalmax = v_probreturn (total, argmax, valmax)几点说明:1.算法对于每一个状态要记录一个三元组:(prob, v_path, v_prob),其中,prob是从开始状态到当前状态所有路径(不仅仅是最有可能的viterbi路径)的概率加在一起的结果(作为算法附产品,它可以输出一个观察序列在给定HMM下总的出现概率,即forward算法的输出),v_path是从开始状态一直到当前状态的viterbi路径,v_prob则是该路径的概率。
2.算法开始,初始化T (T是一个Map,将每一种可能状态映射到上面所说的三元组上)3.三重循环,对每个一活动y,考虑下一步每一个可能的状态next_state,并重新计算若从T中的当前状态state跃迁到next_state概率会有怎样的变化。
跃迁主要考虑天气转移(tp[source_state][next_state])与该天气下从事某种活动(ep[source_state][output])的联合概率。
所有下一步状态考虑完后,要从T中找出最优的选择viterbi路径——即概率最大的viterbi路径,即上面更新Map U的代码U[next_state] = (total, argmax, valmax)。
4.算法最后还要对T中的各种情况总结,对total求和,选择其中一条作为最优的viterbi路径。
5.算法输出四个天气状态,这是因为,计算第三天的概率时,要考虑天气转变到下一天的情况。
6.通过程序的输出可以帮助理解这一过程:observation=Walknext_state=Sunnystate=Sunnyp=0.36triple=(0.144,Sunny->,0.144)state=Rainyp=0.03triple=(0.018,Rainy->,0.018)Update U[Sunny]=(0.162,Sunny->Sunny->,0.144) next_state=Rainystate=Sunnyp=0.24triple=(0.096,Sunny->,0.096)state=Rainyp=0.07triple=(0.042,Rainy->,0.042)Update U[Rainy]=(0.138,Sunny->Rainy->,0.096) observation=Shopnext_state=Sunnystate=Sunnyp=0.18triple=(0.02916,Sunny->Sunny->,0.02592)state=Rainyp=0.12triple=(0.01656,Sunny->Rainy->,0.01152) UpdateU[Sunny]=(0.04572,Sunny->Sunny->Sunny->,0.025 92)next_state=Rainystate=Sunnytriple=(0.01944,Sunny->Sunny->,0.01728)state=Rainyp=0.28triple=(0.03864,Sunny->Rainy->,0.02688) UpdateU[Rainy]=(0.05808,Sunny->Rainy->Rainy->,0.02688 )observation=Cleannext_state=Sunnystate=Sunnyp=0.06triple=(0.0027432,Sunny->Sunny->Sunny->,0.00155 52)state=Rainyp=0.15triple=(0.008712,Sunny->Rainy->Rainy->,0.004032) UpdateU[Sunny]=(0.0114552,Sunny->Rainy->Rainy->Sunn y->,0.004032)next_state=Rainystate=Sunnytriple=(0.0018288,Sunny->Sunny->Sunny->,0.00103 68)state=Rainyp=0.35triple=(0.020328,Sunny->Rainy->Rainy->,0.009408) UpdateU[Rainy]=(0.0221568,Sunny->Rainy->Rainy->Rainy ->,0.009408)finaltriple=(0.033612,Sunny->Rainy->Rainy->Rainy->,0. 009408)所以,最终的结果是,朋友那边这几天最可能的天气情况是Sunny->Rainy->Rainy->Rainy,它有0.009408的概率出现。
而我们算法的另一个附带的结论是,我们所观察到的朋友这几天的活动序列:Walk->Shop->Clean在我们的隐马可夫模型之下出现的总概率是0.033612。
参考文献1./Faculty/Rabiner/ece259/Reprints/tutorial%20on%20hmm%20and%20applications.pdf2./wiki/Viterbi_algorithm3./2006/04/blog-post_17.html附:c++主要代码片断void forward_viterbi(const vector<string> & ob, viterbi_triple_t & vtriple){//aliasmap<string, double>& sp = start_prob;map<string, map<string, double> > & tp = transition_prob;map<string, map<string, double> > & ep = emission_prob;// initializationInitParameters();map<string, viterbi_triple_t> T;for (vector<string>::iterator it = states.begin();it != states.end();++it){viterbi_triple_t foo;foo.prob = sp[*it];foo.vpath.push_back(*it);foo.vprob = sp[*it];T[*it] = foo;}map<string, viterbi_triple_t> U;double total = 0;vector<string> argmax;double valmax = 0;double p = 0;for (vector<string>::const_iterator itob = ob.begin(); itob != ob.end(); ++itob){cout << “observation=”<< *itob << endl;U.clear();for (vector<string>::iterator itNextState = states.begin();itNextState != states.end();++itNextState){cout << “\tnext_state=”<< *itNextState << endl;total = 0;argmax.clear();valmax = 0;for (vector<string>::iterator itSrcState = states.begin();itSrcState != states.end();++itSrcState){cout << “\t\tstate=”<< *itSrcState << endl;viterbi_triple_t foo = T[*itSrcState];p = ep[*itSrcState][*itob] * tp[*itSrcState][*itNextState];cout << “\t\t\tp=”<< p << endl;foo.prob *= p;foo.vprob *= p;cout << “\t\t\ttriple=”<< foo << endl;total += foo.prob;if (foo.vprob > valmax){foo.vpath.push_back(*itNextState);argmax = foo.vpath;valmax = foo.vprob;}}U[*itNextState] = viterbi_triple_t(total, argmax, valmax);cout << “\tUpdate U[" << *itNextState << "]=”<< U[*itNextState]<< “”<< endl;}T.swap(U);}total = 0;argmax.clear();valmax = 0;for (vector<string>::iterator itState = states.begin();itState != states.end();++itState){viterbi_triple_t foo = T[*itState];total += foo.prob;if (foo.vprob > valmax){argmax.swap(foo.vpath);valmax = foo.vprob;}}vtriple.prob = total;vtriple.vpath = argmax;vtriple.vprob = valmax;cout << “final triple=”<< vtriple << endl;}。