头文件:
/*
* Copyright (c) 2008-2011 Zhang Ming (M. Zhang), zmjerry@163.com
*
* 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
*/
/*****************************************************************************
* rls.h
*
* Recursive Least Square Filter.
*
* The RLS adaptive filter recursively finds the filter coefficients that
* minimize a weighted linear least squares cost function relating to the
* input signals. This in contrast to other algorithms such as the LMS that
* aim to reduce the mean square error.
*
* The input signal of RLS adaptive filter is considered deterministic,
* while for the LMS and similar algorithm it is considered stochastic.
* Compared to most of its competitors, the RLS exhibits extremely fast
* convergence. However, this benefit comes at the cost of high computational
* complexity, and potentially poor tracking performance when the filter to
* be estimated changes.
*
* This file includes five types usually used RLS algorithms, they are:
* conventional RLS (rls), stabilised fast transversal RLS (sftrls),
* lattice RLS (lrls), error feedblck lattice RLS (eflrls),
* QR based RLS (qrrls).
*
* Zhang Ming, 2010-10, Xi'an Jiaotong University.
*****************************************************************************/
#ifndef RLS_H
#define RLS_H
#include <vector.h>
#include <matrix.h>
namespace splab
{
template<typename Type>
Type rls( const Type&, const Type&, Vector<Type>&,
const Type&, const Type& );
template<typename Type>
Type sftrls( const Type&, const Type&, Vector<Type>&,
const Type&, const Type&, const string& );
template<typename Type>
Type lrls( const Type&, const Type&, Vector<Type>&,
const Type&, const Type&, const string& );
template<typename Type>
Type eflrls( const Type&, const Type&, Vector<Type>&,
const Type&, const Type&, const string& );
template<typename Type>
Type qrrls( const Type&, const Type&, Vector<Type>&,
const Type&, const string& );
#include <rls-impl.h>
}
// namespace splab
#endif
// RLS_H
实现文件:
/*
* Copyright (c) 2008-2011 Zhang Ming (M. Zhang), zmjerry@163.com
*
* 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
*/
/*****************************************************************************
* rls-impl.h
*
* Implementation for RLS Filter.
*
* Zhang Ming, 2010-10, Xi'an Jiaotong University.
*****************************************************************************/
/**
* The conventional RLS algorighm. The parameter "lambda" is the Forgetting
* Factor, the smaller "lambda" is, the smaller contribution of previous samples.
* This makes the filter more sensitive to recent samples, which means more
* fluctuations in the filter co-efficients. Suggesting range is: [0.8, 1.0].
* The parametet "delta" is the value to initialeze the inverse of the Auto-
* Relation Matrix of input signal, which can be chosen as an estimation of
* the input signal power.
*/
template <typename Type>
Type rls( const Type &xk, const Type &dk, Vector<Type> &wn,
const Type &lambda, const Type &delta )
{
assert( Type(0.8) <= lambda );
assert( lambda <= Type(1.0) );
int filterLen = wn.size();
Vector<Type> vP(filterLen);
Vector<Type> vQ(filterLen);
static Vector<Type> xn(filterLen);
static Matrix<Type> invR = eye( filterLen, Type(1.0/delta) );
// updata input signal
for( int i=filterLen; i>1; --i )
xn(i) = xn(i-1);
xn(1) = xk;
// priori error
Type ak = dk - dotProd(wn,xn);
vQ = invR * xn;
vP = vQ / (lambda+dotProd(vQ,xn));
// updata Correlation-Matrix's inverse
invR = (invR - multTr(vQ,vP)) / lambda;
// update Weight Vector
wn += ak * vP;
// wn += ak * (invR*xn);
return dotProd(wn,xn);
}
/**
* Stabilized Fast Tranversal RLS
*/
template <typename Type>
Type sftrls( const Type &xk, const Type &dk, Vector<Type> &wn,
const Type &lambda, const Type &epsilon,
const string &training )
{
int filterLen = wn.size(),
L = wn.size()-1;
assert( Type(1.0-1.0/(2*L+2)) <= lambda );
assert( lambda <= Type(1.0) );
static Vector<Type> xn(filterLen), xnPrev(filterLen);
const Type k1 = Type(1.5),
k2 = Type(2.5),
k3 = Type(1.0);
// initializing for begin
Type e, ep,
ef, efp,
eb1, eb2, ebp1, ebp2, ebp31, ebp32, ebp33;
static Type gamma = 1,
xiBmin = epsilon,
xiFminInv = 1/epsilon;
Vector<Type> phiExt(L+2);
static Vector<Type> phi(filterLen),
wf(filterLen), wb(filterLen);
// updata input signal
xnPrev = xn;
for( int i=1; i<=L; ++i )
xn[i] = xnPrev[i-1];
xn[0] = xk;
if( training == "on" )
{
// forward prediction error
efp = xk - dotProd(wf,xnPrev);
ef = gamma * efp;
phiExt[0] = efp * xiFminInv/lambda;
for( int i=0; i<filterLen; ++i )
phiExt[i+1] = phi[i] - phiExt[0]*wf[i];
// gamma1
gamma = 1 / ( 1/gamma + phiExt[0]*efp );
// forward minimum weighted least-squares error
xiFminInv = xiFminInv/lambda - gamma*phiExt[0]*phiExt[0];
// forward prediction coefficient vector
wf += ef * phi;
// backward prediction errors
ebp1 = lambda * xiBmin * phiExt[filterLen];
ebp2 = xnPrev[L] - dotProd(wb,xn);
ebp31 = (1-k1)*ebp1 + k1*ebp2;
ebp32 = (1-k2)*ebp1 + k2*ebp2;
ebp33 = (1-k3)*ebp1 + k3*ebp2;
// gamma2
gamma = 1 / ( 1/gamma - phiExt[filterLen]*ebp33 );
// backward prediction errors
eb1 = gamma * ebp31;
eb2 = gamma * ebp32;
// backward minimum weighted least-squares error
xiBmin = lambda*xiBmin + eb2*ebp2;
for( int i=0; i<filterLen; ++i )
phi[i] = phiExt[i] + phiExt[filterLen]*wb[i];
// forward prediction coefficient vector
wb += eb1 * phi;
// gamma3
gamma = 1 / ( 1 + dotProd(phi,xn) );
// Joint-Process Estimation
ep = dk - dotProd(wn,xn);
e = gamma * ep;
wn += e * phi;
}
return dotProd(wn,xn);
}
/**
* Lattice RLS
*/
template <typename Type>
Type lrls( const Type &xk, const Type &dk, Vector<Type> &vn,
const Type &lambda, const Type &epsilon,
const string &training )
{
assert( Type(0.8) <= lambda );
assert( lambda <= Type(1.0) );
int filterLen = vn.size(),
L = filterLen-1;
// initializing for begin
Vector<Type> gamma(filterLen),
eb(filterLen),
kb(L), kf(L),
xiBmin(filterLen), xiFmin(filterLen);
static Vector<Type> delta(L), deltaD(filterLen),
gammaOld(filterLen,Type(1.0)),
ebOld(filterLen),
xiBminOld(filterLen,epsilon),
xiFminOld(filterLen,epsilon);
// initializing for Zeor Order
gamma[0] = 1;
xiBmin[0]= xk*xk + lambda*xiFminOld[0];
xiFmin[0] = xiBmin[0];
Type e = dk;
Type ef = xk;
eb[0] = xk;
for( int j=0; j<L; ++j )
{
// auxiliary parameters
delta[j] = lambda*delta[j] + ebOld[j]*ef/gammaOld[j];
gamma[j+1] = gamma[j] - eb[j]*eb[j]/xiBmin[j];
// reflection coefficients
kb[j] = delta[j] / xiFmin[j];
kf[j] = delta[j] / xiBminOld[j];
// prediction errors
eb[j+1] = ebOld[j] - kb[j]*ef;
ef -= kf[j]*ebOld[j];
// minimum least-squares
xiBmin[j+1] = xiBminOld[j] - delta[j]*kb[j];
xiFmin[j+1] = xiFmin[j] - delta[j]*kf[j];
// feedforward filtering
if( training == "on" )
{
deltaD[j] = lambda*deltaD[j] + e*eb[j]/gamma[j];
vn[j] = deltaD[j] / xiBmin[j];
}
e -= vn[j]*eb[j];
}
// last order feedforward filtering
if( training == "on" )
{
deltaD[L] = lambda*deltaD[L] + e*eb[L]/gamma[L];
vn[L] = deltaD[L] / xiBmin[L];
}
e -= vn[L]*eb[L];
// updated parameters
gammaOld = gamma;
ebOld = eb;
xiFminOld = xiFmin;
xiBminOld = xiBmin;
return dk-e;
}
/**
* Error Feedback Lattice RLS
*/
template <typename Type>
Type eflrls( const Type &xk, const Type &dk, Vector<Type> &vn,
const Type &lambda, const Type &epsilon,
const string &training )
{
assert( Type(0.8) <= lambda );
assert( lambda <= Type(1.0) );
int filterLen = vn.size(),
L = filterLen-1;
// initializing for begin
Vector<Type> gamma(filterLen),
eb(filterLen),
xiBmin(filterLen), xiFmin(filterLen);
static Vector<Type> delta(L), deltaD(filterLen),
gammaOld(filterLen,Type(1.0)),
ebOld(filterLen),
kb(L), kf(L),
xiBminOld2(filterLen,epsilon),
xiBminOld(filterLen,epsilon),
xiFminOld(filterLen,epsilon);
// initializing for Zeor Order
gamma[0] = 1;
xiBmin[0]= xk*xk + lambda*xiFminOld[0];
xiFmin[0] = xiBmin[0];
Type tmp = 0;
Type e = dk;
Type ef = xk;
eb[0] = xk;
for( int j=0; j<L; ++j )
{
// auxiliary parameters
delta[j] = lambda*delta[j] + ebOld[j]*ef/gammaOld[j];
gamma[j+1] = gamma[j] - eb[j]*eb[j]/xiBmin[j];
// reflection coefficients
tmp = ebOld[j]*ef / gammaOld[j]/lambda;
kb[j] = gamma[j+1]/gammaOld[j] * ( kb[j] + tmp/xiFminOld[j] );
kf[j] = gammaOld[j+1]/gammaOld[j] * ( kf[j] + tmp/xiBminOld2[j] ) ;
// prediction errors
eb[j+1] = ebOld[j] - kb[j]*ef;
ef -= kf[j]*ebOld[j];
// minimum least-squares
xiBmin[j+1] = xiBminOld[j] - delta[j]*delta[j]/xiFmin[j];
xiFmin[j+1] = xiFmin[j] - delta[j]*delta[j]/xiBminOld[j];
// feedforward filtering
if( training == "on" )
vn[j] = gamma[j+1]/gamma[j] *
( vn[j] + e*eb[j]/(lambda*gamma[j]*xiBminOld[j]) );
e -= vn[j]*eb[j];
}
// last order feedforward filtering
if( training == "on" )
vn[L] = (gamma[L]-eb[L]*eb[L]/xiBmin[L])/gamma[L] *
(vn[L]+e*eb[L]/(lambda*gamma[L]*xiBminOld[L]));
e -= vn[L]*eb[L];
// updated parameters
gammaOld = gamma;
ebOld = eb;
xiBminOld2 = xiBminOld;
xiBminOld = xiBmin;
xiFminOld = xiFmin;
return dk-e;
}
/**
* QR-RLS
*/
template <typename Type>
Type qrrls( const Type &xk, const Type &dk, Vector<Type> &wn,
const Type &lambdaSqrt, const string &training )
{
int filterLen = wn.size(),
fL1 = filterLen+1;
// initializing for begin
static int k = 1;
Type dp, ep,
gammap,
c, cosTheta, sinTheta,
tmp;
static Type sx1;
Vector<Type> xp(filterLen);
static Vector<Type> xn(filterLen), dn(filterLen), dq2p(filterLen);
static Matrix<Type> Up(filterLen,filterLen);
// updata input signal
for( int i=filterLen; i>1; --i )
xn(i) = xn(i-1);
xn(1) = xk;
if( training == "on" )
{
// initializing for 0 to L iterations
if( k <= filterLen )
{
// updata Up
for( int i=filterLen; i>1; --i )
for( int j=1; j<=filterLen; ++j )
Up(i,j) = lambdaSqrt * Up(i-1,j);
for( int j=1; j<=filterLen; ++j )
Up(1,j) = lambdaSqrt * xn(j);
dn(k) = dk;
for( int i=filterLen; i>1; --i )
dq2p(i) = lambdaSqrt * dq2p(i-1);
dq2p(1) = lambdaSqrt * dn(k);
if( k == 1 )
{
sx1 = xk;
if( abs(sx1) > Type(1.0-6) )
sx1 = Type(1.0);
}
// new Weight Vector
wn(1) = dn(1) / sx1;
if( k > 1 )
for( int i=2; i<=k; ++i )
{
tmp = 0;
for( int j=2; j<=i; ++j )
tmp += xn(k-j+1)*wn(i-j+1);
wn(i) = (-tmp+dn(i)) / sx1;
}
ep = dk - dotProd(wn,xn);
k++;
}
else
{
xp = xn;
gammap = 1;
dp = dk;
// Givens rotation
for( int i=1; i<=filterLen; ++i )
{
c = sqrt( Up(i,fL1-i)*Up(i,fL1-i) + xp(fL1-i)*xp(fL1-i) );
cosTheta = Up(i,fL1-i) / c;
sinTheta = xp(fL1-i) / c;
gammap *= cosTheta;
for( int j=1; j<=filterLen; ++j )
{
tmp = xp(j);
xp(j) = cosTheta*tmp - sinTheta*Up(i,j);
Up(i,j) = sinTheta*tmp + cosTheta*Up(i,j);
}
tmp = dp;
dp = cosTheta*tmp - sinTheta*dq2p(i);
dq2p(i) = sinTheta*tmp + cosTheta*dq2p(i);
}
ep = dp / gammap;
// new Weight Vector
wn(1) = dq2p(filterLen) / Up(filterLen,1);
for( int i=2; i<=filterLen; ++i )
{
tmp = 0;
for( int j=2; j<=i; ++j )
tmp += Up(fL1-i,i-j+1) * wn(i-j+1);
wn(i) = (-tmp+dq2p(fL1-i)) / Up(fL1-i,i);
}
// updating internal variables
Up *= lambdaSqrt;
dq2p *= lambdaSqrt;
}
return dk-ep;
}
else
return dotProd(wn,xn);
}
测试代码:
/*****************************************************************************
* rls_test.cpp
*
* RLS adaptive filter testing.
*
* Zhang Ming, 2010-10, Xi'an Jiaotong University.
*****************************************************************************/
#define BOUNDS_CHECK
#include <iostream>
#include <iomanip>
#include <convolution.h>
#include <vectormath.h>
#include <random.h>
#include <rls.h>
using namespace std;
using namespace splab;
typedef float Type;
const int N = 1000;
const int orderRls = 1;
const int orderLrls = 16;
const int orderTrls = 12;
const int orderQrrls = 8;
const int sysLen = 8;
const int dispNumber = 10;
int main()
{
int start = max(0,N-dispNumber);
Vector<Type> dn(N), xn(N), yn(N), sn(N), rn(N), en(N),
hn(sysLen+1), gn(orderLrls+1), wn(orderRls+1);
Type lambda, delta, eps;
cout << "/************** Conventional RLS <---> Waveform Tracking \
*************/" << endl << endl;
for( int k=0; k<N; ++k )
{
dn[k] = Type(sin(TWOPI*k/7));
xn[k] = Type(cos(TWOPI*k/7));
}
lambda = Type(0.99);
delta = dotProd(xn,xn)/N;
cout << "The last " << dispNumber << " iterations result:" << endl << endl;
cout << "observed" << "\t" << "desired" << "\t\t" << "output" << "\t\t"
<< "adaptive filter" << endl << endl;
for( int k=0; k<start; ++k )
yn[k] = rls( xn[k], dn[k], wn, lambda, delta );
for( int k=start; k<N; ++k )
{
yn[k] = rls( xn[k], dn[k], wn, lambda, delta );
cout << setiosflags(ios::fixed) << setprecision(4)
<< xn[k] << "\t\t" << dn[k] << "\t\t" << yn[k] << "\t\t";
for( int i=0; i<=orderRls; ++i )
cout << wn[i] << "\t";
cout << endl;
}
cout << endl << "The theoretical optimal filter is:\t\t" << "-0.7972\t1.2788"
<< endl << endl << endl;
cout << "/************** Lattice RLS <---> Channel Equalization \
***************/" << endl << endl;
for( int k=0; k<=sysLen; ++k )
hn[k] = Type( 0.1 * pow(0.5,k) );
dn = randn( 37, Type(0.0), Type(1.0), N );
xn = wkeep( conv(dn,hn), N, "left" );
lambda = Type(0.99), eps = Type(0.1);
wn.resize(orderLrls);
wn = Type(0.0);
for( int k=0; k<N; ++k )
// yn[k] = lrls( xn[k], dn[k], wn, lambda, eps, "on" );
yn[k] = eflrls( xn[k], dn[k], wn, lambda, eps, "on" );
Vector<Type> Delta(orderLrls+1);
Delta[(orderLrls+1)/2] = Type(1.0);
for( int k=0; k<=orderLrls; ++k )
// gn[k] = lrls( Delta[k], Type(0.0), wn, lambda, eps, "off" );
gn[k] = eflrls( Delta[k], Type(0.0), wn, lambda, eps, "off" );
cout << setiosflags(ios::fixed) << setprecision(4);
cout << "The original system: " << hn << endl;
cout << "The inverse system: " << gn << endl;
cout << "The cascade system: " << conv( gn, hn ) << endl << endl;
//
cout << "/************ Transversal RLS <---> System Identification \
************/" << endl << endl;
Vector<Type> sys(8);
sys[0] = Type(0.1); sys[1] = Type(0.3); sys[2] = Type(0.0); sys[3] = Type(-0.2);
sys[4] = Type(-0.4); sys[5] = Type(-0.7); sys[6] = Type(-0.4); sys[7] = Type(-0.2);
xn = randn( 37, Type(0.0), Type(1.0), N );
dn = wkeep( conv(xn,sys), N, "left" );
lambda = Type(0.99), eps = Type(1.0);
wn.resize(orderTrls);
wn = Type(0.0);
for( int k=0; k<start; ++k )
yn[k] = sftrls( xn[k], dn[k], wn, lambda, eps, "on" );
cout << "The last " << dispNumber << " iterations result:" << endl << endl;
cout << "input signal" << " " << "original system output" << " "
<< "identified system output" << endl << endl;
for( int k=start; k<N; ++k )
{
yn[k] = sftrls( xn[k], Type(0.0), wn, lambda, eps, "off" );
cout << setiosflags(ios::fixed) << setprecision(4)
<< xn[k] << "\t\t\t" << dn[k] << "\t\t\t" << yn[k] << endl;
}
cout << endl << "The unit impulse response of original system: " << sys << endl;
cout << "The unit impulse response of identified system: " << wn << endl << endl;
cout << "/*************** QR Based RLS <---> Signal Enhancement \
***************/" << endl << endl;
sn = sin( linspace( Type(0.0), Type(4*TWOPI), N ) );
rn = randn( 37, Type(0.0), Type(1.0), N );
dn = sn + rn;
int delay = orderQrrls/2;
for( int i=0; i<N-delay; ++i )
xn[i] = rn[i+delay];
for( int i=N-delay; i<N; ++i )
xn[i] = 0;
Type lambdaSqrt = Type(1.0);
wn.resize(orderQrrls);
wn = Type(0.0);
for( int k=0; k<N; ++k )
yn[k] = qrrls( xn[k], dn[k], wn, lambdaSqrt, "on" );
en = dn - yn;
for( int i=0; i<N/2; ++i )
{
sn[i] = 0;
rn[i] = 0;
en[i] = 0;
}
cout << "The last " << dispNumber << " iterations result:" << endl << endl;
cout << "noised signal\t\t" << "enhanced signal\t\t" << "original signal"
<< endl << endl;
for( int k=start; k<N; ++k )
cout << setiosflags(ios::fixed) << setprecision(4)
<< dn[k] << "\t\t\t" << en[k] << "\t\t\t" << sn[k] << endl;
cout << endl << "The SNR before denoising is: "
<< 20*(log10(norm(sn))/log10(norm(rn))) << " dB" << endl;
cout << "The SNR after denoising is: "
<< 20*(log10(norm(en))/log10(norm(sn-en))) << " dB" << endl << endl;
return 0;
}
运行结果:
/************** Conventional RLS <---> Waveform Tracking *************/
The last 10 iterations result:
observed desired output adaptive filter
-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
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
The theoretical optimal filter is: -0.7972 1.2788
/************** Lattice RLS <---> Channel Equalization ***************/
The original system: size: 9 by 1
0.1000
0.0500
0.0250
0.0125
0.0063
0.0031
0.0016
0.0008
0.0004
The inverse system: size: 17 by 1
0.6038
-0.0026
-0.0018
-0.0012
0.0008
0.0011
0.0011
-0.0009
8.7646
-5.0002
0.0000
0.0015
-0.0007
-0.0004
0.0014
0.0027
0.0048
The cascade system: size: 25 by 1
0.0604
0.0299
0.0148
0.0073
0.0037
0.0020
0.0011
0.0005
0.8767
-0.0618
-0.0309
-0.0153
-0.0077
-0.0039
-0.0018
-0.0006
0.0002
-0.0016
0.0002
0.0001
0.0000
0.0000
0.0000
0.0000
0.0000
/************ Transversal RLS <---> System Identification ************/
The last 10 iterations result:
input signal original system output identified system output
1.5173 -1.7206 -1.7206
-0.9741 -1.3146 -1.3146
-1.4056 -2.1204 -2.1204
-0.9319 -2.3165 -2.3165
-0.5763 -2.1748 -2.1748
0.4665 -1.2228 -1.2228
0.5959 0.7623 0.7623
0.5354 1.7904 1.7904
-0.4990 1.6573 1.6573
-1.1519 0.4866 0.4866
The unit impulse response of original system: size: 8 by 1
0.1000
0.3000
0.0000
-0.2000
-0.4000
-0.7000
-0.4000
-0.2000
The unit impulse response of identified system: size: 12 by 1
0.1000
0.3000
0.0000
-0.2000
-0.4000
-0.7000
-0.4000
-0.2000
0.0000
0.0000
-0.0000
-0.0000
/*************** QR Based RLS <---> Signal Enhancement ***************/
The last 10 iterations result:
noised signal enhanced signal original signal
1.2928 -0.2263 -0.2245
-1.1740 -0.1998 -0.1999
-1.5808 -0.1748 -0.1752
-1.0823 -0.1469 -0.1504
-0.7017 -0.1039 -0.1255
0.3660 -0.0745 -0.1005
0.5205 -0.0628 -0.0754
0.4851 -0.0439 -0.0503
-0.5242 -0.0220 -0.0252
-1.1519 0.0058 0.0000
The SNR before denoising is: 17.5084 dB
The SNR after denoising is: 121.1680 dB
Process returned 0 (0x0) execution time : 0.187 s
Press any key to continue.