Exemplo n.º 1
0
status_t Fft(double real[], double imag[], double td[], int n)
{
    mcon::Vector<double> input;
    mcon::Matrix<double> complex;

    if ( false == input.Resize(n) )
    {
        return -ERROR_CANNOT_ALLOCATE_MEMORY;
    }
    if ( false == complex.Resize(2, n) )
    {
        return -ERROR_CANNOT_ALLOCATE_MEMORY;
    }
    memcpy(input, td, sizeof(double) * n);

    status_t status;
    status = Fft(complex, input);

    if ( NO_ERROR == status )
    {
        memcpy(real, complex[0], n * sizeof(double));
        memcpy(imag, complex[1], n * sizeof(double));
    }
    return status;
}
Exemplo n.º 2
0
/* FFT of real function (size must be a power of two) */
void RealFft(float *array, int size, int sign)
{
  int     i, i1, i2, i3, i4;
  double  s1, s2, qr, qi, rr, ri;
  double  zr, zi, zpr, zpi, r, angle;

  angle = PI/(size/2); 
  s1 = 0.5;
  if (sign > 0) {
    s2 = -0.5;        
    Fft(array, size/2, 1);
  }
  else {
    s2 = 0.5;         
    angle = -angle;
  }
  r = sin(0.5*angle);
  zpr = -2.0*r*r;     zpi = sin(angle);
  zr = 1.0 + zpr;     zi = zpi;
  for (i=2; i<= size/4; i++) {
    i1 = 2*i - 1;
    i2 = i1 + 1;
    i3 = size + 3 - i2;
    i4 = i3 + 1;
    qr = s1*(array[i1] + array[i3]);
    qi = s1*(array[i2] - array[i4]);
    rr = -s2*(array[i2] + array[i4]);
    ri =  s2*(array[i1] - array[i3]);
    array[i1]  =  qr + zr*rr - zi*ri;
    array[i2]  =  qi + zr*ri + zi*rr;
    array[i3]  =  qr - zr*rr + zi*ri;
    array[i4]  = -qi + zr*ri + zi*rr;
    r = zr;
    zr = r*zpr - zi*zpi + zr;
    zi = zi*zpr + r*zpi + zi;
  }
  qr = array[1];
  if (sign > 0) {
    array[1] = qr + array[2];
    array[2] = qr - array[2];
  }
  else {
    array[1] = s1*(qr + array[2]);
    array[2] = s1*(qr - array[2]);
    Fft(array, size/2, -1);
  }
}
Exemplo n.º 3
0
/******************************************************************************\
* OFDM-demodulation                                                            *
\******************************************************************************/
void COFDMDemodulation::ProcessDataInternal(CParameter& ReceiverParam)
{
	int i;

	/* Copy data from CVector in CMatlib vector */
	for (i = 0; i < iInputBlockSize; i++)
		veccFFTInput[i] = (*pvecInputData)[i];

	/* Calculate Fourier transformation (actual OFDM demodulation) */
	veccFFTOutput = Fft(veccFFTInput, FftPlan);

	/* Use only useful carriers and normalize with the block-size ("N"). Check
	   if spectrum can be cut in one step or two steps */
	if (iShiftedKmin < 0)
	{
		/* Spectrum must be cut in two steps since some parts are on the left
		   side of the DC frequency */
		for (i = iShiftedKmin; i < 0; i++)
		{
			(*pvecOutputData)[i - iShiftedKmin] =
				veccFFTOutput[iDFTSize + i] / (CReal) iDFTSize;
		}

		for (i = 0; i < iShiftedKmax + 1; i++)
		{
			(*pvecOutputData)[i - iShiftedKmin] =
				veccFFTOutput[i] / (CReal) iDFTSize;
		}
	}
	else
	{
		/* DRM spectrum is completely on the right side of the DC carrier and
		   can be cut in one step */
		for (i = iShiftedKmin; i < iShiftedKmax + 1; i++)
		{
			(*pvecOutputData)[i - iShiftedKmin] =
				veccFFTOutput[i] / (CReal) iDFTSize;
		}
	}


	/* Save averaged spectrum for plotting ---------------------------------- */
	/* Average power (using power of this tap) (first order IIR filter) */
	for (i = 0; i < iLenPowSpec; i++)
		IIR1(vecrPowSpec[i], SqMag(veccFFTOutput[i]), rLamPSD);
}
Exemplo n.º 4
0
/******************************************************************************\
* OFDM-demodulation only for simulation purposes, with guard interval removal  *
\******************************************************************************/
void COFDMDemodSimulation::ProcessDataInternal(CParameter& ReceiverParam)
{
	int i, j;
	int iEndPointGuardRemov;

	/* Guard-interval removal parameter */
	iEndPointGuardRemov = iSymbolBlockSize - iGuardSize + iStartPointGuardRemov;


	/* Regular signal *********************************************************/
	/* Convert input vector in fft-vector type and cut out the guard-interval */
	for (i = iStartPointGuardRemov; i < iEndPointGuardRemov; i++)
		veccFFTInput[i - iStartPointGuardRemov] = (*pvecInputData)[i].tOut;

	/* Actual OFDM demodulation */
	/* Calculate Fourier transformation (actual OFDM demodulation) */
	veccFFTOutput = Fft(veccFFTInput, FftPlan);

	/* Use only useful carriers and normalize with the block-size ("N") */
	for (i = iShiftedKmin; i < iShiftedKmax + 1; i++)
	{
		(*pvecOutputData2)[i - iShiftedKmin].tOut =
			veccFFTOutput[i] / (CReal) iDFTSize;
	}

	/* We need the same information for channel estimation evaluation, too */
	for (i = 0; i < iNumCarrier; i++)
		(*pvecOutputData)[i] = (*pvecOutputData2)[i].tOut;


	/* Channel-in signal ******************************************************/
	/* Convert input vector in fft-vector type and cut out the guard-interval
	   We have to cut out the FFT window at the correct position, because the
	   channel estimation has information only about the original pilots
	   which are not phase shifted due to a timing-offset. To be able to
	   compare reference signal and channel estimation output we have to use
	   the synchronous reference signal for input */
	for (i = iGuardSize; i < iSymbolBlockSize; i++)
		veccFFTInput[i - iGuardSize] = (*pvecInputData)[i].tIn;

	/* Actual OFDM demodulation */
	/* Calculate Fourier transformation (actual OFDM demodulation) */
	veccFFTOutput = Fft(veccFFTInput, FftPlan);

	/* Use only useful carriers and normalize with the block-size ("N") */
	for (i = iShiftedKmin; i < iShiftedKmax + 1; i++)
	{
		(*pvecOutputData2)[i - iShiftedKmin].tIn =
			veccFFTOutput[i] / (CReal) iDFTSize;
	}


	/* Reference signal *******************************************************/
	/* Convert input vector in fft-vector type and cut out the guard-interval */
	for (i = iStartPointGuardRemov; i < iEndPointGuardRemov; i++)
		veccFFTInput[i - iStartPointGuardRemov] = (*pvecInputData)[i].tRef;

	/* Actual OFDM demodulation */
	/* Calculate Fourier transformation (actual OFDM demodulation) */
	veccFFTOutput = Fft(veccFFTInput, FftPlan);

	/* Use only useful carriers and normalize with the block-size ("N") */
	for (i = iShiftedKmin; i < iShiftedKmax + 1; i++)
	{
		(*pvecOutputData2)[i - iShiftedKmin].tRef =
			veccFFTOutput[i] / (CReal) iDFTSize;
	}


	/* Channel tap gains ******************************************************/
	/* Loop over all taps */
	for (j = 0; j < iNumTapsChan; j++)
	{
		/* Convert input vector in fft-vector type and cut out the
		   guard-interval */
		for (i = iStartPointGuardRemov; i < iEndPointGuardRemov; i++)
			veccFFTInput[i - iStartPointGuardRemov] =
				(*pvecInputData)[i].veccTap[j];

		/* Actual OFDM demodulation */
		/* Calculate Fourier transformation (actual OFDM demodulation) */
		veccFFTOutput = Fft(veccFFTInput, FftPlan);

		/* Use only useful carriers and normalize with the block-size ("N") */
		for (i = 0; i < iNumCarrier; i++)
		{
			(*pvecOutputData2)[i].veccTap[j] =
				veccFFTOutput[i] / (CReal) iDFTSize;
		}

		/* Store the end of the vector, too */
		for (i = 0; i < iNumCarrier; i++)
		{
			(*pvecOutputData2)[i].veccTapBackw[j] =
				veccFFTOutput[iDFTSize - i - 1] / (CReal) iDFTSize;
		}
	}


	/* Take care of symbol IDs ---------------------------------------------- */
	iSymbolCounterTiSy++;
	if (iSymbolCounterTiSy == iNumSymPerFrame)
		iSymbolCounterTiSy = 0;

	/* Set current symbol ID in extended data of output vector */
	(*pvecOutputData).GetExData().iSymbolID = iSymbolCounterTiSy;
	(*pvecOutputData2).GetExData().iSymbolID = iSymbolCounterTiSy;

	/* No timing corrections, timing is constant in this case */
	(*pvecOutputData).GetExData().iCurTimeCorr = 0;
	(*pvecOutputData2).GetExData().iCurTimeCorr = 0;

	/* Symbol ID index is always ok */
	(*pvecOutputData).GetExData().bSymbolIDHasChanged = FALSE;
	(*pvecOutputData2).GetExData().bSymbolIDHasChanged = FALSE;
}
Exemplo n.º 5
0
/* Implementation *************************************************************/
void CChannelEstimation::ProcessDataInternal(CParameter& ReceiverParam)
{
	int			i, j, k;
	int			iModSymNum;
	_COMPLEX	cModChanEst;
	_REAL		rSNRAftTiInt;
	_REAL		rCurSNREst;
	_REAL		rOffsPDSEst;

	/* Check if symbol ID index has changed by the synchronization unit. If it
	   has changed, reinit this module */
	if ((*pvecInputData).GetExData().bSymbolIDHasChanged == TRUE)
	{
		SetInitFlag();
		return;
	}

	/* Move data in history-buffer (from iLenHistBuff - 1 towards 0) */
	for (j = 0; j < iLenHistBuff - 1; j++)
	{
		for (i = 0; i < iNumCarrier; i++)
			matcHistory[j][i] = matcHistory[j + 1][i];
	}

	/* Write new symbol in memory */
	for (i = 0; i < iNumCarrier; i++)
		matcHistory[iLenHistBuff - 1][i] = (*pvecInputData)[i];


	/* Time interpolation *****************************************************/
	/* Get symbol-counter for next symbol. Use the count from the frame 
	   synchronization (in OFDM.cpp). Call estimation routine */
	rSNRAftTiInt = 
		pTimeInt->Estimate(pvecInputData, veccPilots, 
						   ReceiverParam.matiMapTab[(*pvecInputData).
						   GetExData().iSymbolID],
						   ReceiverParam.matcPilotCells[(*pvecInputData).
						   GetExData().iSymbolID], rSNREstimate);

	/* Debar initialization of channel estimation in time direction */
	if (iInitCnt > 0)
	{
		iInitCnt--;

		/* Do not put out data in initialization phase */
		iOutputBlockSize = 0;

		/* Do not continue */
		return;
	}
	else
		iOutputBlockSize = iNumCarrier; 

	/* Define DC carrier for robustness mode D because there is not pilot */
	if (iDCPos != 0)
		veccPilots[iDCPos] = (CReal) 0.0;


	/* -------------------------------------------------------------------------
	   Use time-interpolated channel estimate for timing synchronization 
	   tracking */
	TimeSyncTrack.Process(ReceiverParam, veccPilots, 
		(*pvecInputData).GetExData().iCurTimeCorr, rLenPDSEst /* out */,
		rOffsPDSEst /* out */);


	/* Frequency-interploation ************************************************/
	switch (TypeIntFreq)
	{
	case FLINEAR:
		/**********************************************************************\
		 * Linear interpolation												  *
		\**********************************************************************/
		/* Set first pilot position */
		veccChanEst[0] = veccPilots[0];

		for (j = 0, k = 1; j < iNumCarrier - iScatPilFreqInt;
			j += iScatPilFreqInt, k++)
		{
			/* Set values at second time pilot position in cluster */
			veccChanEst[j + iScatPilFreqInt] = veccPilots[k];

			/* Interpolation cluster */
			for (i = 1; i < iScatPilFreqInt; i++)
			{
				/* E.g.: c(x) = (c_4 - c_0) / 4 * x + c_0 */
				veccChanEst[j + i] =
					(veccChanEst[j + iScatPilFreqInt] - veccChanEst[j]) /
					(_REAL) (iScatPilFreqInt) * (_REAL) i + veccChanEst[j];
			}
		}
		break;

	case FDFTFILTER:
		/**********************************************************************\
		 * DFT based algorithm												  *
		\**********************************************************************/
		/* ---------------------------------------------------------------------
		   Put all pilots at the beginning of the vector. The "real" length of
		   the vector "pcFFTWInput" is longer than the No of pilots, but we 
		   calculate the FFT only over "iNumCarrier / iScatPilFreqInt + 1"
		   values (this is the number of pilot positions) */
		/* Weighting pilots with window */
		veccPilots *= vecrDFTWindow;

		/* Transform in time-domain */
		veccPilots = Ifft(veccPilots, FftPlanShort);

		/* Set values outside a defined bound to zero, zero padding (noise
		   filtering). Copy second half of spectrum at the end of the new vector
		   length and zero out samples between the two parts of the spectrum */
		veccIntPil.Merge(
			/* First part of spectrum */
			veccPilots(1, iStartZeroPadding), 
			/* Zero padding in the middle, length: Total length minus length of
			   the two parts at the beginning and end */
			CComplexVector(Zeros(iLongLenFreq - 2 * iStartZeroPadding), 
			Zeros(iLongLenFreq - 2 * iStartZeroPadding)), 
			/* Set the second part of the actual spectrum at the end of the new
			   vector */
			veccPilots(iNumIntpFreqPil - iStartZeroPadding + 1, 
			iNumIntpFreqPil));

		/* Transform back in frequency-domain */
		veccIntPil = Fft(veccIntPil, FftPlanLong);

		/* Remove weighting with DFT window by inverse multiplication */
		veccChanEst = veccIntPil(1, iNumCarrier) * vecrDFTwindowInv;
		break;

	case FWIENER:
		/**********************************************************************\
		 * Wiener filter													   *
		\**********************************************************************/
#ifdef UPD_WIENER_FREQ_EACH_DRM_FRAME
		/* Update filter coefficients once in one DRM frame */
		if (iUpCntWienFilt > 0)
		{
			iUpCntWienFilt--;

			/* Get maximum delay spread and offset in one DRM frame */
			if (rLenPDSEst > rMaxLenPDSInFra)
				rMaxLenPDSInFra = rLenPDSEst;

			if (rOffsPDSEst < rMinOffsPDSInFra)
				rMinOffsPDSInFra = rOffsPDSEst;
		}
		else
		{
#else
		/* Update Wiener filter each OFDM symbol. Use current estimates */
		rMaxLenPDSInFra = rLenPDSEst;
		rMinOffsPDSInFra = rOffsPDSEst;
#endif
			/* Update filter taps */
			UpdateWienerFiltCoef(rSNRAftTiInt, rMaxLenPDSInFra / iNumCarrier,
				rMinOffsPDSInFra / iNumCarrier);

#ifdef UPD_WIENER_FREQ_EACH_DRM_FRAME
			/* Reset counter and maximum storage variable */
			iUpCntWienFilt = iNumSymPerFrame;
			rMaxLenPDSInFra = (_REAL) 0.0;
			rMinOffsPDSInFra = rGuardSizeFFT;
		}
#endif

		/* FIR filter of the pilots with filter taps. We need to filter the
		   pilot positions as well to improve the SNR estimation (which 
		   follows this procedure) */
		for (j = 0; j < iNumCarrier; j++)
		{
			/* Convolution */
			veccChanEst[j] = _COMPLEX((_REAL) 0.0, (_REAL) 0.0);

			for (i = 0; i < iLengthWiener; i++)
				veccChanEst[j] += 
					matcFiltFreq[j][i] * veccPilots[veciPilOffTab[j] + i];
		}
		break;
	}


	/* Equalize the output vector ------------------------------------------- */
	/* Write to output vector. Take oldest symbol of history for output. Also,
	   ship the channel state at a certain cell */
	for (i = 0; i < iNumCarrier; i++)
	{
		(*pvecOutputData)[i].cSig = matcHistory[0][i] / veccChanEst[i];
		(*pvecOutputData)[i].rChan = SqMag(veccChanEst[i]);
	}


	/* -------------------------------------------------------------------------
	   Calculate symbol ID of the current output block and set parameter */
	(*pvecOutputData).GetExData().iSymbolID = 
		(*pvecInputData).GetExData().iSymbolID - iLenHistBuff + 1;


	/* SNR estimation ------------------------------------------------------- */
	/* Modified symbol ID, check range {0, ..., iNumSymPerFrame} */
	iModSymNum = (*pvecOutputData).GetExData().iSymbolID;

	while (iModSymNum < 0)
		iModSymNum += iNumSymPerFrame;

	for (i = 0; i < iNumCarrier; i++)
	{
		switch (TypeSNREst)
		{
		case SNR_PIL:
			/* Use estimated channel and compare it to the received pilots. This
			   estimation works only if the channel estimation was successful */
			/* Identify pilot positions. Use MODIFIED "iSymbolID" (See lines
			   above) */
			if (_IsScatPil(ReceiverParam.matiMapTab[iModSymNum][i]))
			{
				/* We assume that the channel estimation in "veccChanEst" is
				   noise free (e.g., the wiener interpolation does noise
				   reduction). Thus, we have an estimate of the received signal
				   power \hat{r} = s * \hat{h}_{wiener} */
				cModChanEst = veccChanEst[i] *
					ReceiverParam.matcPilotCells[iModSymNum][i];


				/* Calculate and average noise and signal estimates --------- */
				/* The noise estimation is difference between the noise reduced
				   signal and the noisy received signal
				   \tilde{n} = \hat{r} - r */
				IIR1(rNoiseEst, SqMag(matcHistory[0][i] - cModChanEst),
					rLamSNREstFast);

				/* The received signal power estimation is just \hat{r} */
				IIR1(rSignalEst, SqMag(cModChanEst), rLamSNREstFast);

				/* Calculate final result (signal to noise ratio) */
				if (rNoiseEst != 0)
					rCurSNREst = rSignalEst / rNoiseEst;
				else
					rCurSNREst = (_REAL) 1.0;

				/* Bound the SNR at 0 dB */
				if (rCurSNREst < (_REAL) 1.0)
					rCurSNREst = (_REAL) 1.0;

				/* Average the SNR with a two sided recursion */
				IIR1TwoSided(rSNREstimate, rCurSNREst, rLamSNREstFast,
					rLamSNREstSlow);
			}
			break;

		case SNR_FAC:
			/* SNR estimation with initialization */
			if (iSNREstInitCnt > 0)
			{
				/* Initial signal estimate. Use channel estimation from all
				   cells. Apply averaging */
				rSignalEst += (*pvecOutputData)[i].rChan;

				iSNREstInitCnt--;
			}
			else
			{
				/* Only right after initialization phase apply initial SNR
				   value */
				if (bWasSNRInit == TRUE)
				{
					/* Normalize average */
					rSignalEst /= iNumCellsSNRInit;

					/* Apply initial SNR value */
					rNoiseEst = rSignalEst / rSNREstimate;

					bWasSNRInit = FALSE;
				}

				/* Only use FAC cells for this SNR estimation method */
				if (_IsFAC(ReceiverParam.matiMapTab[iModSymNum][i]))
				{
					/* Get tentative decision for current FAC cell (squared) */
					CReal rCurErrPow =
						TentativeFACDec((*pvecOutputData)[i].cSig);

					/* Use decision together with channel estimate to get
					   estimates for signal and noise */
					IIR1(rNoiseEst, rCurErrPow * (*pvecOutputData)[i].rChan,
						rLamSNREstFast);

					IIR1(rSignalEst, (*pvecOutputData)[i].rChan,
						rLamSNREstFast);

					/* Calculate final result (signal to noise ratio) */
					if (rNoiseEst != (_REAL) 0.0)
						rCurSNREst = rSignalEst / rNoiseEst;
					else
						rCurSNREst = (_REAL) 1.0;

					/* Bound the SNR at 0 dB */
					if (rCurSNREst < (_REAL) 1.0)
						rCurSNREst = (_REAL) 1.0;

					/* The channel estimation algorithms need the SNR normalized
					   to the energy of the pilots */
					rSNREstimate = rCurSNREst / rSNRCorrectFact;
				}
			}
			break;
		}
	}
}