H a r b i n I n s t i t u t e o f T e c h n o l o g y信息论与编码实验报告实验名称:循环码二步大数逻辑译码原理实验院系:电子与信息工程学院通信工程系班级:10硕通信一班姓名:学号:设计时间:2010-11-20哈尔滨工业大学一、 实验内容已知一个(7,4)系统循环码的生成多项式为g x =x 3+x +1,设计基于此生成多项式的大数逻辑译码器。
二、 实验原理2.1 多项式的除法电路本实验的输入为串行数据,因而只考虑串行数据的除法电路。
假设多项式r x =r n x n +r n −1x n−1+⋯+r 1x +r 0,g x =g r x r +g r−1x r−1+⋯+g 1x +g 0,且有r ≤n ,则r x 除以g x 的除法电路的一般形式如图1。
图1多项式除法的一般电路图1中,输入序列按r n −1r n …r 0的顺序输入,右上方的输出为商多项式,待r 0输入结束后,各寄存器中的数据为余式多项式。
在二进制的情况下,模2加法等效于模2减法,且g x 的系数只可能为0或1,因而除法电路可进一步简化,例如,g x =x 3+x +1对应的除法电路如图2所示。
图2 除式为g x =x 3+x +1的除法电路在本实验中,只对余式感兴趣,在输入序列完毕后,余式为s x =s 2x 2+s 1x +s 0。
2.2 循环码的译码原理假设系统循环码的生成多项式为g x =g r x r +g r−1x r−1+⋯+g 1x +g 0,接收到的一组循环码字的多项式表示为r x =r n x n +r n −1x n−1+⋯+r 1x +r 0,则按照以下方法译码:i) 求r x 除以g x 的余式s x ,定义此余式为校验子多项式。
ii) 根据校验子多项多生成错误图样e x 。
iii) e x+r x=c x即为译码结果。
这里不讨论循环码的纠检错能力,(7,4)系统循环码可以纠正一位错。
根据第ii步所用的方法不同,循环码的译码方法有梅吉特译码、捕错译码及大数译码等方法。
2.3大数译码原理实际上,无论是梅吉特译码器,捕错译码器还是大数译码器,都用到了循环码的一个重要性质:如果s x为接收码字多项式r x的校验子多项式,则xs x[模g x]也必然是xr x[模x n+1]的校验子多项式。
每个校验子多项式对应一种错误图样。
循环码本身的定义就表明了xr x[模x n+1]也对应一个许用码字(在无错的情况下),这就意味着,如果一个校验子对应的错误图样可以纠正一位错,那么就可以通过上述运算纠正这个码字中的所有一位错的情况。
下面以本实验的实验内容来构造大数逻辑译码器。
(7,4)系统循环码的码字长度为7,收到的码字为r x。
错误图样e=[1000000]可以纠正码字r6,假设此错误图样对应的校验子多项式为s6x,则可以通过以下运算来纠正码字r5(假设只有一位错):i) 通过除法电路得到校验子多项式s x。
ii) 做运算s5x=xs x[模g x]。
iii) 如果s5x等于s6x,则证明码字r5有错,否则无错。
依照这样的方法可以依次纠正其余码字。
在图2中,当输入为零时,就相当进行了运算xs x[模g x]。
现在问题转化为,如何根据验子多项式为s6x纠正码字r6?亦即如何根据s6x的系数s0s1s2纠正码字r6?考虑循环码一致监督矩阵与校验子向量、错误图样之间的关系:S T=H R T=H E T式中S为校验子向量,H为监督矩阵,E错误图样向量。
生成多项式为g x=x3+x+1的一致监督矩阵为:H=1110100 0111010 1101001代入上式,并将S及E展开可得:s2s1 s0=111010001110101101001e6e5e4e3e2e1e0于是,得到以下关系式:s2=e6+e5+e4+e2s1=e5+e4+e3+e1s0=e6+e5+e3+e0记A11=s1+s0=e6+e4+e1+e0A12=s2=e6+e4+e5+e2A21=s2=e6+e5+e4+e2A22=s0=e6+e5+e3+e0上式中用到了模二加的性质e+e=0。
再记A1=A11 & A12=e6+e4A2=A21 & A22=e6+e5式中符号&表示与操作,并且假设e i,i=0…6最多只能有一位等于1,即接收码字只可能为无错或有一位错。
显然,只有当A1与A2均为1的情况下,可以知道e6=1,否则一定有e6=0,但不能确定e i,i=0…5的情况。
最后,结合图2的除法电路及上面的分析,可以得到生成多项式为g x=x3+x+ 1的(7,4)系统循环码的大数逻辑译码电路图,如图3所示。
图3 生成多项式为g x=x3+x+1的循环码大数逻辑译码电路图3中,各寄存器的初始状态为零,在前7个时钟周期,接收码字序列r6r5 0次进入系统,输出为7个零。
寄存器S0、S1、S2保存此时的校验子多项式的系数,如果A1、A2与操作结果为1,表明接收到的码字最高位即r6有错,在下一个时钟周期就可以对r6进行纠错。
在后7个时间周期,电路输入为7个零,输出为译码结果。
因此,整个系统需要14个时钟周期才能完成一个码字的译码。
因为经过两级逻辑运算才得到错误结果,因此称上面的电路为二步大数逻辑译码电路。
为了达到连续译码的目的,图中增加了虚线所示的反馈,在检测到错误后,这个反馈可以将寄存器S0、S1、S2清零,虚线只在后7个时钟周期有效。
此外需要说明的是寄存器D的作用:在第7个时钟周期后,A1、A2相与的结果已经出现,标志着r6的错误情况,但此时r6在7级移位寄存器中,因此将A1、A2相与的结果延时一个时钟周期方可正确译码。
另一种解决方法是将7级移位寄存器改为6级。
事实上,图3中,只有当S0=1,S1=0,S2=1时,组合逻辑电路部分才输出1,即有错误发生,如果将组合逻辑电路部分换为一个“101”识别器,就构成了梅吉特译码器。
三、实验环境及设计工具3.1 实验环境操作系统:Windows XP SP2简体中文版运行环境:.NET Framework 2.03.2设计工具本实验程序使用C#语言编写译码过程及交互界面,所用开发工具为SharpDevelop 3.2;使用gnuplot 4.4绘制码元的波形图。
四、设计方法4.1模块/单元设计二步大数逻辑译码器实验程序由三部分组成:界面及控制模块、译码器单元和波形生成模块。
各部分关系如图4。
图4 二步大数逻辑译码器实验程序组成由于采用了面向对象的设计方法,因而用类来描述程序更为方便。
图4中,界面显示及主控制对应的类为MainForm,除负责整个程序的逻辑控制外,还要读取用户输入的数据及指令、显示译码结果。
在良好的程序设计中各模块之间是松耦合的,为此,MainForm并不涉及对译码过程的任何操作,它将收到的码字R x传递给译码器单元执行,然后从译码器单元读取操作结果。
译码器单元对应的类为Decoder,该类完成(7,4)循环码序列的译码。
Decoder类存储译码过程中各寄存器及组合电路输出的状态,供MainForm类查询。
此外,MainForm 类每下一次译码指令,Decoder就进行一位码元的输入,也就对应时序电路中的一次时钟输入。
(7,4)循环码的一个码字长度为7,根据大数逻辑译码的电路原理图可知,在14个时间周期后,方可完成一个码字的译码,因而Decoder在接收14次指令后将标志本次结果有效。
波形生成器对应的类为GnuplotWrapper。
这个类对工具gnuplot进行简单的封装,根据输入的接收码字R x、译码结果C x及错误图样E x,生成二进制码元波形图,结果以png图形格式存储。
MainForm类负责显示该波形图。
4.2译码器单元设计译码器的工作过程为:接收任意长度的(7,4)循环码码字序列,在每7个码元后插入7个0码;然后,每接收到一条来自MainForm的译码指令,就将一位码元输入到程序所模拟的电路中;在第14个指令后,译码器修改其状态,表明此时一个码字译码完毕,结果有效。
图5 Decoder类的属性、方法图5给出了类Decoder的组成。
在这个类中,用整型变量模拟二进制码元0或1(C#语言中没有位类型)。
属性S0、S1、S2分别保存某一时刻寄存器S0、S1、S2的状态;属性A11、A12、A21、A22、A1、A2也分别对应第2.3节对校验子系数S0、S1、S2进行逻辑运算的结果;一个IsResultV alid属性指示当前结果是否有效。
Decoder类用先进先出(FIFO)的队列模拟移位寄存器,输入和输出也可以用移位寄存器来保存数据,因此输入与输出也有相应的队列。
队列的操作包含入列和出列,这两个操作的组合就可以模拟移位寄存器的一次移位操作。
buffer队列保存图3中7级移位寄存器的值;currentCode保存当前正在被翻译的码字;receivedCode保存输入的任意长度的码字序列;result队列保存译码结果;error队列保存错误图样。
Decoder类的方法包括Received,reset,Next和Calculate,最后一个Decoder为构造函数。
本程序的核心方法为Next与Calculate,两者的联合工作流程如图6所示,它对应2.3节讨论的译码过程。
图5 Decoder类的译码过程流程图Calculate方法中进行译码运算,Next方法维护一个计数器,也维护一个状态来指示当前译码的阶段。
本程序将译码过程分为两个阶段,第一个阶段为Buffering阶段,此时输入为接收码元,输出为零,且无反馈输入;第二个阶段为Decoding阶段,此时输入为零,且有反馈输入,输出为译码结果。
4.3界面设计界面使用Windows Forms框架设计,如图6所示。
用户输入接收到的循环码字序列,然后点击“开始译码”开始单步译码。
左方显示各寄存器级组合电路的状态,在译码完成后,右下方显示接收码字、译码结果及错误情况的波形图。
本实验程序支持连续译码。
图6 循环码译码实验程序界面五、部分程序代码5.1Decoder类源代码1using System;2using System.Collections.Generic;34namespace CCDecoder5{6/// <summary>7/// (7,4)循环码二步大数逻辑译码器,可连续译码8/// </summary>9public class Decoder10{11#region constructors12public Decoder() { }13#endregion1415#region properties16public Queue<int> receivedCode{private set;get;}//接收到的码字,长度可大于7 17public Queu e<in t> buffe r{private se t;ge t;} //7级移位寄存器18public Queue<int> result{private set;get;} //译码结果,长度为719public Queue<int> error{private set;get;} //错误图样,长度为720public Queue<int> currentCode{private set;get;}//当前被译的码字,长度为7 21public bool IsResultValid{private set;get;} //C(x),E(x)有效标志22public int S0 {private set;get;} //寄存器S023public int S1 {private set;get;} //寄存器S124public int S2 {private set;get;} //寄存器S225public int A11 {private set;get;} //A11=S1'+S0'26public int A12 {private set;get;} //A12=S2'27public int A21 {private set;get;} //A21=S2'28public int A22 {private set;get;} //A22=S0'29public int A1 {private set;get;} //A1=A11+A1230public int A2 {private set;get;} //A2=A21+A2231#endregion3233#region private fields34int counter; //内部计数器35DecodingPhase phase; //当前译码的状态,分为两个阶段:Buffering和Decoding 36#endregion3738#region public methods39public void reset() //程序复位,将各个寄存器及中间结果清零40{41counter = 0;42IsResultValid = false;43receivedCode = new Queue<int>();44currentCode = new Queue<int>();45result = new Queue<int>(new int[]{0,0,0,0,0,0,0});46error = new Queue<int>(new int[]{0,0,0,0,0,0,0});47buffer = new Queue<int>(new int[]{0,0,0,0,0,0,0});48A11 = 0;49A12 = 0;50A21 = 0;51A22 = 0;52A1 = 0;53A2 =0;54S0 = 0;55S1 = 0;56S2 = 0;57}5859public bool Next() //进行一次译码操作60{61counter = counter + 1;6263if (counter == 1)64{65IsResultValid = false;66currentCode.Clear();67}6869if (counter <= 7) //译码第一阶段:Buffering70{71phase = DecodingPhase.Buffering;72if (receivedCode.Count == 0) return false; //译码完毕73}74else //译码第二阶段:Decoding75{76phase = DecodingPhase.Decoding;77}78Calculate(receivedCode.Dequeue());7980if (counter == 14) //译完一个码字,标志结果有效81{82counter = 0;83IsResultValid = true;84}85return true;86}8788public void Received(List<int> Code) //接收到码字,进行初始化处理89{90reset();91receivedCode=new Queue<int>();92int i;93for(i=0;i<Code.Count;i++) //在每7个码元后添加7个零94{95if(i!=0 && i%7==0)96for(int j=0;j<7;j++) receivedCode.Enqueue(0);97receivedCode.Enqueue(Code[i]);98}99if(i!=0 && i%7==0)100for(int j=0;j<7;j++) receivedCode.Enqueue(0);101}102103private void Calculate(int input) //一个时钟周期所需要的操作104{105int S0_p,S1_p,S2_p,E_p; //暂存S0,S1,S2,A1&A2的值106107S0_p = S0;108S1_p = S1;109S2_p = S2;110E_p = A1 & A2;111112if(phase == DecodingPhase.Buffering)113{114S0 = input ^ S2_p; //在Buffering阶段115currentCode.Enqueue(input); //S0=input+S2'116}117else118{ //在Decoding阶段119S0 = S2_p ^ E_p; //S0=S2+(A1+A2)120}121122S1 = S0_p ^ S2_p; //S1=S0'+S2'123S2 = S1_p; //S2=S1'124A11 = S1 ^ S0; //A11=S1'+S0'125A12 = S2; //A12=S2'126A21 = S2; //A21=S2'127A22 = S0; //A22=S0'128A1 = A11 & A12; //A1=A11+A12129A2 = A21 & A22; //A2=A21+A22130131buffer.Enqueue(input); //7级移位寄存器移出一位码元132result.Enqueue(buffer.Dequeue() ^ E_p);//移出的码元与(A1+A2)模2加133result.Dequeue();134error.Enqueue(E_p); //错误图样寄存器移入一位码元135error.Dequeue(); //错误图样寄存器移出一位码元136}137#endregion138139public enum DecodingPhase{Buffering,Decoding}140}141}5.2GnuplotWrapper类源代码1using System;2using System.IO;3using System.Collections.Generic;4using System.Diagnostics;56namespace CCDecoder7{8/// <summary>9/// gnuplot封装类10/// </summary>11public class GnuplotWrapper12{13public GnuplotWrapper(Decoder decoder)14{15this.decoder=decoder;16}1718private Decoder decoder;1920public string GetImagePath() //获取所生成图形的文件名21{22GenerateDataFile(); //生成波形图23Process process=new Process();24process.StartInfo.FileName=@"gnuplot\gnuplot.exe";25process.StartInfo.Arguments="script.txt";26process.Start();27process.WaitForExit();28return "result.png";29}3031private void GenerateDataFile()32{33List<int> code=new List<int>(decoder.currentCode);34List<int> result=new List<int>(decoder.result);35List<int> error=new List<int>(decoder.error);3637using(StreamWriter sw=new StreamWriter("data.txt",false)) 38{39sw.Write("{0} {1} {2}\n\r",code[0].ToString(),result[0].ToString(),error[0].ToString()); //写入文件40for(int i=0;i<7;i++)41{42sw.Write("{0} {1}{2}\n\r",code[i].ToString(),result[i].ToString(),error[i].ToString());43}44}45}46}47}5.3Gnuplot生成波形所用的脚本1#Gnuplot生成码元图形的脚本2reset3set terminal png #设置输出格式为png图形格式4set output "result.png" #设置输出文件名为result.png5set multiplot6set noborder7set grid xtics8set size 1,0.3333910#画R(x)波形图11set origin 0.0,0.666612unset label13unset key14set ylabel "R(x)"15set ytics 0,1,116set xtics ("" 0,"" 1,"" 2,"" 3,"" 4,"" 5,"" 6,"" 7)17plot "data.txt" using 1 linetype 7 linewidth 4 with fsteps1819#画C(x)波形图20set origin 0.0,0.333321unset label22unset key23set ytics 0,1,124set ylabel "C(x)"25plot "data.txt" using 2 linetype 10 linewidth 4 with fsteps2627#画E(x)波形图28set origin 0.0,0.029unset label30unset key31set ytics 0,1,132set ylabel "E(x)"33plot "data.txt" using 3 linetype 11 linewidth 4 with fsteps3435unset multiplot36reset六、运行结果6.1R x无错的测试码字0011101及0001011都是本实验所用的(7,4)循环许用码字,其输出结果如图7所示。