git-svn-id: http://moon:8086/svn/software/trunk/libsrc/avpflms@1 b431acfa-c32f-4a4a-93f1-934dc6c82436
229 lines
6.4 KiB
Plaintext
Executable File
229 lines
6.4 KiB
Plaintext
Executable File
/*-------------------------------------------------------------------------
|
|
* pflms.c Partioned Frequency Least-Mean-Square adaptive algorithm
|
|
* $Id: $
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* Copyright (C) 2001 Algo Vision Systems GmbH
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#define AVNEEDFLOAT
|
|
|
|
#include <math.h>
|
|
#include "../../../include/avtypes.h"
|
|
#include "../../../include/averror.h"
|
|
#include "../../../include/avrtl.h"
|
|
#include "../../../include/fft.h"
|
|
#include "pflms.h"
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
AVERR PflmsInit(
|
|
PFLMS *pObj, /* Zeiger auf PFLMS-Objekt */
|
|
UINT32 N,
|
|
UINT32 P,
|
|
UINT32 S,
|
|
UINT32 L,
|
|
UINT32 C
|
|
)
|
|
{
|
|
UINT32 i, NP;
|
|
|
|
/* Auto-Param */
|
|
if ((N*L)==0)
|
|
return AV_E_FAIL;
|
|
|
|
if (P==0)
|
|
{
|
|
if ((N%L) != 0)
|
|
return AV_E_FAIL;
|
|
P = N/L;
|
|
}
|
|
|
|
/* Auto-guess FFT-Groesse C */
|
|
if (C==0)
|
|
pObj->C = (UINT32)pow(2,ceil(log(L+N/P-1)/log(2.0)));
|
|
|
|
/* Objekt initialisieren */
|
|
pObj->L = L;
|
|
pObj->N = N;
|
|
pObj->P = P;
|
|
pObj->S = S;
|
|
NP = pObj->S * pObj->L;
|
|
|
|
/*-------------------------------------------------------*/
|
|
/* Speicher allokieren */
|
|
/*-------------------------------------------------------*/
|
|
/* Speicher fuer Mu[P*S][C] (reell) */
|
|
pObj->pMu = (REALBUF*)AvMemAlloc(P*S*sizeof(REALBUF));
|
|
|
|
for (i=0; i < P*S; i++)
|
|
{
|
|
pObj->pMu[i].pData = (FLOAT32*)AvMemAlloc(pObj->C*sizeof(FLOAT32));
|
|
AvZeroMem(pObj->pMu[i].pData,pObj->C*sizeof(FLOAT32));
|
|
pObj->pMu[i].pNext = &pObj->pMu[i+1];
|
|
pObj->pMu[i].pLast = &pObj->pMu[i-1];
|
|
pObj->pMu[i].user = i;
|
|
}
|
|
pObj->pMu[i-1].pNext = &pObj->pMu[0];
|
|
pObj->pMu[0].pLast = &pObj->pMu[i-1];
|
|
|
|
/* Speicher fuer PX[C] (reell) */
|
|
pObj->pPX = (REALBUF*)AvMemAlloc(sizeof(REALBUF));
|
|
pObj->pPX->pData = (FLOAT32*)AvMemAlloc(pObj->C*sizeof(FLOAT32));
|
|
AvZeroMem(pObj->pPX->pData,pObj->C*sizeof(FLOAT32));
|
|
pObj->pPX->pNext = pObj->pPX;
|
|
pObj->pPX->pLast = pObj->pPX;
|
|
pObj->pPX->user = 0;
|
|
|
|
|
|
/* Speicher fuer X[P*S][C] (complex) */
|
|
pObj->pX = (CMPXBUF*)AvMemAlloc(P*S*sizeof(CMPXBUF));
|
|
|
|
for (i=0; i < P*S; i++)
|
|
{
|
|
pObj->pX[i].cmpxData.pReal = (FLOAT32*)AvMemAlloc(pObj->C*sizeof(FLOAT32));
|
|
pObj->pX[i].cmpxData.pImag = (FLOAT32*)AvMemAlloc(pObj->C*sizeof(FLOAT32));
|
|
AvZeroMem(pObj->pX[i].cmpxData.pReal,pObj->C*sizeof(FLOAT32));
|
|
AvZeroMem(pObj->pX[i].cmpxData.pImag,pObj->C*sizeof(FLOAT32));
|
|
pObj->pX[i].pNext = &pObj->pX[i+1];
|
|
pObj->pX[i].pLast = &pObj->pX[i-1];
|
|
pObj->pX[i].user = i;
|
|
}
|
|
pObj->pX[i-1].pNext = &pObj->pX[0];
|
|
pObj->pX[0].pLast = &pObj->pX[i-1];
|
|
|
|
|
|
/* Speicher fuer WS[P][C] (complex) */
|
|
pObj->pWS = (CMPXBUF*)AvMemAlloc(P*S*sizeof(CMPXBUF));
|
|
|
|
for (i=0; i < P*S; i++)
|
|
{
|
|
pObj->pWS[i].pData = (COMPLEX*)AvMemAlloc(pObj->C*sizeof(COMPLEX));
|
|
AvZeroMem(pObj->pWS[i].pData,pObj->C*sizeof(COMPLEX));
|
|
pObj->pWS[i].pNext = &pObj->pWS[i+1];
|
|
pObj->pWS[i].pLast = &pObj->pWS[i-1];
|
|
pObj->pWS[i].user = i;
|
|
|
|
}
|
|
pObj->pWS[i-1].pNext = &pObj->pWS[0];
|
|
pObj->pWS[0].pLast = &pObj->pWS[i-1];
|
|
pObj->pPj = pObj->pWS; /* aktueller Buffer fuer Projektion */
|
|
|
|
/* Ergebnis 'Y' der Faltung (complex) */
|
|
pObj->pY = (COMPLEX*)AvMemAlloc(pObj->C*sizeof(COMPLEX));
|
|
AvZeroMem(pObj->pY,pObj->C*sizeof(COMPLEX));
|
|
|
|
/* Overlap-Save 'xs' */
|
|
pObj->pXsave = (FLOAT32*)AvMemAlloc(NP*sizeof(FLOAT32));
|
|
AvZeroMem(pObj->pXsave,NP*sizeof(FLOAT32));
|
|
|
|
/* FFT initialisieren */
|
|
pObj->pFFT = (FFT*)AvMemAlloc(sizeof(FFT));
|
|
FFTinit(pObj->pFFT, pObj->C);
|
|
|
|
return AV_E_OK;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Partitioned FFT
|
|
/*-----------------------------------------------------------------------*/
|
|
AVERR Pflms(PFLMS *pObj, FLOAT32 *pDataTD)
|
|
{
|
|
|
|
UINT32 p, s, NP;
|
|
|
|
CMPXBUF *pX, *pWS;
|
|
NP = pObj->S*pObj->L;
|
|
|
|
pX = pObj->pX; /* Aktueller Zeiger *X[C] */
|
|
pWS = pObj->pWS; /* Aktueller Zeiger *WS[C] */
|
|
|
|
/* Arbeitspuffer 'X' auffuellen Re{X[S*L..C-1]} = x[0..L] */
|
|
AvMemCpy(&pX->pData[NP].real,pDataTD, pObj->L*sizeof(FLOAT32));
|
|
|
|
/* letzten Saveblock 'xs' anfuegen Re{X[0..S*L-1]} = xs[0..S*L-1] */
|
|
AvMemCpy(&pX->pData->real,pObj->pXsave, NP*sizeof(FLOAT32));
|
|
|
|
/* Saveblock aktualisieren xs[0..S*L-1] = x[L..C-1] */
|
|
AvMemCpy(pObj->pXsave, &pDataTD[pObj->L], NP*sizeof(FLOAT32));
|
|
|
|
/* Imaginaerteil von 'X' auf Null setzen Im{X[0..C-1]} = 0 */
|
|
AvZeroMem(&pX->pData->imag,pObj->C*sizeof(FLOAT32));
|
|
|
|
/* X = FFT{x} */
|
|
fft(pObj->pFFT, &pX->pData->real, &pX->pData->imag);
|
|
|
|
/* 1. Partition Faltung im Frequenzbereich Y = X * H */
|
|
CmpxVectMul(pX->pData, pWS->pData, pObj->pY, pObj->C);
|
|
|
|
/* 2. Partition bis P-te Partition */
|
|
for (p=1; p < pObj->P; p++)
|
|
{
|
|
pWS = pWS->pNext;
|
|
|
|
for (s=0; s < pObj->S; s++)
|
|
pX = pX->pLast;
|
|
|
|
CmpxVectMac(pX->pData, pWS->pData, pObj->pY, pObj->C);
|
|
}
|
|
|
|
/* y = IFFT{Y} */
|
|
ifft(pObj->pFFT, &pObj->pY->real, &pObj->pY->imag);
|
|
|
|
/* Abspeichern der letzten L Daten */
|
|
AvMemCpy(pDataTD, &pObj->pY[NP].real, pObj->L*sizeof(FLOAT32));
|
|
|
|
return AV_E_OK;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Complex-Funktionen
|
|
/*-----------------------------------------------------------------------*/
|
|
void CmpxVectMul(struct _sCOMPLEX *pA, struct _sCOMPLEX *pB, struct _sCOMPLEX *pAB, UINT32 len)
|
|
{
|
|
UINT32 i;
|
|
|
|
for (i=0; i < len; i++)
|
|
{
|
|
pAB[i].real = pA[i].real*pB[i].real - pA[i].imag*pB[i].imag;
|
|
pAB[i].imag = pA[i].real*pB[i].imag + pA[i].imag*pB[i].real;
|
|
}
|
|
}
|
|
|
|
void CmpxVectAdd(struct _sCOMPLEX *pA, struct _sCOMPLEX *pB, struct _sCOMPLEX *pAB, UINT32 len)
|
|
{
|
|
UINT32 i;
|
|
|
|
for (i=0; i < len; i++)
|
|
{
|
|
pAB[i].real = pA[i].real + pB[i].real;
|
|
pAB[i].imag = pA[i].imag + pB[i].imag;
|
|
}
|
|
}
|
|
|
|
void CmpxVectMac(struct _sCOMPLEX *pA, struct _sCOMPLEX *pB, struct _sCOMPLEX *pAB, UINT32 len)
|
|
{
|
|
UINT32 i;
|
|
|
|
for (i=0; i < len; i++)
|
|
{
|
|
pAB[i].real += pA[i].real*pB[i].real - pA[i].imag*pB[i].imag;
|
|
pAB[i].imag += pA[i].real*pB[i].imag + pA[i].imag*pB[i].real;
|
|
}
|
|
}
|
|
|
|
void RealVectSquConj(struct _sCOMPLEX *pA, FLOAT32 *pAA, UINT32 len)
|
|
{
|
|
UINT32 i;
|
|
|
|
for (i=0; i < len; i++)
|
|
{
|
|
pAA[i] = pA[i].real*pA[i].real + pA[i].imag*pA[i].imag;
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|