• 问题描述

信道H长度L=3,H = (h0,h1,h2),其中h0=,h1=,h2=; 基本信号类型 x =10或-10,一个完整的信号序列为X = (x0,x1,x2,...,x9);噪声W = (w0,w1,w2,...,w11)是满足高斯分布的(0,1)范围内的随机数;按照Y = H·X + W公式转换得到一个完整的信号序列Y = (y0,y1,y2,...,y11)。信号接收端需要在已知Y,H的情况下通过Viterbi算法得到满足 min (W)即 min(Y - H·X)的X`序列。

  •  算法思路

将问题转换为的篱笆图,通过动态规划算法,以min(Y - H·X)为图中每一条边的权值计算公式,从显性序列 Y 推导得到隐性序列 X。

  • 实现代码

package cn.edu.karel.algorithm.wirelesschannel;

import java.util.Random;

/**
 *Decoder类
 * 
 * @author Karel Zuo
 * @time 2015.5.18
 * @version 1.0
 * @description 
 *   该类模拟无线通信过程,接收信息后采用维特比算法或者枚举算法消除噪音并解码。
 */

public class Decoder
{
    /** 接收到的信号*/
    double receive[];
    /** 去噪解码后的信息 */
    int[] message;
    /** 接收信号的通信信道*/
    double h[];
    /** 接收信号的基本信号类型*/
    int signal[];
    /**信道矩阵*/
    double H[][];
            
    /** 
     * @param receive 接收到的信号(Y)
     * @return message 除噪并解码后得到的信号
     */
    public void decodeByViterbi( double receive[])
    {
        int len = receive.length-(h.length-1);//原信号长度
        int n = signal.length;//信号基本类型数
        int minRoadIndex[][] = new int[len][n];//记录每一个阶段的最短路的序号,X为1或-1
        double minRoadValue[][] = new double[len][n];//记录每一个阶段的从原点到该点最短路的权值
        /**计算每一个阶段的最短路权值和选择最短路*/
        int i,j;
        for(i=0;i<len;i++)
        {        
            /**初始化原顶点层 */
            if(i==0)
            {
                minRoadIndex[i][0] = 0;
                minRoadIndex[i][1] = 0;
                
                minRoadValue[i][0] = h[0]*-10;
                minRoadValue[i][1] = h[0]*10;
            }
            else
            {
                /**计算各个路径的距离和该Xi到原点S的距离*/
                int q,p;
                for(q=0;q<n;q++)//遍历第Xi的所有可能取值
                {
                    double temp[] = new double[2];
                    for(p=0;p<n;p++)//遍历Xi-1的所有可能取值
                        temp[p] = getValue(i, q, p, minRoadIndex)+minRoadValue[i-1][p];
                    
                    if(temp[0] <temp[1])
                    {
                        minRoadIndex[i][q] = -1;
                        minRoadValue[i][q] = temp[0];
                    }
                    else
                    {
                        minRoadIndex[i][q] = 1;
                        minRoadValue[i][q] = temp[1];
                    }
                }
            }
        }
        
        /** 输出解码结果 */
        message = new int[len];
        if(minRoadValue[len-1][0] < minRoadValue[len-1][1])
            message[len-1] = -10;
        else
            message[len-1] = 10;
        for(j=len-2;j>=0;j--)
        {
            if(message[j+1] == -10)
                message[j] = minRoadIndex[j+1][0]*10;
            else
                message[j] = minRoadIndex[j+1][1]*10;
        }
        System.out.println("");
        System.out.println("");
        System.out.print("Viterbi算法解码后的信号 :");
        for(j=0;j<len;j++)
            System.out.print(message[j] + " , ");    
    }
    
    /** 
     * @param receive 接收到的信号(Y)
     * @return message 除噪并解码后得到的信号
     */
    public void decodeByEnum(double receive[])
    {
        int len_y = receive.length;//接收信号长度
        int len_x = len_y-(h.length-1);//原信号长度
        int num = (int) Math.pow(signal.length, len_x );
        int x[][] = new int[num][len_x ]; 
        double value[] = new double[num];
        
        /** 枚举所有信号组合形式及其路径长度*/
        x = enmuSignal(len_x ,num);
        
        int p,q,k;
        for(p=0;p<num;p++)
        {
            double temp = 0;
            for(q=0;q<len_y;q++)
            {
                temp = 0;
                for(k=0;k<len_x ;k++)
                    temp += x[p][k]*H[q][k];
                value[p] += Math.pow((receive[q]-temp), 2); 
            }
        }
        
        /** 搜索到最短路径的组合 */
        int minRoad = 0;
        double minValue = value[minRoad];
        int n;
        for(n=1;n<num;n++)
        {
            if(value[n]<minValue)
            {
                minRoad = n;
                minValue = value[n];
            }
        }
        /**输出,测试 */
        System.out.println("枚举算法结果:  ");
        for(n=0;n<len_x;n++)
            System.out.print(x[minRoad][n] + " , ");    
        System.out.println("");
    }
    
    /** 
     * 接收信号及其他参数
     * @param en 发送方类对象
     */
    public void getSignal(Encoder en)
    {
        this.receive = new double[(Encoder.sendMessage.length)];
        this.receive = Encoder.sendMessage;
        this.h = new double[Encoder.h.length];
        this.h = Encoder.h;
        this.signal = new int[Encoder.signal.length];
        this.signal = Encoder.signal;
        
        /**初始化信道矩阵*/
        int len = receive.length-(h.length-1);
        H = new double[receive.length][len];//信道矩阵
        int i,j;
        for(i=0;i<len;i++)
        {
            for(j=i;j<(i+h.length);j++)
                H[j][i] = h[(j-i)];
        }
    }
    
    /**
     * 计算Xi到Xi-1的边长
     * @param index 当前x的下标
     * @param cur_X 当前xi的取值序号(0,1)
     * @param per_X 当前xi-1的取值序号(0,1)
     * @param minRoadIndex 记录Xi到Xi-1的最短路时,Xi-1的取值
     * @return value 边长
     */
    public double getValue(int index, int cur_X, int per_X, int minRoadIndex[][])
    {
        double value = 0;
        int x[] = new int[10];//x的序列
        
        if(cur_X == 0)
            x[index] = -10;
        else 
            x[index] =10;
        
        if(per_X == 0)
            x[index-1] = -10;
        else
            x[index-1] = 10;
        
        if(index >= 2)
        {
            int i;
            for(i=(index-2);i>=0;i--)
            {
                if(x[i+1] == -10)
                    x[i] = minRoadIndex[i][0]*10;
                else
                    x[i] = minRoadIndex[i][1]*10;    
            }
        }
        
        int i;
        for(i=0;i<10;i++)
            value += x[i]*H[index][i];
        value = Math.pow((receive[index]-value),2); 
        
        return value;
    }
    
    /**递归实现信号转态的枚举 
     * @param len X序列的长度
     * @param num X的组合总数
     * @return x 所有枚举组合
     * */
    public int[][] enmuSignal(int len,int num)
    {
        int m = 0;
        int i[] = new int[len];
        int x[][] = new int[num][len];
        int n = signal.length;
        
        for(i[0]=0;i[0]<n;i[0]++){
            for(i[1]=0;i[1]<n;i[1]++){
                for(i[2]=0;i[2]<n;i[2]++){
                    for(i[3]=0;i[3]<n;i[3]++){
                        for(i[4]=0;i[4]<n;i[4]++){
                            for(i[5]=0;i[5]<n;i[5]++){
                                for(i[6]=0;i[6]<n;i[6]++){
                                    for(i[7]=0;i[7]<n;i[7]++){
                                        for(i[8]=0;i[8]<n;i[8]++){
                                            for(i[9]=0;i[9]<n;i[9]++){
                                                int j;
                                                for(j=0;j<len;j++)
                                                    x[m][j]=signal[(i[j])];
                                                m++;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        
        return x;
    }
}

/**
 * Encoder类
 * 
 * @author Karel Zuo
 * @time 2015.5.18
 * @version 1.0
 * @description 
 *   该类模拟无线通信过程,发送信息 X 经过编码得到H·X ,在传输过程中受到干扰变成 H·X + W ,并被接收。
 */

public class Encoder 
{
    /** 信道总数 */
    static final int L = 3;
    /** 基本信号 */
    static final int signal[] = {10,-10};
    /** H */
    static final double h[] = {0.8, 0.4, 0.2};
    /** 信号长度  */
    static final int SUM_X = 10;
    /** 噪声数量 */
    static final int SUM_W = 12;
    /** 最终发送的信号 */
    public static double sendMessage[];
    
    public Encoder()
    {
        sendMessage = new double[SUM_W];
        sendMessage = getMessage(creatMessage());
    }
    
    /**
     * @param signal[] 基本信号
     * @return message[] 随机产生的一段信号
     */
    public int[] creatMessage()
    {
        int message[] = new int[SUM_X];//随机产生并返回的一段信号信息
        int i;
        Random r = new Random(); 
        
        for(i=0;i<SUM_X;i++)
        {
            if(r.nextInt(10) < 5)
                message[i] = signal[0];
            else
                message[i] = signal[1];
        }
        
        /**输出,测试结果*/
        System.out.println(" 随机生成的发送序列 X:");
        for(i=0;i<SUM_X;i++)
            System.out.print(message[i]+" , ");
        System.out.println(" ");
        
        return message;
    }
    
    /**
     * @param message[] 原始信号
     * @return receive[] 接收到的信号
     */
    public double[] getMessage(int message[])
    {
        double H[][] = new double[SUM_W][SUM_X];//信道矩阵
        double receive[] = new double[SUM_W];//接收信号矩阵
        int i,j;
        Random r = new Random();
        
        /** 初始化 H 矩阵 */
        for(i=0;i<SUM_X;i++)
            for(j=i;j<(i+h.length);j++)
                H[j][i] = h[(j-i)];
            
        /** 矩阵运算 Y = H·X +W */
        for(i=0;i<SUM_W;i++)
        {
            for(j=0;j<SUM_X;j++)
                receive[i] += H[i][j]*message[j];
            receive[i] += r.nextGaussian();
        }
        
        /** 输出,测试 */
        System.out.println("");
        System.out.println("");
        System.out.println(" 输出信号 Y :");
        for(i=0;i<SUM_W;i++)
            System.out.println(receive[i] + " , ");
        System.out.println("");
        
        return receive;
    }
}

/**
 * Test类
 * 
 * @author Karel Zuo
 * @time 2015.5.18
 * @version 1.0
 * @description 
 *   该类模拟无线通信过程。
 */
public class Test {

    public static void main(String[] args) {
        
        /** 随机生成信号并用Viterbi算法和枚举算法分别还原信号 */
        Encoder en = new Encoder();
        Decoder de = new Decoder();
        de.getSignal(en);
    
        long startEnum = System.currentTimeMillis();//记录枚举算法开始时间
        de.decodeByEnum(de.receive);
        long endEnum = System.currentTimeMillis();//记录枚举算法结束时间
        
        long startViterbi = System.currentTimeMillis();//Viterbi算法开始时间
        de.decodeByViterbi(de.receive);
        long endViterbi = System.currentTimeMillis();//记录Viterbi算法结束时间
        
        /**输出程序运行时间 */
        System.out.println(" ");
        System.out.println("枚举算法执行时间: " + (endEnum - startEnum));
        System.out.println("Viterbi算法执行时间: " + (endViterbi - startViterbi));
    }
}
  • 运行结果