[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Discuss-gnuradio] Phase Locked Loop Example Part 2
From: |
Rick Parrish |
Subject: |
[Discuss-gnuradio] Phase Locked Loop Example Part 2 |
Date: |
Sat, 08 Nov 2003 03:39:13 -0600 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 |
Ian;
Here's the implementation. Not much to it ...a simple loop inside
inputData method and some accessors for setting options. This particular
version has been hacked up a bit for accepting 4 level FSK symbol sets.
On some radios, the signal is inverted from what's expected so an invert
flag takes care of that. For a 4 level symbol set {0, 1, 2, 3} inverting
the signal means subtracting the original symbol from 3 so 0 becomes 3,
1 becomes 2, etc.
The PLL effect is actually accomplished in one line of code ... see
below where the accumulator is scaled by 0.95 (see "95%" in comments).
After extracting a sequence of one or symbols, the accumulator measures
the number of samples remaining to be carried over into the next pass.
On a perfect signal, the time remaining is zero which implies perfect
phase. In reality, we'll be a little bit early (positive) or a little
bit late (negative). Scaling this left-over time value has the effect of
fine tuning the periodic point in time where the PLL demarks the
boundary between successive symbols.
-rick
/* Copyright 2002 see the file "COPYING" for license. */
#include "PhaseLockedLoop.h"
PhaseLockedLoop::PhaseLockedLoop(unsigned long dwSamplesPerSecond,
unsigned long dwSymbolsPerSecond, SymbolConsumer *pConsumer) :
_dwSamplesPerSecond(dwSamplesPerSecond),
_pConsumer(pConsumer),
_bInvert(false),
_nLastCount(0L),
_chLastSymbol(0),
_iSymbolRate(dwSymbolsPerSecond)
{
_fDamp = _fPhase = _fAccumulate = 0.0;
setSpeed(dwSymbolsPerSecond);
}
// Handle phase correction and delta value to discrete bit decomposition.
// As clock drifts around, calculate drift and add/subtract a small
// adjustment to the accumulator.
bool PhaseLockedLoop::inputData(char chSymbol, const long nDelta, const
unsigned long dwSamplesPerSecond)
{
if (!_pConsumer) return false;
// Compute new dampened/averaged phase error - using 5% correction for
now.
const double kPhaseDamper = 0.05;
double fDelta = 0.;
if (chSymbol == _chLastSymbol)
{
_nLastCount += nDelta;
return false;
}
char chMappedSymbol = _bInvert ? 3 - _chLastSymbol : _chLastSymbol;
fDelta = _nLastCount;
// Compute delta time as some sub-second decimal value.
fDelta /= dwSamplesPerSecond;
// Add delta to our delta time accumlator.
_fAccumulate += fDelta;
// Decompose the delta time value into a sequence of
// zero or more symbols all having the same value.
while (_fAccumulate >= _fBitHalfTime)
{
_pConsumer->consume(chMappedSymbol); // symbol consumer called here.
_fAccumulate -= _fBitTime;
}
// _fAccumulate is in range of -_fBitHalfTime to +_fBitHalfTime.
// A value of zero is perfect mid-phase sampling.
// A positive value means we are sampling early in the clock phase.
// A negative value means we are sampling late in the clock phase.
// Ideally the accumulator value IS our phase but we can't trust
// this 100% due to noise so we dampen and average the phase error
// values to tolerate an occassional noise glitch while improving
// phase tracking over time.
// Apply error to clock accumulator.
// Comment out this next line to turn PLL phase correction OFF.
_fAccumulate *= (1.0 - kPhaseDamper); // 95%
_chLastSymbol = chSymbol;
_nLastCount = nDelta;
return false;
}
void PhaseLockedLoop::setSpeed(const unsigned long dwSymbolsPerSecond)
{
_iSymbolRate = dwSymbolsPerSecond;
// measured in seconds
_fBitTime = 1.0 / (double)dwSymbolsPerSecond;
_fBitHalfTime = 0.5 / (double)dwSymbolsPerSecond;
if (_pConsumer) _pConsumer->setOption("symbolrate", _iSymbolRate);
}
void PhaseLockedLoop::setConsumer(SymbolConsumer *pConsumer)
{
_pConsumer = pConsumer;
if (_pConsumer) _pConsumer->setOption("symbolrate", _iSymbolRate);
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Discuss-gnuradio] Phase Locked Loop Example Part 2,
Rick Parrish <=