/******************************************************************************\ * OFDM cells demapping * \******************************************************************************/ void COFDMCellDemapping::ProcessDataInternal(CParameter& ReceiverParam) { /* Set absolute symbol position */ const int iSymbolCounterAbs = iCurrentFrameID * iNumSymPerFrame + iSymbolCounter; /* Set output block-sizes for this symbol */ iOutputBlockSize = ReceiverParam.veciNumMSCSym[iSymbolCounterAbs]; iOutputBlockSize2 = ReceiverParam.veciNumFACSym[iSymbolCounterAbs]; iOutputBlockSize3 = ReceiverParam.veciNumSDCSym[iSymbolCounterAbs]; /* Demap data from the cells */ int iMSCCounter = 0; int iFACCounter = 0; int iSDCCounter = 0; for (int iCar = 0; iCar < iNumCarrier; iCar++) { /* MSC */ if (_IsMSC(ReceiverParam.matiMapTab[iSymbolCounterAbs][iCar])) { /* Ignore dummy cells */ if (iMSCCounter < ReceiverParam.veciNumMSCSym[iSymbolCounterAbs]) { (*pvecOutputData)[iMSCCounter] = (*pvecInputData)[iCar]; iMSCCounter++; /* Local counter */ iMSCCellCounter++; /* Super-frame counter */ } } /* FAC */ if (_IsFAC(ReceiverParam.matiMapTab[iSymbolCounterAbs][iCar])) { (*pvecOutputData2)[iFACCounter] = (*pvecInputData)[iCar]; iFACCounter++; /* Local counter */ iFACCellCounter++; /* Super-frame counter */ } /* SDC */ if (_IsSDC(ReceiverParam.matiMapTab[iSymbolCounterAbs][iCar])) { (*pvecOutputData3)[iSDCCounter] = (*pvecInputData)[iCar]; iSDCCounter++; /* Local counter */ iSDCCellCounter++; /* Super-frame counter */ } } /* Get symbol-counter for next symbol and adjust frame-ID. Use the extended data, shipped with the input vector */ int iNewSymbolCounter = (*pvecInputData).GetExData().iSymbolID + 1; /* Check range (iSymbolCounter must be in {0, ... , iNumSymPerFrame - 1} */ while (iNewSymbolCounter >= iNumSymPerFrame) iNewSymbolCounter -= iNumSymPerFrame; while (iNewSymbolCounter < 0) iNewSymbolCounter += iNumSymPerFrame; /* Increment internal symbol counter and take care of wrap around */ iSymbolCounter++; if (iSymbolCounter == iNumSymPerFrame) iSymbolCounter = 0; /* Check if symbol counter has changed (e.g. due to frame synchronization unit). Reset all buffers in that case to avoid buffer overflow */ if (iSymbolCounter != iNewSymbolCounter) { /* Init symbol counter with new value and reset all output buffers */ iSymbolCounter = iNewSymbolCounter; SetBufReset1(); SetBufReset2(); SetBufReset3(); iMSCCellCounter = 0; iFACCellCounter = 0; iSDCCellCounter = 0; } /* If frame bound is reached, update frame ID from FAC stream */ if (iSymbolCounter == 0) { /* Check, if number of FAC cells is correct. If not, reset output cyclic-buffer. An incorrect number of FAC cells can be if the "iSymbolCounterAbs" was changed, e.g. by the synchronization units */ if (iFACCellCounter != NUM_FAC_CELLS) SetBufReset2(); /* FAC: buffer number 2 */ /* Reset FAC cell counter */ iFACCellCounter = 0; /* Frame ID of this FAC block stands for the "current" block. We need the ID of the next block, therefore we have to add "1" */ int iNewFrameID = ReceiverParam.iFrameIDReceiv + 1; if (iNewFrameID == NUM_FRAMES_IN_SUPERFRAME) iNewFrameID = 0; /* Increment internal frame ID and take care of wrap around */ iCurrentFrameID++; if (iCurrentFrameID == NUM_FRAMES_IN_SUPERFRAME) iCurrentFrameID = 0; /* Check if frame ID has changed, if yes, reset output buffers to avoid buffer overflows */ if (iCurrentFrameID != iNewFrameID) { iCurrentFrameID = iNewFrameID; /* Only SDC and MSC depend on frame ID */ SetBufReset1(); /* MSC: buffer number 1 */ SetBufReset3(); /* SDC: buffer number 3 */ iMSCCellCounter = 0; iSDCCellCounter = 0; } if (iCurrentFrameID == 0) { /* Super-frame bound reached, test cell-counters (same as with the FAC cells, see above) */ if (iMSCCellCounter != iNumUsefMSCCellsPerFrame * NUM_FRAMES_IN_SUPERFRAME) { SetBufReset1(); /* MSC: buffer number 1 */ } if (iSDCCellCounter != iNumSDCCellsPerSFrame) SetBufReset3(); /* SDC: buffer number 3 */ /* Reset counters */ iMSCCellCounter = 0; iSDCCellCounter = 0; } } }
/******************************************************************************\ * OFDM cells mapping * \******************************************************************************/ void COFDMCellMapping::ProcessDataInternal(CParameter& TransmParam) { /* Mapping of the data and pilot cells on the OFDM symbol --------------- */ /* Set absolute symbol position */ int iSymbolCounterAbs = TransmParam.iFrameIDTransm * iNumSymPerFrame + iSymbolCounter; /* Init temporary counter */ int iDummyCellCounter = 0; int iMSCCounter = 0; int iFACCounter = 0; int iSDCCounter = 0; for (int iCar = 0; iCar < iNumCarrier; iCar++) { /* MSC */ if (_IsMSC(TransmParam.matiMapTab[iSymbolCounterAbs][iCar])) { if (iMSCCounter >= TransmParam.veciNumMSCSym[iSymbolCounterAbs]) { /* Insert dummy cells */ (*pvecOutputData)[iCar] = pcDummyCells[iDummyCellCounter]; iDummyCellCounter++; } else (*pvecOutputData)[iCar] = (*pvecInputData)[iMSCCounter]; iMSCCounter++; } /* FAC */ if (_IsFAC(TransmParam.matiMapTab[iSymbolCounterAbs][iCar])) { (*pvecOutputData)[iCar] = (*pvecInputData2)[iFACCounter]; iFACCounter++; } /* SDC */ if (_IsSDC(TransmParam.matiMapTab[iSymbolCounterAbs][iCar])) { (*pvecOutputData)[iCar] = (*pvecInputData3)[iSDCCounter]; iSDCCounter++; } /* Pilots */ if (_IsPilot(TransmParam.matiMapTab[iSymbolCounterAbs][iCar])) (*pvecOutputData)[iCar] = TransmParam.matcPilotCells[iSymbolCounterAbs][iCar]; /* DC carrier */ if (_IsDC(TransmParam.matiMapTab[iSymbolCounterAbs][iCar])) (*pvecOutputData)[iCar] = _COMPLEX((_REAL) 0.0, (_REAL) 0.0); } /* Increase symbol-counter and wrap if needed */ iSymbolCounter++; if (iSymbolCounter == iNumSymPerFrame) { iSymbolCounter = 0; /* Increase frame-counter (ID) (Used also in FAC.cpp) */ TransmParam.iFrameIDTransm++; if (TransmParam.iFrameIDTransm == NUM_FRAMES_IN_SUPERFRAME) TransmParam.iFrameIDTransm = 0; } /* Set absolute symbol position (for updated relative positions) */ iSymbolCounterAbs = TransmParam.iFrameIDTransm * iNumSymPerFrame + iSymbolCounter; /* Set input block-sizes for next symbol */ iInputBlockSize = TransmParam.veciNumMSCSym[iSymbolCounterAbs]; iInputBlockSize2 = TransmParam.veciNumFACSym[iSymbolCounterAbs]; iInputBlockSize3 = TransmParam.veciNumSDCSym[iSymbolCounterAbs]; }
/* 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; } } }