[time-nuts] I've designed a GPSDO, but how "good" is it?

Tom Van Baak tvb at LeapSecond.com
Mon Aug 17 15:31:12 EDT 2015

Hi Attila,

I'm planning to collect raw phase data from his TCXO (in holdover). Not only will we get the ADEV of his LO but that data, plus the Adafruit GPS data, can then be fed into the GPSDO simulator program.

Nick can modify the simulator with his current algorithm and see how his GPSDO would perform with different styles of control loop. The GPS simulator can easily model his phase comparator (a CPU capture register with some known granularity) and his DAC (also with known granularity).

When done right, the very C code used in his AVR control loop can be the C code used in the simulator. Actual LO data, actual GPS data, actual code. The result is seeing how your GPSDO works on your PC in a few seconds instead of waiting a few days (and needing a precision frequency counter and atomic reference) to test the real thing. More info here:


In the end of course you want to test the real h/w, but being able to see how control loops work, and solving problems of lost lock, and maximizing the performance of the code -- can be done far more efficiently under simulation.


----- Original Message ----- 
From: "Attila Kinali" <attila at kinali.ch>
To: "Discussion of precise time and frequency measurement" <time-nuts at febo.com>
Sent: Monday, August 17, 2015 12:07 PM
Subject: Re: [time-nuts] I've designed a GPSDO, but how "good" is it?

On Mon, 17 Aug 2015 07:14:34 -0700
Nick Sayer via time-nuts <time-nuts at febo.com> wrote:

> > Without having had a look at your code (sorry, i currently don't have
> > the time for this), if you trully implemented just an FLL, then this
> > is where you should start from. The way to get a PLL is to let the counter
> > of the capture unit run freely. Don't reset it, just let it wrap around.
> I do that. It’s a 32 bit counter (the 16 bit counter has an overflow
> interrupt that increments the high 16 bytes in software). The counter
> free-runs. 32 bits at 10 MHz takes around 400 seconds to wrap.

So that works right. Good.

> > The PPS pulse will now be wandering in each period, so you have to track
> > where you would expect the PPS next (unless you set the counter such,
> > that its wrap around divides a second evenly). Doing this, you will
> > integrate over the frequency difference and thus get a phase comparator.
> I don’t quite get it.
> What I do is every time there’s a capture interrupt, I subtract the counter 
> value of the last capture from this one. That gives me how many clock cycles 
> there were between PPS rising edges. But there’s no way for me to know the 
> phase relationship between the two rising edges (the PPS and 10 MHz). I can 
> only assume that the capture takes place within one cycle. Fortunately, I 
> don’t have to be concerned with software latency, as the capture interrupt 
> occurs immediately after, well before anything else gets in the way.

By taking the difference of "current pulse time" minus "previous pulse time"
and using this as the input into your control loop, you are making an FLL.

Instead you should use "time the pps is expected to arrive" minus "when
the pulse actually arrived".

You have a nominal frequency of 10MHz and a 16bit counter. That means
a second is 152 overflows plus 38528 counts long. Assuming you start with
0, the expected arrival of the next pulse is at count 38528. When it comes
earlier, your TCXO frequency was too low, when it comes later your TCXO
frequency was too high. The third pulse is exected to arrive at
count = (38528*2) % 2^16 = 11520. Again, feed the difference between that
value and when the pulse actually arrived into your control loop. The forth
pulse is expected at, (38528*3) % 2^16 = 50048,... etc pp

By not taking the difference to the previous pulse, but to the expected
time of the pulse, any fractional error in the calculation/frequency
will accumulate until it reaches the point where it actually becomes
visible as an offset between expected pulse time and pulse time.
And hence, forms a PLL.

If the timer of the ATtiny allows that, you can set it to overflow
at 62500. This divides 10e6 evenly, which gives you a constant count
number when you expect the pulse, which you then can set into mid range,
ie. at 31250. (makes the software easier)

> When the error delta over 100 seconds is non-zero and less than 5, I 
> increment or decrement the DAC value, thus adjusting the trim by an expected 
> ~370 ppt. When the error is more than 5, I double the error and add/subtract 
> that to the DAC value. It’s not a PID, but it generally reaches steady-state 
> quickly enough. I don’t make any LOCK LED indications at all until the 1000 
> second sample window is full, and by then the 100 second deltas are under 5 
> (usually at or under 1).

You really should read the wikipedia article on the PID loop and implement
a simple PI loop (no need for the D part). That's not more effort than what
you already did, but gives you better stability.

Attila Kinali

I must not become metastable. 
Metastability is the mind-killer.
Metastability is the little-death that brings total obliteration.
I will face my metastability. 
I will permit it to pass over me and through me. 
And when it has gone past I will turn the inner eye to see its path. 
Where the metastability has gone there will be nothing. Only I will remain.

More information about the time-nuts mailing list