示例#1
0
/******************************************************************************\
* OFDM-modulation                                                              *
\******************************************************************************/
void COFDMModulation::ProcessDataInternal(CParameter& TransmParam)
{
	int	i;

	/* Copy input vector in matlib vector and place bins at the correct
	   position */
	for (i = iShiftedKmin; i < iEndIndex; i++)
		veccFFTInput[i] = (*pvecInputData)[i - iShiftedKmin];

	/* Calculate inverse fast Fourier transformation */
	veccFFTOutput = Ifft(veccFFTInput, FftPlan);

	/* Copy complex FFT output in output buffer and scale */
	for (i = 0; i < iDFTSize; i++)
		(*pvecOutputData)[i + iGuardSize] = veccFFTOutput[i] * (CReal) iDFTSize;

	/* Copy data from the end to the guard-interval (Add guard-interval) */
	for (i = 0; i < iGuardSize; i++)
		(*pvecOutputData)[i] = (*pvecOutputData)[iDFTSize + i];


	/* Shift spectrum to desired IF ----------------------------------------- */
	/* Only apply shifting if phase is not zero */
	if (cExpStep != _COMPLEX((_REAL) 1.0, (_REAL) 0.0))
	{
		for (i = 0; i < iOutputBlockSize; i++)
		{
			(*pvecOutputData)[i] = (*pvecOutputData)[i] * Conj(cCurExp);
			
			/* Rotate exp-pointer on step further by complex multiplication
			   with precalculated rotation vector cExpStep. This saves us from
			   calling sin() and cos() functions all the time (iterative
			   calculation of these functions) */
			cCurExp *= cExpStep;
		}
	}
}
示例#2
0
/* Implementation *************************************************************/
void CSyncUsingPil::ProcessDataInternal(CParameter& ReceiverParam)
{
	int i;

	/**************************************************************************\
	* Frame synchronization detection										   *
	\**************************************************************************/
	_BOOLEAN bSymbolIDHasChanged = FALSE;

	if ((bSyncInput == FALSE) && (bAquisition == TRUE))
	{
#ifdef USE_DRM_FRAME_SYNC_IR_BASED
		/* DRM frame synchronization using impulse response ----------------- */
		/* We assume that the current received OFDM symbol is the first symbol
		   in a DRM frame and estimate the channel transfer function at the
		   pilot positions (the positions of pilots in the first OFDM symbol in
		   a DRM frame). Then we calculate an FFT to get the impulse response of
		   the channel. If the assumption was correct and this really was the
		   correct OFDM symbol, we will get something which looks like an
		   impulse response (contains peaks -> peak-to-average ratio is high).
		   If not, we will certainly get only noise -> no peaks -> peak to
		   average ratio is small. This is because the transmitted values at
		   the pilot positions are different from the values at the pilot cells
		   when transmitting the correct OFDM symbol (which we assumed) */

		/* Pick pilot positions and calculate "test" channel estimation */
		int iCurIndex = 0;
		for (i = 0; i < iNumCarrier; i++)
		{
			if (_IsScatPil(ReceiverParam.matiMapTab[0][i]))
			{
				/* Get channel estimate */
				veccChan[iCurIndex] =
					(*pvecInputData)[i] / ReceiverParam.matcPilotCells[0][i];

				/* We have to introduce a new index because not on all carriers
				   is a pilot */
				iCurIndex++;
			}
		}

		/* Calculate abs(IFFT) for getting estimate of impulse response */
		vecrTestImpResp = Abs(Ifft(veccChan, FftPlan));

		/* Calculate peak to average */
		const CReal rResultIREst = Max(vecrTestImpResp) / Sum(vecrTestImpResp);

		/* Store correlation results in a shift register for finding the peak */
		vecrCorrHistory.AddEnd(rResultIREst);

#else

		/* DRM frame synchronization based on time pilots ------------------- */
		/* Calculate correlation of received cells with pilot pairs */
		CReal rResultPilPairCorr = (CReal) 0.0;
		for (i = 0; i < iNumPilPairs; i++)
		{
			/* Actual correlation */
			const CComplex cCorrRes = (*pvecInputData)[vecPilCorr[i].iIdx1] *
				Conj(vecPilCorr[i].cPil1) *
				Conj((*pvecInputData)[vecPilCorr[i].iIdx2]) *
				vecPilCorr[i].cPil2 * cR_HH;

			rResultPilPairCorr += Real(cCorrRes);
		}

		/* Store correlation results in a shift register for finding the peak */
		vecrCorrHistory.AddEnd(rResultPilPairCorr);
#endif


		/* Finding beginning of DRM frame in results ------------------------ */
		/* Wait until history is filled completly */
		if (iInitCntFraSy > 0)
			iInitCntFraSy--;
		else
		{
			/* Search for maximum */
			int iMaxIndex = 0;
			CReal rMaxValue = -_MAXREAL;
			for (i = 0; i < iNumSymPerFrame; i++)
			{
				if (vecrCorrHistory[i] > rMaxValue)
				{
					rMaxValue = vecrCorrHistory[i];
					iMaxIndex = i;
				}
			}

			/* For initial frame synchronization, use maximum directly */
			if (bInitFrameSync == TRUE)
			{
				/* Reset init flag */
				bInitFrameSync = FALSE;

				/* Set symbol ID index according to received data */
				iSymbCntFraSy = iNumSymPerFrame - iMaxIndex - 1;
			}
			else
			{
				/* If maximum is in the middle of the interval
				   (check frame sync) */
				if (iMaxIndex == iMiddleOfInterval)
				{
					if (iSymbCntFraSy == iNumSymPerFrame - iMiddleOfInterval - 1)
					{
						/* Reset flags */
						bBadFrameSync = FALSE;
						bFrameSyncWasOK = TRUE;

						/* Post Message for GUI (Good frame sync) */
						PostWinMessage(MS_FRAME_SYNC, 0); /* green */
					}
					else
					{
						if (bBadFrameSync == TRUE)
						{
							/* Reset symbol ID index according to received
							   data */
							iSymbCntFraSy =
								iNumSymPerFrame - iMiddleOfInterval - 1;

							/* Inform that symbol ID has changed */
							bSymbolIDHasChanged = TRUE;

							/* Reset flag */
							bBadFrameSync = FALSE;

							PostWinMessage(MS_FRAME_SYNC, 2); /* red */
						}
						else
						{
							/* One false detected frame sync should not reset
							   the actual frame sync because the measurement
							   could be wrong. Sometimes the frame sync
							   detection gets false results. If the next time
							   the frame sync is still unequal to the
							   measurement, then correct it */
							bBadFrameSync = TRUE;

							if (bFrameSyncWasOK == TRUE)
							{
								/* Post Message that frame sync was wrong but
								   was not yet corrected (yellow light) */
								PostWinMessage(MS_FRAME_SYNC, 1); /* yellow */
							}
							else
								PostWinMessage(MS_FRAME_SYNC, 2); /* red */
						}

						/* Set flag for bad sync */
						bFrameSyncWasOK = FALSE;
					}
				}
			}
		}
	}
	else
	{
		/* Frame synchronization has successfully finished, show always green
		   light */
		PostWinMessage(MS_FRAME_SYNC, 0);
	}

	/* Set current symbol ID and flag in extended data of output vector */
	(*pvecOutputData).GetExData().iSymbolID = iSymbCntFraSy;
	(*pvecOutputData).GetExData().bSymbolIDHasChanged = bSymbolIDHasChanged;

	/* Increase symbol counter and take care of wrap around */
	iSymbCntFraSy++;
	if (iSymbCntFraSy >= iNumSymPerFrame)
		iSymbCntFraSy = 0;


	/**************************************************************************\
	* Using Frequency pilot information										   *
	\**************************************************************************/
	if ((bSyncInput == FALSE) && (bTrackPil == TRUE))
	{
		CComplex cFreqOffEstVecSym = CComplex((CReal) 0.0, (CReal) 0.0);

		for (i = 0; i < NUM_FREQ_PILOTS; i++)
		{
			/* The old pilots must be rotated due to timing corrections */
			const CComplex cOldFreqPilCorr =
				Rotate(cOldFreqPil[i], iPosFreqPil[i],
				(*pvecInputData).GetExData().iCurTimeCorr);

			/* Calculate the inner product of the sum */
			const CComplex cCurPilMult =
				(*pvecInputData)[iPosFreqPil[i]] * Conj(cOldFreqPilCorr);

			/* Save "old" frequency pilots for next symbol. Special treatment
			   for robustness mode D (carriers 7 and 21) necessary 
			   (See 8.4.2.2) */
			if ((ReceiverParam.GetWaveMode() == RM_ROBUSTNESS_MODE_E) &&
				(i < 2))
			{
				cOldFreqPil[i] = -(*pvecInputData)[iPosFreqPil[i]];
			}
			else
				cOldFreqPil[i] = (*pvecInputData)[iPosFreqPil[i]];

#ifdef USE_SAMOFFS_TRACK_FRE_PIL
			/* Get phase difference for sample rate offset estimation. Average
			   the vector, real and imaginary part separately */
			IIR1(cFreqPilotPhDiff[i], cCurPilMult, rLamSamRaOff);
#endif

			/* Calculate estimation of frequency offset */
			cFreqOffEstVecSym += cCurPilMult;
		}


		/* Frequency offset ------------------------------------------------- */
		/* Correct frequency offset estimation for resample offset corrections.
		   When a sample rate offset correction was applied, the frequency
		   offset is shifted proportional to this correction. The correction
		   is mandatory if large sample rate offsets occur */

		/* Get sample rate offset change */
		const CReal rDiffSamOffset =
			rPrevSamRateOffset - ReceiverParam.rResampleOffset;

		/* Save current resample offset for next symbol */
		rPrevSamRateOffset = ReceiverParam.rResampleOffset;

		/* Correct sample-rate offset correction according to the proportional
		   rule. Use relative DC frequency offset plus relative average offset
		   of frequency pilots to the DC frequency. Normalize this offset so
		   that it can be used as a phase correction for frequency offset
		   estimation  */
		CReal rPhaseCorr = (ReceiverParam.rFreqOffsetAcqui +
			ReceiverParam.rFreqOffsetTrack + rAvFreqPilDistToDC) *
			rDiffSamOffset / SOUNDCRD_SAMPLE_RATE / rNormConstFOE;

		/* Actual correction (rotate vector) */
		cFreqOffVec *= CComplex(Cos(rPhaseCorr), Sin(rPhaseCorr));


		/* Average vector, real and imaginary part separately */
		IIR1(cFreqOffVec, cFreqOffEstVecSym, rLamFreqOff);

		/* Calculate argument */
		const CReal rFreqOffsetEst = Angle(cFreqOffVec);

		/* Correct measurement average for actually applied frequency
		   correction */
		cFreqOffVec *= CComplex(Cos(-rFreqOffsetEst), Sin(-rFreqOffsetEst));

#ifndef USE_FRQOFFS_TRACK_GUARDCORR
		/* Integrate the result for controling the frequency offset, normalize
		   estimate */
		ReceiverParam.rFreqOffsetTrack += rFreqOffsetEst * rNormConstFOE;
#endif


#ifdef USE_SAMOFFS_TRACK_FRE_PIL
		/* Sample rate offset ----------------------------------------------- */
		/* Calculate estimation of sample frequency offset. We use the different
		   frequency offset estimations of the frequency pilots. We normalize
		   them with the distance between them and average the result (/ 2.0) */
		CReal rSampFreqOffsetEst =
			((Angle(cFreqPilotPhDiff[1]) - Angle(cFreqPilotPhDiff[0])) /
			(iPosFreqPil[1] - iPosFreqPil[0]) +
			(Angle(cFreqPilotPhDiff[2]) - Angle(cFreqPilotPhDiff[0])) /
			(iPosFreqPil[2] - iPosFreqPil[0])) / (CReal) 2.0;

		/* Integrate the result for controling the resampling */
		ReceiverParam.rResampleOffset +=
			CONTR_SAMP_OFF_INTEGRATION * rSampFreqOffsetEst;
#endif

#ifdef _DEBUG_
/* Save frequency and sample rate tracking */
static FILE* pFile = fopen("test/freqtrack.dat", "w");
fprintf(pFile, "%e %e\n", SOUNDCRD_SAMPLE_RATE * ReceiverParam.rFreqOffsetTrack,
	ReceiverParam.rResampleOffset);
fflush(pFile);
#endif
	}


	/* If synchronized DRM input stream is used, overwrite the detected
	   frequency offest estimate by "0", because we know this value */
	if (bSyncInput == TRUE)
		ReceiverParam.rFreqOffsetTrack = (CReal) 0.0;

	/* Do not ship data before first frame synchronization was done. The flag
	   "bAquisition" must not be set to FALSE since in that case we would run
	   into an infinite loop since we would not ever ship any data. But since
	   the flag is set after this module, we should be fine with that. */
	if ((bInitFrameSync == TRUE) && (bSyncInput == FALSE))
		iOutputBlockSize = 0;
	else
	{
		iOutputBlockSize = iNumCarrier;

		/* Copy data from input to the output. Data is not modified in this
		   module */
		for (i = 0; i < iOutputBlockSize; i++)
			(*pvecOutputData)[i] = (*pvecInputData)[i];
	}
}
示例#3
0
/* Implementation *************************************************************/
void CTimeSyncTrack::Process(CParameter& Parameter,
			     CComplexVector& veccChanEst, int iNewTiCorr,
			     FXP& rLenPDS_fxp, FXP& rOffsPDS_fxp)
{
  int			i, j;
  int			iIntShiftVal;
  int			iFirstPathDelay;
  CFReal		rPeakBound_fxp;	  
  CFReal		rPropGain_fxp;  
  long long		rCurEnergy_fxp;  
  long long		rWinEnergy_fxp;  
  long long		rMaxWinEnergy_fxp;
  
  _BOOLEAN	bDelayFound;        //ok
  _BOOLEAN	bPDSResultFound;    //ok
  
  /* Rotate the averaged PDP to follow the time shifts -------------------- */
  /* Update timing correction history (shift register) */
  vecTiCorrHist.AddEnd(iNewTiCorr);
  
  /* Calculate the actual shift of the timing correction. Since we do the
     timing correction at the sound card sample rate (48 kHz) and the
     estimated impulse response has a different sample rate (since the
     spectrum is only one little part of the sound card frequency range)
     we have to correct the timing correction by a certain bandwidth factor */
  
  const CFReal rActShiftTiCor_fxp = rFracPartTiCor_fxp -
    (_FREAL) vecTiCorrHist[0] * iNumCarrier / iDFTSize;
  
  /* Integer part of shift */
  const int iIntPartTiCorr = (int) Round(rActShiftTiCor_fxp);
  
  /* Extract the fractional part since we can only correct integer timing
     shifts */
  rFracPartTiCor_fxp = rActShiftTiCor_fxp - iIntPartTiCorr;
  
  /* Shift the values in the vector storing the averaged impulse response. We
     have to consider two cases for shifting (left and right shift) */
  if (rActShiftTiCor_fxp < 0)
    iIntShiftVal = iIntPartTiCorr + iNumIntpFreqPil;
  else
    iIntShiftVal = iIntPartTiCorr;
  
  /* If new correction is out of range, do not apply rotation */
  if ((iIntShiftVal > 0) && (iIntShiftVal < iNumIntpFreqPil))
    {
      /* Actual rotation of vector */
      vecrAvPoDeSp.Merge(vecrAvPoDeSp(iIntShiftVal + 1, iNumIntpFreqPil),
			 vecrAvPoDeSp(1, iIntShiftVal));
    }
  /* New estimate for impulse response ------------------------------------ */
  /* Apply hamming window, Eq (15) */
  veccPilots = veccChanEst * vecrHammingWindow;
  
  /* Transform in time-domain to get an estimate for the delay power profile,
     Eq (15) */
  veccPilots = Ifft(veccPilots, FftPlan);
  
  /* Average result, Eq (16) (Should be a moving average function, for
     simplicity we have chosen an IIR filter here) */
  IIR1(vecrAvPoDeSp, SqMag(veccPilots), rLamAvPDS);
  
  /* Rotate the averaged result vector to put the earlier peaks
     (which can also detected in a certain amount) at the beginning of
     the vector */
  vecrAvPoDeSpRot.Merge(vecrAvPoDeSp(iStPoRot, iNumIntpFreqPil),
			vecrAvPoDeSp(1, iStPoRot - 1));
  
  
  /* Different timing algorithms ------------------------------------------ */
  switch (TypeTiSyncTrac)
    {
    case TSFIRSTPEAK:
      /* Detect first peak algorithm proposed by Baoguo Yang */
      /* Lower and higher bound */
      rBoundHigher = Max(vecrAvPoDeSpRot) * rConst1;  //ok
      rBoundLower = Min(vecrAvPoDeSpRot) * rConst2;   //ok
      
      /* Calculate the peak bound, Eq (19) */
      rPeakBound_fxp = FXP (Max(rBoundHigher, rBoundLower));
      
      /* Get final estimate, Eq (18) */
      bDelayFound = FALSE; /* Init flag */
      for (i = 0; i < iNumIntpFreqPil - 1; i++)
	{
	  /* We are only interested in the first peak */
	  if (bDelayFound == FALSE)
	    {
	      if ((vecrAvPoDeSpRot[i] > vecrAvPoDeSpRot[i + 1]) &&
		  (FXP (vecrAvPoDeSpRot[i]) > rPeakBound_fxp))
		{
		  /* The first peak was found, store index */
		  iFirstPathDelay = i;
		  
		  /* Set the flag */
		  bDelayFound = TRUE;
		}
	    }
	}
      break;
      
    case TSENERGY:
      /* Determin position of window with maximum energy in guard-interval.
	 A window with the size of the guard-interval is moved over the entire
	 profile and the energy inside this window is calculated. The window
	 position which maximises this energy is taken as the new timing
	 position */
      rMaxWinEnergy_fxp = 0;
      iFirstPathDelay = 0;
      for (i = 0; i < iNumIntpFreqPil - 1 - rGuardSizeFFT; i++)
	{
	  rWinEnergy_fxp = 0;
	  
	  /* Energy IN the guard-interval */
	  for (j = 0; j < rGuardSizeFFT; j++)
	    rWinEnergy_fxp += (long long)(vecrAvPoDeSpRot[i + j]*(1<<FXP_TIME_SYNC_TRACK_SCALE));
	  
	  /* Get maximum */
	  if (rWinEnergy_fxp > rMaxWinEnergy_fxp)
	    {
	      rMaxWinEnergy_fxp = rWinEnergy_fxp;
	      iFirstPathDelay = i;
	    }
	}
      
      /* We always have a valid measurement, set flag */
      bDelayFound = TRUE;
      break;
    }
  
  
  /* Only apply timing correction if search was successful and tracking is
     activated */
  if ((bDelayFound == TRUE) && (bTiSyncTracking == TRUE))
    {
      /* Consider the rotation introduced for earlier peaks in path delay.
	 Since the "iStPoRot" is the position of the beginning of the block
	 at the end for cutting out, "iNumIntpFreqPil" must be substracted.
	 (Actually, a part of the following line should be look like this:
	 "iStPoRot - 1 - iNumIntpFreqPil + 1" but the "- 1 + 1" compensate
	 each other) */
      iFirstPathDelay += iStPoRot - iNumIntpFreqPil - iTargetTimingPos - 1;
      
      
      /* Correct timing offset -------------------------------------------- */
      /* Final offset is target position in comparision to the estimated first
	 path delay. Since we have a delay from the channel estimation, the
	 previous correction is subtracted "- vecrNewMeasHist[0]". If the
	 "real" correction arrives after the delay, this correction is
	 compensated. The length of the history buffer (vecrNewMeasHist) must
	 be equal to the delay of the channel estimation.
	 The corrections must be quantized to the upsampled output sample
	 rate ("* iDFTSize / iNumCarrier") */
      iDFTSize / iNumCarrier - veciNewMeasHist[0];
      const CFReal rTiOffset_fxp = (CFReal) -iFirstPathDelay *
	iDFTSize / iNumCarrier - veciNewMeasHist[0];
      
      /* Different controlling parameters for different types of tracking */
      switch (TypeTiSyncTrac)
	{
	case TSFIRSTPEAK:
	  /* Adapt the linear control parameter to the region, where the peak
	     was found. The region left of the desired timing position is
	     critical, because we immediately get ISI if a peak appers here.
	     Therefore we apply fast correction here. At the other positions,
	     we smooth the controlling to improve the immunity against false
	     peaks */
	  if (rTiOffset_fxp > 0)
	    rPropGain_fxp = CONT_PROP_BEFORE_GUARD_INT;
	  else
	    rPropGain_fxp = CONT_PROP_IN_GUARD_INT;
	  break;
	  
	case TSENERGY:
	  rPropGain_fxp = CONT_PROP_ENERGY_METHOD;
	  break;
	}
      
      /* In case of sample rate offset acquisition phase, use faster timing
	 corrections */
      if (bSamRaOffsAcqu == TRUE)
	rPropGain_fxp *= 2;
      
      /* Apply proportional control and fix result to sample grid */
      const CFReal rCurCorrValue_fxp = rTiOffset_fxp * rPropGain_fxp + rFracPartContr_fxp;
      
      const int iContrTiOffs = (int) Fix(rCurCorrValue_fxp);
      
      /* Calculate new fractional part of controlling */
      rFracPartContr_fxp = rCurCorrValue_fxp - iContrTiOffs;
      
      /* Manage correction history */
      veciNewMeasHist.AddEnd(0);
      for (i = 0; i < iSymDelay - 1; i++)
	veciNewMeasHist[i] += iContrTiOffs;
      
      /* Apply correction */
      Parameter.iTimingOffsTrack = -iContrTiOffs;
    }
  
  
  /* Sample rate offset estimation ---------------------------------------- */
  /* This sample rate offset estimation is based on the movement of the
     estimated PDS with time. The movement per symbol (or a number of symbols)
     is proportional to the sample rate offset. It has to be considered the
     PDS shiftings of the timing correction unit ("rActShiftTiCor" can be used
     for that). The procedere is to detect the maximum peak in the PDS and use
     this as a reference, assuming tha delay of this peak is not changing. The
     problem is when another peak get higher than this due to fading. In this
     case we must adjust the history to this new peak (the new reference) */
  int		iMaxInd;
  CReal	rMax;
  //int	rMax_fxp;
  
  /* Find index of maximum peak in PDS estimation. This is our reference
     for this estimation method */
  Max(rMax, iMaxInd, vecrAvPoDeSpRot);
  
  /* Integration of timing corrections
     FIXME: Check for overrun of "iIntegTiCorrections" variable! */
  iIntegTiCorrections += (long long) iIntPartTiCorr;
  
  /* We need to consider the timing corrections done by the timing unit. What
     we want to estimate is only the real movement of the detected maximum
     peak */
  const long long iCurRes = iIntegTiCorrections + iMaxInd;
  veciSRTiCorrHist.AddEnd(iCurRes);
  
  /* We assumed that the detected peak is always the same peak in the actual
     PDS. But due to fading the maximum can change to a different peak. In
     this case the estimation would be wrong. We try to detect the detection
     of a different peak by defining a maximum sample rate change. The sample
     rate offset is very likely to be very constant since usually crystal
     oscialltors are used. Thus, if a larger change of sample rate offset
     happens, we assume that the maximum peak has changed */
  const long long iNewDiff = veciSRTiCorrHist[iLenCorrectionHist - 2] - iCurRes;
  
  /* If change is larger than 2, it is most likely that a new peak was chosen
     by the maximum function. Also, if the sign has changed of the difference
     (and it is not zero), we also say that a new peak was selected */
  if ((llabs(iNewDiff) > 2) ||
      ((Sign(iOldNonZeroDiff) != Sign(iNewDiff)) && (iNewDiff != 0)))
    {
      /* Correct the complete history to the new reference peak. Reference
	 peak was already added, therefore do not use last element */
      for (i = 0; i < iLenCorrectionHist - 1; i++)
	veciSRTiCorrHist[i] -= iNewDiff;
    }
  
  /* Store old difference if it is not zero */
  if (iNewDiff != 0)
    iOldNonZeroDiff = iNewDiff;
  
  
  /* Check, if we are in acquisition phase */
  if (iResOffsetAcquCnt > 0)
    {
      /* Acquisition phase */
      iResOffsetAcquCnt--;
    }
  else
    {
      /* Apply the result from acquisition only once */
      if (bSamRaOffsAcqu == TRUE)
	{
	  /* End of acquisition phase */
	  bSamRaOffsAcqu = FALSE;
	  
	  /* Set sample rate offset to initial estimate. We consider the
	     initialization phase of channel estimation by "iSymDelay" */
	  /*rInitSamOffset = FXP GetSamOffHz(iCurRes - veciSRTiCorrHist[
	    iLenCorrectionHist - (iResOffAcqCntMax - iSymDelay)],
	    iResOffAcqCntMax - iSymDelay - 1); */
	  CFReal rInitSamOffset = FXP (GetSamOffHz(iCurRes - veciSRTiCorrHist[
									      iLenCorrectionHist - (iResOffAcqCntMax - iSymDelay)],
						   iResOffAcqCntMax - iSymDelay - 1)); 
	  
	  
#ifndef USE_SAMOFFS_TRACK_FRE_PIL
	  /* Apply initial sample rate offset estimation */
	  // (Parameter.rResampleOffset) -= rInitSamOffset;
	  FXP (Parameter.rResampleOffset) -= rInitSamOffset;
	  
#endif
	  
	  /* Reset estimation history (init with zeros) since the sample
	     rate offset was changed */
	  veciSRTiCorrHist.Init(iLenCorrectionHist, 0);
	  iIntegTiCorrections = 0;
	}
      else
	{
	  /* Tracking phase */
	  /* Get actual sample rate offset in Hertz */
	  /* const CReal rSamOffset = GetSamOffHz(iCurRes - veciSRTiCorrHist[0],
	     iLenCorrectionHist - 1); */
	  const CFReal rSamOffset = FXP (GetSamOffHz(iCurRes - veciSRTiCorrHist[0],
						     iLenCorrectionHist - 1));
	  
#ifndef USE_SAMOFFS_TRACK_FRE_PIL
	  /* Apply result from sample rate offset estimation */
	  //Parameter.rResampleOffset -= CONTR_SAMP_OFF_INT_FTI * rSamOffset;
	  FXP (Parameter.rResampleOffset) -= CONTR_SAMP_OFF_INT_FTI * rSamOffset;
#endif
	}
    }
  
  
  /* Delay spread length estimation --------------------------------------- */
  /* Estimate the noise energy using the minimum statistic. We assume that
     the noise variance is equal on all samples of the impulse response.
     Therefore we subtract the variance on each sample. The total estimated
     signal energy is the total energy minus the noise energy */
  /* Calculate total energy */
  const CFReal rTotEgy = Sum(vecrAvPoDeSpRot);
  
  /* Sort the values of the PDS to get the smallest values */
  CRealVector rSortAvPoDeSpRot(Sort(vecrAvPoDeSpRot));
  
  /* Average the result of smallest values and overestimate result */
  const long long rSigmaNoise_fxp =
    (long long)(Sum(rSortAvPoDeSpRot(1, NUM_SAM_IR_FOR_MIN_STAT - 1)) /
		NUM_SAM_IR_FOR_MIN_STAT * OVER_EST_FACT_MIN_STAT*(1<<FXP_TIME_SYNC_TRACK_SCALE));
  
  /* Calculate signal energy by subtracting the noise energy from total
     energy (energy cannot by negative -> bound at zero) */
  const long long rSigEnergyBound_fxp =
    (long long)((double)Max(rTotEgy - ((double)rSigmaNoise_fxp/(1<<FXP_TIME_SYNC_TRACK_SCALE)) * iNumIntpFreqPil,
			    (FXP)0)*(1<<FXP_TIME_SYNC_TRACK_SCALE));
  
  /* From left to the right -> search for end of PDS */
  rEstPDSEnd_fxp = (FXP) (iNumIntpFreqPil - 1);
  rCurEnergy_fxp = 0;
  bPDSResultFound = FALSE;
  for (i = 0; i < iNumIntpFreqPil; i++)
    {
      if (bPDSResultFound == FALSE)
	{
	  if (rCurEnergy_fxp > rSigEnergyBound_fxp)
	    {
	      /* Delay index */
	      rEstPDSEnd_fxp = (CReal) i;
	      
	      bPDSResultFound = TRUE;
	    }
	  
	  /* Accumulate signal energy, subtract noise on each sample */
	  rCurEnergy_fxp += (long long)(vecrAvPoDeSpRot[i]*(1<<FXP_TIME_SYNC_TRACK_SCALE)) - rSigmaNoise_fxp; //slu2 change
	}
    }
  
  /* From right to the left -> search for beginning of PDS */
  rEstPDSBegin_fxp = 0;
  rCurEnergy_fxp = 0;
  bPDSResultFound = FALSE;
  for (i = iNumIntpFreqPil - 1; i >= 0; i--)
    {
      if (bPDSResultFound == FALSE)
	{
	  if (rCurEnergy_fxp > rSigEnergyBound_fxp)
	    {
	      /* Delay index */
	      rEstPDSBegin_fxp = (CFReal) i;
	      
	      bPDSResultFound = TRUE;
	    }
	  
	  /* Accumulate signal energy, subtract noise on each sample */
	  rCurEnergy_fxp += (long long)(vecrAvPoDeSpRot[i]*(1<<FXP_TIME_SYNC_TRACK_SCALE)) - rSigmaNoise_fxp; //slu2 change
	}
    }
  
  /* If the signal energy is too low it can happen that the estimated
     beginning of the impulse response is before the end -> correct */
  if (rEstPDSBegin_fxp > rEstPDSEnd_fxp)
    {
      /* Set beginning and end to their maximum (minimum) value */
      //rEstPDSBegin = (CReal) 0.0;
      rEstPDSBegin_fxp = 0;
      rEstPDSEnd_fxp = (CFReal) (iNumIntpFreqPil - 1);
    }
  
  /* Correct estimates of begin and end of PDS by the rotation */
  const CReal rPDSLenCorrection = iNumIntpFreqPil - iStPoRot + 1; /* slu2: dont' have to change here */
  rEstPDSBegin_fxp -= FXP (rPDSLenCorrection);
  rEstPDSEnd_fxp -= FXP (rPDSLenCorrection);
  
  /* Set return parameters */
  rLenPDS_fxp = rEstPDSEnd_fxp - rEstPDSBegin_fxp;
  rOffsPDS_fxp= rEstPDSBegin_fxp;
}
/* 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;
		}
	}
}