Hello,
Since I am going to be working on the hybrid FLL/PLL control loop algorithm for the STM32 GPSDO, I want to discuss a few aspects of GPSDO control loops and PID algorithms as applicable.
So first the PID reference is the Wikipedia article:
https://en.wikipedia.org/wiki/PID_controllerAnd let us clarify a couple of points related to GPSDO control loops:
1. There are two main types of GPSDO control loops: FLL and PLL.
2. In FLL loops, the "process variable" PV is the frequency of the OCXO in Hz, measured by a counter with the gate time controlled by the PPS from the GPS receiver. No PPS, no frequency measurement.
3. In PLL loops, the "process variable" PV is the phase difference (in ns) between the rising edge of the 10MHz from the OCXO, and again the rising edge of the PPS from the GPS receiver, measured by a "time interval counter" TIC circuit which can be digital or analog. And similarly, no PPS, no phase difference measurement.
4. In both cases, the presence of a PPS from the GPS receiver is essential. Not only that, but the "precision" of the PPS from the GPS receiver determines the precision of our measurements of the PV variables frequency or phase difference. This is in fact what GPSDOs are all about: we use the PPS from the GPS receiver as a "proxy" for the atomic clocks onboard the satellites, to measure our local oscillator frequency or phase, and "discipline" it.
5. Just a note about digital/analog measurement circuits: the STM32 GPSDO FLL uses a 100% digital frequency measurement circuit, Lars' DIY GPSDO uses an analog TIC that generates a voltage that is then converted to a digital value using an ADC.
6. Getting back to our PPS from the GPS receiver, how "accurate" is it ? The accuracy of a clock is not a single number, it is actually best described ("characterized") by a chart, the famous ADEV/MDEV charts, which essentially plot the statistical variance of the frequency of our clock over a period of time (tau). So we know that
the ideal frequency of the PPS from the GPS receiver is exactly 1Hz, and we can measure (using an even better clock) the minute variations in time between two consecutive rising edges of our PPS signal, and then if we collect enough measurements over e.g. a day or two, we can plot an ADEV/MDEV chart for our PPS receiver. This has been done over and over again by extremely knowledgeable people using
very expensive equipment for a number of GPS receivers, and - surprise, surprise - they have found that the ADEV/MDEV curves for the PPS from different GPS receivers are actually quite similar. I'll come back to that later. But for the moment, we can assume that the "precision" of the PPS signal from a < $10 u-blox NEO M8N
is better than 100ns over 1 second (10E-7) and improves by an order or magnitude per decade iow it is approximately 10E-8 for tau = 10s, 10E-9 for tau = 100s, etc. up to 10E-11 for tau=10k seconds.
7. I have previously posted a link to an excellent analysis of various GPS receivers and I again refer you to it :
https://hamsci.org/sites/default/files/publications/2020_TAPR_DCC/N8UR_GPS_Evaluation_August2020.pdf by John Ackermann N8UR
8. Note that in the STM32 GPSDO we use a little trick to further improve the accuracy of the PPS from the u-blox NEO-M8N. Check the function ubxconfig() and you'll find this comment:
// send UBX commands to set optimal configuration for GPSDO use
// we are going to change a single parameter from default by
// setting the navigation mode to "stationary"
9. Getting back to the Wikipedia article on PID control loops, we have now defined our two process variables PVs frequency and phase difference, and we have just seen how to measure them. What is the
setpoint SP or target value for these PVs ? For the frequency, it is the nominal frequency of our OCXO or 10MHz in our case, and for the phase difference it is exactly 0. In the STM32 GPSDO we already measure the
error term e(t) every second for both PVs: for the frequency, this is the "offset" which is now stored in a unified ring buffer, and for the phase difference this is the reading from the TIC Vphase, which we average over the last 10 second using the moving average library.
10. Again referring to our ideal PID controller, our control variable u(t) in the case of most low-cost GPSDOs is the control voltage that we can apply to the OCXO to vary its frequency. For Lars' DIY GPSDO and for the STM32 GPSDO a 16-bit PWM DAC is used to generate a control voltage Vctl between 0 and 4V. This is an extremely economical solution but it does the job.
11. A complicating factor for programming the PLL or FLL algorithms for a GPSDO is that we are dealing with a discrete correction process, in other words changes in the control variable are applied at discrete time intervals which can be fixed or variable. For example, the STM32 GPSDO with its very crude FLL algorithm uses a fixed interval of 429s to change Vctl (except during the initial calibration). In older GPSDO designs using a purely analog circuit the control variable is applied continuously.
12. Consequently the program of an FLL or PLL loop for a GPSDO has two decisions to make every second:
a) What is the size of the correction to be applied to the control variable in other words how to compute the new value for Vctl ?
b) Should the correction that was just computed be applied now, or should we wait and apply a different correction later ? How frequently do we change Vctl and do we use a fixed or variable time constant?
13. The programmer (in this case myself) has to decide whether to use a P, PI or PID loop, the optimal values for Kp, Ki and Kd, how frequently do we change Vctl and do we use a fixed or variable time constant (the delay between changes to the Vctl), and any processing (filtering, averaging, removal of outlying values, etc) of the measurements from the frequency counter and the TIC.
14. More precisely in my case, there is an extra complicating factor because I am trying to merge the FLL and PLL control loops into a "hybrid" FLL/PLL control loop. How to best combine the information from the two measurements frequency and phase difference ? Should I have the two loops acting concurrently, or should one loop take over and in what conditions ? Aaaaahhhhhhhh