Skip to content

Commit 8bfc5b0

Browse files
committed
gps/README.md Improvements and corrections.
1 parent 40d4a36 commit 8bfc5b0

File tree

2 files changed

+49
-27
lines changed

2 files changed

+49
-27
lines changed

gps/README.md

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -739,29 +739,9 @@ The claimed absolute accuracy of the leading edge of the PPS signal is +-10ns.
739739
In practice this is dwarfed by errors including latency in the MicroPython VM.
740740
Nevertheless the `get_ms` method can be expected to provide 1 digit (+-1ms)
741741
accuracy and the `get_t_split` method should provide accuracy on the order of
742-
+-70μs (standard deviation). This is based on a Pyboard running at 168MHz.
743-
744-
Without an atomic clock synchronised to a Tier 1 NTP server absolute accuracy
745-
is hard to prove. However if the manufacturer's claim of the accuracy of the
746-
PPS signal is accepted, the errors contributed by MicroPython can be estimated.
747-
748-
The driver interpolates between PPS pulses using `utime.ticks_us()` to provide
749-
μs precision. The leading edge of PPS triggers an interrupt which records the
750-
arrival time of PPS in the `acquired` bound variable. The ISR also records, to
751-
1 second precision, an accurate datetime derived from the previous RMC message.
752-
The time can therefore be estimated by taking the datetime and adding the
753-
elapsed time since the time stored in the `acquired` bound variable.
754-
755-
Sources of error are:
756-
* Variations in interrupt latency.
757-
* Inaccuracy in the `ticks_us` timer.
758-
* Latency in the function used to retrieve the time.
759-
* Mean value of the interrupt latency.
760-
761-
The test program `as_GPS_time.py` has a test `usecs` which aims to assess the
762-
first two. It repeatedly uses `ticks_us` to measure the time between PPS pulses
763-
over a minute then calculates some simple statistics on the result. On targets
764-
other than a 168MHz Pyboard this offers a way of estimating overheads.
742+
-5μs +65μs (standard deviation). This is based on a Pyboard running at 168MHz.
743+
The reasoning behind this is discussed in
744+
[section 2.5](./README.md#7-notes-on-timing).
765745

766746
## 4.6 Test/demo program as_GPS_time.py
767747

@@ -850,8 +830,50 @@ seconds) as the fundamental time reference. This is updated by the RMC message.
850830
The `utc`, `date` and `localtime` properties convert this to usable values with
851831
the latter two using the `local_offset` value to ensure correct results.
852832

853-
A discussion of how the precision timing methods interpolate between epoch
854-
times may be found here [section 4.5](./README.md##45-absolute-accuracy).
833+
## 7.1 Absolute accuracy
834+
835+
Without an atomic clock synchronised to a Tier 1 NTP server, absolute accuracy
836+
(Einstein notwithstanding :-)) is hard to prove. However if the manufacturer's
837+
claim of the accuracy of the PPS signal is accepted, the errors contributed by
838+
MicroPython can be estimated.
839+
840+
The driver interpolates between PPS pulses using `utime.ticks_us()` to provide
841+
μs precision. The leading edge of PPS triggers an interrupt which records the
842+
arrival time of PPS in the `acquired` bound variable. The ISR also records, to
843+
1 second precision, an accurate datetime derived from the previous RMC message.
844+
The time can therefore be estimated by taking the datetime and adding the
845+
elapsed time since the time stored in the `acquired` bound variable. This is
846+
subject to the following errors:
847+
848+
Sources of fixed lag:
849+
* Latency in the function used to retrieve the time.
850+
* Mean value of the interrupt latency.
851+
852+
Sources of variable error:
853+
* Variations in interrupt latency (small on Pyboard).
854+
* Inaccuracy in the `ticks_us` timer (significant over 1 second).
855+
856+
With correct usage when the PPS interrupt occurs the UART will not be receiving
857+
data (this can affect ISR latency). Consequently, on the Pyboard, variations in
858+
interrupt latency are small. Using an osciloscope a normal latency of 15μs was
859+
measured with the `time` test in `as_GPS_time.py` running. The maximum observed
860+
was 17μs.
861+
862+
The test program `as_GPS_time.py` has a test `usecs` which aims to assess the
863+
sources of variable error. Over a period it repeatedly uses `ticks_us` to
864+
measure the time between PPS pulses. Given that the actual time is effectively
865+
constant the measurement is of error relative to the expected value of 1s. At
866+
the end of the measurement period it calculates some simple statistics on the
867+
results. On targets other than a 168MHz Pyboard this may be run to estimate
868+
overheads.
869+
870+
Assuming the timing function has a similar latency to the ISR there is likely
871+
to be a 30μs lag coupled with ~+-35μs (SD) jitter largely caused by inaccuracy
872+
of `ticks_us` over a 1 second period. Note that I have halved the jitter time
873+
on the basis that the timing method is called asynchronously to PPS: the
874+
interval will centre on 0.5s. The assumption is that inaccuracy in the
875+
`ticks_us` timer measured in μs is proportional to the duration over which it
876+
is measured.
855877

856878
[MicroPython]:https://micropython.org/
857879
[frozen module]:https://learn.adafruit.com/micropython-basics-loading-modules/frozen-modules

gps/as_GPS_time.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ async def do_usec(terminate):
139139
tick.clear()
140140
err = 1000000 - usecs
141141
count += 1
142-
print('Error {:4d}μs {}'.format(err, '(skipped)' if count < 3 else ''))
142+
print('Timing discrepancy is {:4d}μs {}'.format(err, '(skipped)' if count < 3 else ''))
143143
if count < 3: # Discard 1st two samples from statistics
144144
continue # as these can be unrepresentative
145145
max_us = max(max_us, err)
@@ -148,7 +148,7 @@ async def do_usec(terminate):
148148
nsamples += 1
149149
# SD: apply Bessel's correction for infinite population
150150
sd = int(math.sqrt(sd/(nsamples - 1)))
151-
print('Error: {:5d}μs max {:5d}μs min. Standard deviation {:4d}μs'.format(max_us, min_us, sd))
151+
print('Timing discrepancy is: {:5d}μs max {:5d}μs min. Standard deviation {:4d}μs'.format(max_us, min_us, sd))
152152

153153
def usec(minutes=1):
154154
terminate = asyn.Event()

0 commit comments

Comments
 (0)