Wiener滤波算法的C++实现

头文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                                  levinson.h
 *
 * If the coefficient matrix of a linear equations is Toeplitz, then it can
 * be solved in a high computational efficiency way through Levinson-Durbin
 * algorithm. The subroutiones in this file will be used for solving Wiener
 * -Hopf equeations in Wiener filtring and Yule- Walker equations in
 * parametric spectrum estimation, respectively.
 *
 * Zhang Ming, 2010-11, Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef LEVINSON_H
#define LEVINSON_H


#include <vector.h>


namespace splab
{

    template<typename Type>
    Vector<Type> levinson( const Vector<Type>&, const Vector<Type>& );

    template<typename Type>
    Vector<Type> levinson( const Vector<Type>&, Type& );


    #include <levinson-impl.h>

}
// namespace splab


#endif
// LEVINSON_H
/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                                   wiener.h
 *
 * Wiener Filter.
 *
 * The goal of the Wiener filter is to filter out noise that has corrupted
 * a signal. It is based on a statistical approach.
 *
 * Wiener filters are characterized by the following:
 * Assumption:  signal and (additive) noise are stationary linear stochastic
 *              processes with known spectral characteristics or known
 *              autocorrelation and cross-correlation.
 * Requirement: the filter must be physically realizable/causal (this
 *              requirement can be dropped, resulting in a non-causal solution).
 * Performance: criterion: minimum mean-square error (MMSE).
 *
 * And The correlation matrix is a symmetric Toeplitz matrix, so we can use the
 * efficient algorithm, Levinson-Durbin algorithm, to solve the Wiener-Hopf
 * Equations.
 *
 * Zhang Ming, 2010-10, Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef WIENER_H
#define WIENER_H


#include <vector.h>
#include <correlation.h>
#include <levinson.h>


namespace splab
{

    template<typename Type>
    Vector<Type> wienerFilter( const Vector<Type>&,
                               const Vector<Type>&, int );

    template<typename Type>
    Vector<Type> wienerPredictor( const Vector<Type>&, int );


    #include <wiener-impl.h>

}
// namespace splab


#endif
// WIENER_H

实现文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                               levinson-impl.h
 *
 * Implementationfor Levinson-Durbin alogrithm.
 *
 * Zhang Ming, 2010-11, Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * Levinson algorithm for solving Toeplitz equations.
 * t    : t(0), t(1), ..., t(n-1) of Toeplitz coefficient matrix
 * b    : constant vector
 */
template <typename Type>
Vector<Type> levinson( const Vector<Type> &t, const Vector<Type> &b )
{
    assert( t.size() == b.size() );

    int n = t.size();
	Type alpha, beta, q, c, omega;
	Vector<Type> y(n), yy(n), x(n);

	alpha = t[0];
	if( abs(alpha) < EPS )
	{
		cerr << "The matrix is ill-conditioned!" << endl;
		return x;
	}
	y[0] = 1;
	x[0] = b[0] / alpha;

	for( int k=1; k<n; ++k )
	{
		q = 0;
		beta = 0;
		for( int j=0; j<k; ++j )
		{
			q += x[j] * t[k-j];
			beta += y[j] * t[j+1];
		}
		c = -beta / alpha;

		yy[0] = c * y[k-1];
		y[k] = y[k-1];
		for( int i=1; i<k; ++i )
			yy[i] = y[i-1] + c*y[k-i-1];
		yy[k] = y[k-1];

		alpha += c*beta;
		if( abs(alpha) < EPS )
		{
			cerr << "The matrix is ill-conditioned!" << endl;
			return x;
		}

		omega = (b[k]-q) / alpha;
		for( int i=0; i<k; ++i )
		{
			x[i] += omega*yy[i];
			y[i] = yy[i];
		}
		x[k] = omega*y[k];
	}

	return x;
}


/**
 * Levinson-Durbin algorithm for solving Youle-Walker equations.
 * rn       : r(0), r(1), ..., r(p)
 * sigma2   : the variance of exciting white noise
 */
template <typename Type>
Vector<Type> levinson( const Vector<Type> &rn, Type &sigma2 )
{
    int p = rn.size()-1;
    Type tmp;
    Vector<Type> ak(p+1), akPrev(p+1);

    ak[0] = Type(1.0);
    sigma2 = rn[0];
    ak[1] = -rn[1]/sigma2;
    sigma2 *= 1 - ak[1]*ak[1];

    for( int k=2; k<=p; ++k )
    {
        tmp = 0;
        for( int i=0; i<k; ++i )
            tmp += ak[i]*rn[k-i];
        ak[k] = -tmp/sigma2;

        for( int i=1; i<k; ++i )
            akPrev[i] = ak[i] + ak[k]*ak[k-i];
        for( int i=1; i<k; ++i )
            ak[i] = akPrev[i];

        sigma2 *= 1 - ak[k]*ak[k];
    }

	return ak;
}
/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                              wiener-impl.h
 *
 * Implementation for Wiener Filter.
 *
 * Zhang Ming, 2010-10, Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * By given the observed signal "xn" and desired signal "dn", this routine
 * return the coefficients for Wiener filter with "p" order.
 */
