📄 timesync.cpp
字号:
/******************************************************************************\
* Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik
* Copyright (c) 2001
*
* Author(s):
* Volker Fischer
*
* Description:
* Time synchronization
* This module can have different amounts of input data. If two
* possible FFT-window positions are found, the next time no new block is
* requested.
*
* Robustness-mode detection
*
******************************************************************************
*
* 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 of the License, or (at your option) any later
* version.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
\******************************************************************************/
#include "TimeSync.h"
/* Implementation *************************************************************/
void CTimeSync::ProcessDataInternal(CParameter& ReceiverParam)
{
int i, j, k;
int iMaxIndex;
int iNewStIndCount;
int iIntDiffToCenter;
int iCurPos;
int iDetectedRModeInd;
int iDecInpuSize;
CReal rMaxValue;
CReal rMaxValRMCorr;
CReal rSecHighPeak;
CReal rFreqOffsetEst;
CComplexVector cvecInpTmp;
CRealVector rResMode(NUM_ROBUSTNESS_MODES);
/* Max number of detected peaks ("5" for safety reasons. Could be "2") */
CVector<int> iNewStartIndexField(5);
/* Init start index (in case no timing could be detected or init phase) */
int iStartIndex = iSymbolBlockSize;
/* Write new block of data at the end of shift register */
HistoryBuf.AddEnd(*pvecInputData, iInputBlockSize);
/* In case the time domain frequency offset estimation method is activated,
the hilbert filtering of input signal must always be applied */
#ifndef USE_FRQOFFS_TRACK_GUARDCORR
if ((bTimingAcqu == TRUE) || (bRobModAcqu == TRUE))
#endif
{
/* ---------------------------------------------------------------------
Data must be band-pass-filtered before applying the algorithms,
because we do not know which mode is active when we synchronize
the timing and we must assume the worst-case, therefore use only
from DC to 4.5 kHz. If the macro "USE_10_KHZ_HILBFILT" is defined,
a bandwith of approx. 10 kHz is used. In this case, we have better
performance with the most probable 10 kHz mode but may have worse
performance with the 4.5 or 5 kHz modes (for the acquisition) */
/* The FIR filter intermediate buffer must be adjusted to the new
input block size since the size can be vary with time */
cvecInpTmp.Init(iInputBlockSize);
/* Copy CVector data in CMatlibVector */
for (i = 0; i < iInputBlockSize; i++)
cvecInpTmp[i] = (*pvecInputData)[i];
/* Complex Hilbert filter. We use the copy constructor for storing
the result since the sizes of the output vector varies with time.
We decimate the signal with this function, too, because we only
analyze a spectrum bandwith of approx. 5 [10] kHz */
CComplexVector cvecOutTmp(
FirFiltDec(cvecB, cvecInpTmp, cvecZ, GRDCRR_DEC_FACT));
/* Get size of new output vector */
iDecInpuSize = Size(cvecOutTmp);
/* Copy data from Matlib vector in regular vector for storing in
shift register
TODO: Make vector types compatible (or maybe only use matlib vectors
everywhere) */
cvecOutTmpInterm.Init(iDecInpuSize);
for (i = 0; i < iDecInpuSize; i++)
cvecOutTmpInterm[i] = cvecOutTmp[i];
/* Write new block of data at the end of shift register */
HistoryBufCorr.AddEnd(cvecOutTmpInterm, iDecInpuSize);
#ifdef USE_FRQOFFS_TRACK_GUARDCORR
/* ---------------------------------------------------------------------
Frequency offset tracking estimation method based on guard-interval
correlation.
Problem: The tracking frequency range is "GRDCRR_DEC_FACT"-times
smaller than the one in the frequency domain tracking algorithm.
Therefore, the acquisition unit must work more precisely
(see FreqSyncAcq.h) */
/* Guard-interval correlation at ML estimated timing position */
/* Calculate start points for correlation. Consider delay from
Hilbert-filter */
const int iHalHilFilDelDec = NUM_TAPS_HILB_FILT / 2 / GRDCRR_DEC_FACT;
const int iCorrPosFirst = iDecSymBS + iHalHilFilDelDec;
const int iCorrPosSec =
iDecSymBS + iHalHilFilDelDec + iLenUsefPart[iSelectedMode];
/* Actual correlation over entire guard-interval */
CComplex cGuardCorrFreqTrack = 0.0;
for (i = 0; i < iLenGuardInt[iSelectedMode]; i++)
{
/* Use start point from ML timing estimation. The input stream is
automatically adjusted to have this point at "iDecSymBS" */
cGuardCorrFreqTrack += HistoryBufCorr[i + iCorrPosFirst] *
Conj(HistoryBufCorr[i + iCorrPosSec]);
}
/* Average vector, real and imaginary part separately */
IIR1(cFreqOffAv, cGuardCorrFreqTrack, rLamFreqOff);
/* Calculate argument */
const CReal rFreqOffsetEst = Angle(cFreqOffAv);
/* Correct measurement average for actually applied frequency
correction */
cFreqOffAv *= CComplex(Cos(-rFreqOffsetEst), Sin(-rFreqOffsetEst));
/* Integrate the result for controling the frequency offset, normalize
estimate */
ReceiverParam.rFreqOffsetTrack -= rFreqOffsetEst * rNormConstFOE;
#endif
if ((bTimingAcqu == TRUE) || (bRobModAcqu == TRUE))
{
/* Guard-interval correlation ----------------------------------- */
/* Set position pointer back for this block */
iTimeSyncPos -= iDecInpuSize;
/* Init start-index count */
iNewStIndCount = 0;
/* We use the block in the middle of the buffer for observation */
for (i = iDecSymBS + iDecSymBS - iDecInpuSize;
i < iDecSymBS + iDecSymBS; i++)
{
/* Only every "iStepSizeGuardCorr"'th value is calculated for
efficiency reasons */
if (i == iTimeSyncPos)
{
/* Do the following guard interval correlation for all
possible robustness modes (this is needed for robustness
mode detection) */
for (j = 0; j < NUM_ROBUSTNESS_MODES; j++)
{
/* Guard-interval correlation ----------------------- */
/* Speed optimized calculation of the guard-interval
correlation. We devide the total block, which has to
be computed, in parts of length "iStepSizeGuardCorr".
The results of these blocks are stored in a vector.
Now, only one new part has to be calculated and one
old one has to be subtracted from the global result.
Special care has to be taken since "iGuardSize" must
not be a multiple of "iStepSizeGuardCorr". Therefore
the "if"-condition */
/* First subtract correlation values shifted out */
cGuardCorr[j] -=
veccIntermCorrRes[j][iPosInIntermCResBuf[j]];
rGuardPow[j] -=
vecrIntermPowRes[j][iPosInIntermCResBuf[j]];
/* Calculate new block and add in memory */
for (k = iLengthOverlap[j]; k < iLenGuardInt[j]; k++)
{
/* Actual correlation */
iCurPos = iTimeSyncPos + k;
cGuardCorrBlock[j] += HistoryBufCorr[iCurPos] *
Conj(HistoryBufCorr[iCurPos + iLenUsefPart[j]]);
/* Energy calculation for ML solution */
rGuardPowBlock[j] +=
SqMag(HistoryBufCorr[iCurPos]) +
SqMag(HistoryBufCorr[iCurPos + iLenUsefPart[j]]);
/* If one complete block is ready -> store it. We
need to add "1" to the k, because otherwise
"iLengthOverlap" would satisfy the
"if"-condition */
if (((k + 1) % iStepSizeGuardCorr) == 0)
{
veccIntermCorrRes[j][iPosInIntermCResBuf[j]] =
cGuardCorrBlock[j];
vecrIntermPowRes[j][iPosInIntermCResBuf[j]] =
rGuardPowBlock[j];
/* Add the new block to the global result */
cGuardCorr[j] += cGuardCorrBlock[j];
rGuardPow[j] += rGuardPowBlock[j];
/* Reset block result */
cGuardCorrBlock[j] = (CReal) 0.0;
rGuardPowBlock[j] = (CReal) 0.0;
/* Increase position pointer and test if wrap */
iPosInIntermCResBuf[j]++;
if (iPosInIntermCResBuf[j] == iLengthIntermCRes[j])
iPosInIntermCResBuf[j] = 0;
}
}
/* Save correlation results in shift register */
for (k = 0; k < iRMCorrBufSize - 1; k++)
vecrRMCorrBuffer[j][k] = vecrRMCorrBuffer[j][k + 1];
/* ML solution */
vecrRMCorrBuffer[j][iRMCorrBufSize - 1] =
abs(cGuardCorr[j] + cGuardCorrBlock[j]) -
(rGuardPow[j] + rGuardPowBlock[j]) / 2;
}
/* Energy of guard intervall calculation and detection of
peak is only needed if timing aquisition is true */
if (bTimingAcqu == TRUE)
{
/* Start timing detection not until initialization phase
is finished */
if (iTiSyncInitCnt > 1)
{
/* Decrease counter */
iTiSyncInitCnt--;
}
else
{
/* Average the correlation results */
IIR1(vecCorrAvBuf[iCorrAvInd],
vecrRMCorrBuffer[iSelectedMode][iRMCorrBufSize - 1],
1 - rLambdaCoAv);
/* Energy of guard-interval correlation calculation
(this is simply a moving average operation) */
vecrGuardEnMovAv.Add(vecCorrAvBuf[iCorrAvInd]);
/* Taking care of correlation average buffer ---- */
/* We use a "cyclic buffer" structure. This index
defines the position in the buffer */
iCorrAvInd++;
if (iCorrAvInd == iMaxDetBufSize)
{
/* Adaptation of the lambda parameter for
guard-interval correlation averaging IIR
filter. With this adaptation we achieve
better averaging results. A lower bound is
defined for this parameter */
if (rLambdaCoAv <= 0.1)
rLambdaCoAv = 0.1;
else
rLambdaCoAv /= 2;
iCorrAvInd = 0;
}
/* Detection buffer ----------------------------- */
/* Update buffer for storing the moving average
results */
pMaxDetBuffer.AddEnd(vecrGuardEnMovAv.GetAverage());
/* Search for maximum */
iMaxIndex = 0;
rMaxValue = (CReal) -_MAXREAL; /* Init value */
for (k = 0; k < iMaxDetBufSize; k++)
{
if (pMaxDetBuffer[k] > rMaxValue)
{
rMaxValue = pMaxDetBuffer[k];
iMaxIndex = k;
}
}
/* If maximum is in the middle of the interval, mark
position as the beginning of the FFT window */
if (iMaxIndex == iCenterOfMaxDetBuf)
{
/* The optimal start position for the FFT-window
is the middle of the "MaxDetBuffer" */
iNewStartIndexField[iNewStIndCount] =
iTimeSyncPos * GRDCRR_DEC_FACT -
iSymbolBlockSize / 2 -
/* Compensate for Hilbert-filter delay. The
delay is introduced in the downsampled
domain, therefore devide it by
"GRDCRR_DEC_FACT" */
NUM_TAPS_HILB_FILT / 2 / GRDCRR_DEC_FACT;
iNewStIndCount++;
}
}
}
/* Set position pointer to next step */
iTimeSyncPos += iStepSizeGuardCorr;
}
}
/* Robustness mode detection ------------------------------------ */
if (bRobModAcqu == TRUE)
{
/* Start robustness mode detection not until the buffer is
filled */
if (iRobModInitCnt > 1)
{
/* Decrease counter */
iRobModInitCnt--;
}
else
{
/* Correlation of guard-interval correlation with prepared
cos-vector. Store highest peak */
rMaxValRMCorr = (CReal) 0.0;
for (j = 0; j < NUM_ROBUSTNESS_MODES; j++)
{
/* Correlation with symbol rate frequency (Correlations
must be normalized to be comparable!
("/ iGuardSizeX")) */
rResMode[j] =
Abs(Sum(vecrRMCorrBuffer[j] * vecrCos[j])) /
iLenGuardInt[j];
/* Search for maximum */
if (rResMode[j] > rMaxValRMCorr)
{
rMaxValRMCorr = rResMode[j];
iDetectedRModeInd = j;
}
}
/* Get second highest peak */
rSecHighPeak = (CReal) 0.0;
for (j = 0; j < NUM_ROBUSTNESS_MODES; j++)
{
if ((rResMode[j] > rSecHighPeak) &&
(iDetectedRModeInd != j))
{
rSecHighPeak = rResMode[j];
}
}
/* Find out if we have a reliable measure
(distance to next peak) */
if ((rMaxValRMCorr / rSecHighPeak) > THRESHOLD_RELI_MEASURE)
{
/* Reset aquisition flag for robustness mode detection */
bRobModAcqu = FALSE;
/* Set wave mode */
if (ReceiverParam.
SetWaveMode(GetRModeFromInd(iDetectedRModeInd)) == TRUE)
{
/* Reset output cyclic-buffer because wave mode has
changed and the data written in the buffer is not
valid anymore */
SetBufReset1();
}
}
}
}
}
}
if (bTimingAcqu == TRUE)
{
/* Use all measured FFT-window start points for determining the "real"
one */
for (i = 0; i < iNewStIndCount; i++)
{
/* Check if new measurement is in range of predefined bound. This
bound shall eliminate outliers for the calculation of the
filtered result */
if (((iNewStartIndexField[i] < (iCenterOfBuf + TIMING_BOUND_ABS)) &&
(iNewStartIndexField[i] > (iCenterOfBuf - TIMING_BOUND_ABS))))
{
/* New measurement is in range -> use it for filtering */
/* Low-pass filter detected start of frame */
IIR1(rStartIndex, (CReal) iNewStartIndexField[i],
LAMBDA_LOW_PASS_START);
/* Reset counters for non-linear correction algorithm */
iCorrCounter = 0;
iAveCorr = 0;
/* GUI message that timing is ok */
PostWinMessage(MS_TIME_SYNC, 0);
ReceiverParam.ReceptLog.SetSync(TRUE);
/* Acquisition was successful, reset init flag (just in case it
was not reset by the non-linear correction unit */
bInitTimingAcqu = FALSE;
}
else
{
/* Non-linear correction of the filter-output to ged rid of
large differences between current measurement and
filter-output */
iCorrCounter++;
/* Average the NUM_SYM_BEFORE_RESET measurements for reset
rStartIndex */
iAveCorr += iNewStartIndexField[i];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -