头文件:
/* * 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 */ /***************************************************************************** * lms.h * * Least Mean Square Adaptive Filter. * * Least mean squares (LMS) algorithms are a class of adaptive filter used * to mimic a desired filter by finding the filter coefficients that relate * to producing the least mean squares of the error signal (difference * between the desired and the actual signal). It is a stochastic gradient * descent method in that the filter is only adapted based on the error at * the current time. * * This file implement three types of the LMS algorithm: conventional LMS, * algorithm, LMS-Newton algorhm and normalized LMS algorithm. * * Zhang Ming, 2010-10, Xi'an Jiaotong University. *****************************************************************************/ #ifndef LMS_H #define LMS_H #include <vector.h> #include <matrix.h> namespace splab { template<typename Type> Type lms( const Type&, const Type&, Vector<Type>&, const Type& ); template<typename Type> Type lmsNewton( const Type&, const Type&, Vector<Type>&, const Type&, const Type&, const Type& ); template<typename Type> Type lmsNormalize( const Type&, const Type&, Vector<Type>&, const Type&, const Type& ); #include <lms-impl.h> } // namespace splab #endif // LMS_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 */ /***************************************************************************** * lms-impl.h * * Implementation for LMS Adaptive Filter. * * Zhang Ming, 2010-10, Xi'an Jiaotong University. *****************************************************************************/ /** * The conventional LMS algorithm, which is sensitive to the scaling of its * input "xn". The filter order p = wn.size(), where "wn" is the Weight * Vector, and "mu" is the iterative setp size, for stability "mu" should * belong to (0, Rr[Rxx]). */ template <typename Type> Type lms( const Type &xk, const Type &dk, Vector<Type> &wn, const Type &mu ) { int filterLen = wn.size(); static Vector<Type> xn(filterLen); // update input signal for( int i=filterLen; i>1; --i ) xn(i) = xn(i-1); xn(1) = xk; // get the output Type yk = dotProd( wn, xn ); // update the Weight Vector wn += 2*mu*(dk-yk) * xn; return yk; } /** * The LMS-Newton is a variant of the LMS algorithm which incorporate * estimates of the second-order statistics of the environment signals is * introduced. The objective of the algorithm is to avoid the slowconvergence * of the LMS algorithm when the input signal is highly correlated. The * improvement is achieved at the expense of an increased computational * complexity. */ template <typename Type> Type lmsNewton( const Type &xk, const Type &dk, Vector<Type> &wn, const Type &mu, const Type &alpha, const Type &delta ) { assert( 0 < alpha ); assert( alpha <= Type(0.1) ); int filterLen = wn.size(); Type beta = 1-alpha; Vector<Type> vP(filterLen); Vector<Type> vQ(filterLen); static Vector<Type> xn(filterLen); // initialize the Correlation Matrix's inverse static Matrix<Type> invR = eye( filterLen, Type(1.0/delta) ); // update input signal for( int i=filterLen; i>1; --i ) xn(i) = xn(i-1); xn(1) = xk; Type yk = dotProd(wn,xn); // update the Correlation Matrix's inverse vQ = invR * xn; vP = vQ / (beta/alpha+dotProd(vQ,xn)); invR = (invR - multTr(vQ,vP)) / beta; // update the Weight Vector wn += 2*mu * (dk-yk) * (invR*xn); return yk; } /** * The conventional LMS is very hard to choose a learning rate "mu" that * guarantees stability of the algorithm. The Normalised LMS is a variant * of the LMS that solves this problem by normalising with the power of * the input. For stability, the parameter "rho" should beong to (0,2), * and "gamma" is a small number to prevent <Xn,Xn> == 0. */ template <typename Type> Type lmsNormalize( const Type &xk, const Type &dk, Vector<Type> &wn, const Type &rho, const Type &gamma ) { assert( 0 < rho ); assert( rho < 2 ); int filterLen = wn.size(); static Vector<Type> sn(filterLen); // update input signal for( int i=filterLen; i>1; --i ) sn(i) = sn(i-1); sn(1) = xk; // get the output Type yk = dotProd( wn, sn ); // update the Weight Vector wn += rho*(dk-yk)/(gamma+dotProd(sn,sn)) * sn; return yk; }
测试代码:
/***************************************************************************** * lms_test.cpp * * LMS adaptive filter testing. * * Zhang Ming, 2010-10, Xi'an Jiaotong University. *****************************************************************************/ #define BOUNDS_CHECK #include <iostream> #include <iomanip> #include <lms.h> using namespace std; using namespace splab; typedef double Type; const int N = 50; const int order = 1; const int dispNumber = 10; int main() { Vector<Type> dn(N), xn(N), yn(N), wn(order+1); for( int k=0; k<N; ++k ) { xn[k] = Type(cos(TWOPI*k/7)); dn[k] = Type(sin(TWOPI*k/7)); } int start = max(0,N-dispNumber); Type xnPow = dotProd(xn,xn)/N; Type mu = Type( 0.1 / ((order+1)*xnPow) ); Type rho = Type(1.0), gamma = Type(1.0e-9), alpha = Type(0.08); cout << "The last " << dispNumber << " iterations of Conventional-LMS:" << endl; cout << "observed" << "\t" << "desired" << "\t\t" << "output" << "\t\t" << "adaptive filter" << endl << endl; wn = 0; for( int k=0; k<start; ++k ) yn[k] = lms( xn[k], dn[k], wn, mu ); for( int k=start; k<N; ++k ) { yn[k] = lms( xn[k], dn[k], wn, mu ); cout << setiosflags(ios::fixed) << setprecision(4) << xn[k] << "\t\t" << dn[k] << "\t\t" << yn[k] << "\t\t"; for( int i=0; i<=order; ++i ) cout << wn[i] << "\t"; cout << endl; } cout << endl << endl; cout << "The last " << dispNumber << " iterations of LMS-Newton:" << endl; cout << "observed" << "\t" << "desired" << "\t\t" << "output" << "\t\t" << "adaptive filter" << endl << endl; wn = 0; for( int k=0; k<start; ++k ) yn[k] = lmsNewton( xn[k], dn[k], wn, mu, alpha, xnPow ); for( int k=start; k<N; ++k ) { yn[k] = lmsNewton( xn[k], dn[k], wn, mu, alpha, xnPow ); cout << setiosflags(ios::fixed) << setprecision(4) << xn[k] << "\t\t" << dn[k] << "\t\t" << yn[k] << "\t\t"; for( int i=0; i<=order; ++i ) cout << wn[i] << "\t"; cout << endl; } cout << endl << endl; cout << "The last " << dispNumber << " iterations of Normalized-LMS:" << endl; cout << "observed" << "\t" << "desired" << "\t\t" << "output" << "\t\t" << "adaptive filter" << endl << endl; wn = 0; for( int k=0; k<start; ++k ) yn[k] = lmsNormalize( xn[k], dn[k], wn, rho, gamma ); for( int k=start; k<N; ++k ) { yn[k] = lmsNormalize( xn[k], dn[k], wn, rho, gamma ); cout << setiosflags(ios::fixed) << setprecision(4) << xn[k] << "\t\t" << dn[k] << "\t\t" << yn[k] << "\t\t"; for( int i=0; i<=order; ++i ) cout << wn[i] << "\t"; cout << endl; } cout << endl << endl; cout << "The theoretical optimal filter is:\t\t" << "-0.7972\t1.2788" << endl << endl; return 0; }
运行结果:
The last 10 iterations of Conventional-LMS: observed desired output adaptive filter -0.2225 -0.9749 -0.8216 -0.5683 1.0810 0.6235 -0.7818 -0.5949 -0.5912 1.0892 1.0000 -0.0000 0.0879 -0.6084 1.0784 0.6235 0.7818 0.6991 -0.5983 1.0947 -0.2225 0.9749 0.8156 -0.6053 1.1141 -0.9010 0.4339 0.2974 -0.6294 1.1082 -0.9010 -0.4339 -0.4314 -0.6289 1.1086 -0.2225 -0.9749 -0.8589 -0.6239 1.1291 0.6235 -0.7818 -0.6402 -0.6412 1.1353 1.0000 -0.0000 0.0667 -0.6543 1.1271 The last 10 iterations of LMS-Newton: observed desired output adaptive filter -0.2225 -0.9749 -0.9739 -0.7958 1.2779 0.6235 -0.7818 -0.7805 -0.7964 1.2783 1.0000 -0.0000 0.0006 -0.7966 1.2783 0.6235 0.7818 0.7816 -0.7966 1.2784 -0.2225 0.9749 0.9743 -0.7968 1.2787 -0.9010 0.4339 0.4334 -0.7971 1.2787 -0.9010 -0.4339 -0.4340 -0.7971 1.2787 -0.2225 -0.9749 -0.9747 -0.7971 1.2788 0.6235 -0.7818 -0.7816 -0.7972 1.2789 1.0000 -0.0000 0.0001 -0.7973 1.2789 The last 10 iterations of Normalized-LMS: observed desired output adaptive filter -0.2225 -0.9749 -0.9749 -0.7975 1.2790 0.6235 -0.7818 -0.7818 -0.7975 1.2790 1.0000 -0.0000 -0.0000 -0.7975 1.2790 0.6235 0.7818 0.7818 -0.7975 1.2790 -0.2225 0.9749 0.9749 -0.7975 1.2790 -0.9010 0.4339 0.4339 -0.7975 1.2790 -0.9010 -0.4339 -0.4339 -0.7975 1.2790 -0.2225 -0.9749 -0.9749 -0.7975 1.2790 0.6235 -0.7818 -0.7818 -0.7975 1.2790 1.0000 -0.0000 -0.0000 -0.7975 1.2790 The theoretical optimal filter is: -0.7972 1.2788 Process returned 0 (0x0) execution time : 0.109 s Press any key to continue.