template <typename Type>
Vector<Type> wienerFilter( const Vector<Type> &xn,
                           const Vector<Type> &dn, int p )
{
    int N = xn.size();
    assert( dn.size() == N );

    // auto-correlation and corss-correlation
    Vector<Type> Rxx = fastCorr( xn, "unbiased" );
    Vector<Type> Rdx = fastCorr( dn, xn, "unbiased" );

    Vector<Type> tn(p+1), bn(p+1);
    for( int i=0; i<=p; ++i )
    {
        tn[i] = Rxx[N-1+i];
        bn[i] = Rdx[N-1+i];
    }

    // solving Wiener-Hopf equations
    return levinson( tn, bn );
}


/**
 * One step Wiener predictor by using a "p" order filter. The input
 * signal "xn" should be much longer the "p" in order to have a more
 * precision estimation of the Correlation Matrix of "xn".
 */
template <typename Type>
Vector<Type> wienerPredictor( const Vector<Type> &xn, int p )
{
    int N = xn.size();

    // auto-correlation and corss-correlation
    Vector<Type> Rxx = fastCorr( xn, "unbiased" );
    Vector<Type> tn(p+1), bn(p+1), predictor(p);

    for( int i=0; i<=p; ++i )
        tn[i] = Rxx[N-1+i];
    bn(1) = Type(1.0);

    // solving Yule-Walker equations
    Vector<Type> tmp = levinson( tn, bn );

    for( int i=1; i<=p; ++i )
        predictor(i) = -tmp(i+1) / tmp(1);

    return predictor;
}

测试代码:

/*****************************************************************************
 *                                wiener_test.h
 *
 * Wiener filter testing.
 *
 * Zhang Ming, 2010-10, Xi'an Jiaotong University.
 *****************************************************************************/


#define BOUNDS_CHECK

#include <iostream>
#include <iomanip>
#include <wiener.h>
#include <random.h>
#include <vectormath.h>


using namespace std;
using namespace splab;


typedef double  Type;
const   int     N = 1024;
const   int     M = 12;
const   int     fOrder = 8;
const   int     pOrder = 3;


int main()
{
    Vector<Type> tn(N), dn(N), vn(N), xn(N), yn(N);
    tn = linspace( Type(0.0), Type(2*TWOPI), N );
    dn = sin(tn);
    vn = randn( 37, Type(0.0), Type(1.0), N );
    xn = dn + vn;

    Vector<Type> hn = wienerFilter( xn, dn, fOrder );
    cout << "Wiener filter hn:   " << hn << endl;
    yn = wkeep( conv(xn,hn), N, "left" );
    cout << "original relative error:   " << norm(dn-xn)/norm(dn) << endl;
    cout << "filtered relative error:   " << norm(dn-yn)/norm(dn) << endl << endl;

    Vector<Type> sn(M);
    for( int i=0; i<M; ++i )
        sn[i] = sin( Type(i*TWOPI/10) );
    Vector<Type> pn = wienerPredictor( sn, pOrder );
    Vector<Type> snPred = wkeep( conv(sn,pn), M, "left" );
    cout << "Wiener predictor pn:   " << pn << endl;
    cout << "original\tpredicted\terror" << endl;
    Type realValue = sin( Type(M*TWOPI/10) );
    cout << setiosflags(ios::fixed) << setprecision(4)
         << realValue << "\t\t" << snPred[M-1] << "\t\t"
         << abs(realValue-snPred[M-1]) << endl << endl;

    return 0;
}

运行结果:

Wiener filter hn:   size: 9 by 1
0.0903079
0.0858067
0.0813221
0.0870775
0.0968708
0.0888659
0.0844214
0.0901495
0.0965093

original relative error:   1.43689
filtered relative error:   0.416294

Wiener predictor pn:   size: 3 by 1
0.606355
0.699992
-1.03413

original        predicted       error
0.9511          0.9643          0.0132


Process returned 0 (0x0)   execution time : 0.094 s
Press any key to continue.

你可能感兴趣的:(Wiener滤波算法的C++实现)