Closed hcab14 closed 6 years ago
Yes, this is pretty much what I was planning to do.
What I wanted to understand first was how, on the client side, you would use the timestamp to figure out which sample exactly falls on a fixed time scale. Like every second or millisecond or something (at 12 kHz one sample is ~83 usec). It's a little tricky because at the point this header is generated the audio stream has already been buffered a little between the FPGA and Kiwi. So adding a timestamp here doesn't represent true real-time. Maybe this doesn't matter for most applications as long as the timestamp offset is constant. There will be some jitter considerations because this header is added by C code running on the Beagle.
I also need to add some options which allow the GPS correction of the ADC clock to be disabled per-connection. Some people want to do ionograms and not get the phase jump from the ADC clock being changed. But they still might want a timestamp. And the users on other connections still need the correction for frequency calibration.
Thanks a lot for your fast reply!
It's a little tricky because at the point this header is generated the audio stream has already been buffered a little between the FPGA and Kiwi. So adding a timestamp here doesn't represent true real-time. Maybe this doesn't matter for most applications as long as the timestamp offset is constant. There will be some jitter considerations because this header is added by C code running on the Beagle.
As far as I understand the 64 bit counter is coming from the FPGA. If the difference if the tick counter between the last GPS solution and the tick counter for the current audio buffer is used to obtain the GPS time of the current audio buffer
Of course there is a processing delay in the FPGA.
What I wanted to understand first was how, on the client side, you would use the timestamp to figure out which sample exactly falls on a fixed time scale. Like every second or millisecond or something (at 12 kHz one sample is ~83 usec).
I would leave this to the user. Anyway I can imagine that one probably wants to interpolate between samples to increase the time resolution, so having a precise start time for each buffer is in my opinion enough.
Hi @jks-prv,
yesterday I got a KiwiSDR and began working on the time stamps, see https://github.com/jks-prv/Beagle_SDR_GPS/pull/134
For testing I feed the 1PPS pulse of a ublox NEO-7M GPS mouse into the antenna input of the KiwiSDR (using a RC network with a 4.7kOhm resistor + some capacitor). This should allow to understand latency and time offsets.
Interesting. There is another guy here in New Zealand who was going to try the "feed pulses into the antenna" trick. So let me know how this works out.
Application of this technique for phase locking a receiver: http://www.qsl.net/zl1bpu/SOFT/click.htm
Hi @jks-prv,
I managed to do some test with GPS time stamps using a NEO-7M GPS where I fed the 1PPS pulse into the KiwiSDR using a 4.7kOhm resistor.
Then I tuned the KiwiSDR to 30 kHz and recorded IQ samples with GPS timestamps enabled.
The relevant code is here https://github.com/hcab14/Beagle_SDR_GPS and the modified version of the python recorder along with octave code to read the WAV file with 'kiwi' chunks is here https://github.com/hcab14/kiwiclient
This plot shows abs(IQ) w.r.t. mod(gpssec, 1)
The raising and falling edge of the 1PPS pulse show up as delta-function-like peaks
Zooming into the peaks I find this: (rising edge)
and this: (falling edge)
This jitter might of course be due to the GPS module, but does it remind you of something in the FPGA code?
Thanks a lot Christoph
A couple of questions/comments: Why are there two peaks in the first graph?
Do you mean 305.5 usec, not 3.055 usec? That's what 5000 cycles at 16.368 MHz is. And it would match the x-axis time shown on your second graph (6 peak intervals shown across 2 msec). 333 usec is 4 samples at 12 kHz (the audio rate) which is interesting.
You might not know but I assume the first peak in the rising edge graph is paired with the first peak of the falling edge graph. That is, the 1PPS has a constant width, but it is showing 21 slightly different rising edge phase points for some reason.
Okay, I think I know what might be wrong here. Hint: 21 * 4 (samples) = 84 which is the size of the FPGA audio buffer (kiwi.config constant NRX_SAMPS).
Okay, I think I know what might be wrong here. Hint: 21 * 4 (samples) = 84 which is the size of the FPGA audio buffer (kiwi.config constant NRX_SAMPS).
Can you explain?
In verilog/rx/receiver.v
data transfer through SPI is triggered by the rx_avail_A
wire and at the end of data transfer the ADC tick counter is read out and transferred. rx_avail_A
is in verilog/rx/rx.v
connected to rx_cic2_strobe_i
which signals that the CIC computation has finished.
Does the 333us jitter imply that the downconversion in the FPGA takes different discrete times?
You might not know but I assume the first peak in the rising edge graph is paired with the first peak of the falling edge graph. That is, the 1PPS has a constant width, but it is showing 21 slightly different rising edge phase points for some reason.
Here are the time differences between the peaks seen in IQ data. For this I have computed the weighted average around each peak of the GPS time of the samples. The 1PPS pulse is 0.1 seconds long:
And here are the GPS times modulo 1 w.r.t. number of the pulses
I think I understand better (please correct me if I am wrong)
Would the following make sense?
adc_ticks
from the GPS FPGA module to the receiver modulerx_avail_A
copy the ADC tick into a registerI haven't had enough coffee this morning to understand your graphs, but will try later on.
But your second post is absolutely correct. And the second point about latching the 48-bit adc_ticks
before inserting it as three 16-bit words into the audio buffer is what I was trying to do all day yesterday without success. Thanks for suggesting rx_avail_A
as the latch signal. That worked great. I was trying to generate a separate one from the state machine but it never quite worked.
I have pushed v1.147 that has the new adc_ticks
latching. Please try it and see if the jitter improves.
Now the jitter became more random:
Why do you do this
always @ (posedge cpu_clk)
if (rx_avail_A)
ticks_latched_A <= ticks_A;
instead of
always @ (posedge rx_avail_A)
ticks_latched_A <= ticks_A;
Finally I have to solder RXD,TXD lines to the BBG and check that the GPS module indeed has a good position solution (up to now I rely on the red LED which shows the 1PPS pulse).
Thanks a lot.
Did you mean to reverse those two pieces of Verilog wrt the text? Because I'm doing the first one now. Anyway, I don't think the second one is a good idea because you're essentially running the latch clock on a signal that is asynchronous to the adc_clk. Although it's going to be very close. Is the intent to latch one adc_clk earlier? I don't see how that is going to make a difference. ticks_A is incrementing every single adc_clk. Latching it one clock period earlier shouldn't effect the jitter at all.
I was asking because it is always @ (posedge cpu_clk)
and not always @ (posedge adc_clk)
. Anyway the jitter is more than one cpu clock. Must check the state of the GPS module.
Ugh. How did that happen? Lack of coffee no doubt. Fixing now. Update soon..
Okay, pushed v1.148. Please restart to update and give that a try.
Okay, pushed v1.148. Please restart to update and give that a try.
Thanks a lot!
I realized today that I overlooked the FIR filter in https://github.com/jks-prv/Beagle_SDR_GPS/blob/master/rx/rx_sound.cpp#L509:
ns_out=512
) one needs to take the right time stamp from the past and add the correct offset to it.Here is how the 1PPS pulse fed into the KiwiSDR looks now
As you see it looks much better now.
What remains to be understood / calibrated is the offset/processing delay of 28926.838 usec (~1928450 ADC clocks @66.666467 MHz).
Let me know if you have ideas for further testing / if I can make a pull request.
Okay, I see. So it's that weird pipeline delay of the FIR filter (it's one of those fast overlap-save FFT FIRs).
I'll think about the remaining delay problem. Yes, please send me a pull. Good stuff!
While waiting for a new version of the KiwiSDR software, I noticed that some KiwiSDRs run already the current master tag which includes the GPS timestamps in the IQ data stream.
One of them is http://hb9ryz.homeip.net:8073/ and the DCF77 signal strength plotted w.r.t. GPS seconds modulo 1 looks like this:
The map below is made using https://www.movable-type.co.uk/scripts/latlong.html
Here is the DCF77 signal recorded today at http://kiwisdr.ddnss.de:8073 The magenta line indicates the expected delay.
What can be seen is the pulse shape of DCF77 (see http://tycho.usno.navy.mil/ptti/2011papers/Paper24.pdf):
So it looks like the GPS time stamps are correct to at least 20 usec (6 km), possibly much better but for this one would have to use the PRN phase modulation:
In their paper I couldn't find the value of t0 (or equivalently the interval tau sub s). Looks like it must be less than 200 usec though. I understand the part about reducing the transmitter power to zero for 250 usec to get a faster fall-time. Really fantastic that you're getting the propagation delay numbers you expect. Thank you for all your work on this. I'm not sure I ever would have figured this out in such detail.
I think 20 usec is not too bad for an amateur GPS receiver written without any fancy optimizations. There is certainly no "survey mode" in effect here where the receiver position is known and can be fixed in the position/time solution calculations. And also no use of the second order corrections like the ionospheric delay contained in the GPS nav data. Andrew started to write code to consider this but it was never finished. Then there is stuff like antenna feed line delay correction etc. I'm not sure how important these factors are. I have an hp z3801a GPSDO here. I should set that up with a splitter to the same GPS antenna as the Kiwi and do some 1PPS comparisons (work needed to get the Kiwi to generate a 1PPS output of course).
In their paper I couldn't find the value of t0 (or equivalently the interval tau sub s). Looks like it must be less than 200 usec though. I understand the part about reducing the transmitter power to zero for 250 usec to get a faster fall-time. Really fantastic that you're getting the propagation delay numbers you expect. Thank you for all your work on this. I'm not sure I ever would have figured this out in such detail.
This is what I am used to do at work...
See here for more information (page 10) https://www.ptb.de/cms/fileadmin/internet/fachabteilungen/abteilung_4/4.4_zeit_und_frequenz/pdf/2011_PTBMitt_50a_DCF77_engl.pdf It seems that the delay by the feedline+antenna is corrected for.
I think 20 usec is not too bad for an amateur GPS receiver written without any fancy optimizations.
I believe that the true accuracy of the KiwiSDR time stamps is much better than 20 µs: (note that the people from DCF77 also say that their measurements in the near field of the antenna are accurate to ± 25 µs) These are the sources of errors I can think of:
There is certainly no "survey mode" in effect here where the receiver position is known and can be fixed in the position/time solution calculations. And also no use of the second order corrections like the ionospheric delay contained in the GPS nav data. Andrew started to write code to consider this but it was never finished.
I realized that the smoothing and outlier removal you apply to the clock correction could be transferred to the GPS position solution, e.g., using a Kalman filter, see https://www.dst.defence.gov.au/sites/default/files/publications/documents/DST-Group-TR-3260.pdf (there must be many more other references)
I have an hp z3801a GPSDO here. I should set that up with a splitter to the same GPS antenna as the Kiwi and do some 1PPS comparisons (work needed to get the Kiwi to generate a 1PPS output of course).
It would be great if you and/or anyone else could check the time alignment. As having a 1PPS output from the KiwiSDR can be nontrivial, in my opinion it would be easiest to feed the 1PPS pulse into the KiwiSDR. For comparison it would be also good to couple the 1PPS pulse into the antenna.
This is the position of DCF77 estimated from time differences using three KiwiSDRs
This is what I used to do at work...
Okay, that explains why you're making such great progress so quickly, lol.
As having a 1PPS output from the KiwiSDR can be nontrivial, in my opinion it would be easiest to feed the 1PPS pulse into the KiwiSDR. For comparison it would be also good to couple the 1PPS pulse into the antenna.
Ah, of course. I forgot that's what you had done.
Really interesting that the TDoA for DCF77 worked so well. I hope I can understand your exact method at some point.
Hi Christoph,
This is excellent work.
If you wish you can use my second 'Private' Kiwi for more experiments.
http://southwest.ddns.net:8077/
If it would be of further use for development purposes, it has a spare but currently unused antenna switch extension, so I could modify this to switch a 1PPS marker on when required.
I have a separate GPS with a 1PPS output that I could pipe in from my workshop, but maybe John could indicate if there is a suitable point on the KiWi that I could sniff an output from ?
Regards,
Martin - G8JNJ
Hi @G8JNJ,
If it would be of further use for development purposes, it has a spare but currently unused antenna switch extension, so I could modify this to switch a 1PPS marker on when required.
It would be great if you could connect the 1PPS signal to the antenna switch. What kind of GPS receiver would provide the 1PPS signal?
Best regards Christoph
Martin, are you asking if the Kiwi produces a 1PPS output? It doesn't currently. But the point is to supply 1PPS from an independent GPS into the antenna input so it can be compared against the Kiwi GPS-derived timestamp to judge its correctness / accuracy. Christoph used a 4.7kOhm resistor to couple the 1PPS to the input (see above).
I would do the same here, but I'm in the middle of a move and everything is packed up.
Hi Christoph & John,
John - thanks for the info that's as I suspected but I just wanted to ask first.
Christoph - It's a Trimble Thunderbolt.
It's not next to the KiWi as it's in my workshop about 20m away. But I can pipe the 1PPS signal to the KiWi and connect a switch if required. It will take me a couple of days to sort out the hardware.
I have use the Trimble previously for some other experiments with Peter G3PLX so I know that it can provide a suitable signal.
I mentioned this work to Peter and he was surprised by the accuracy of your results.
He commented that it's difficult to get figures so accurate for DCF77 using only the falling edge. This apparently is problematic as it doesn't make allowance for the time-constant of the antenna resonance. The radiated RF ourput of the antenna takes quite a long time to decay after the transmitter is turned off because the antenna Q factor is so high. The p-n code on DCF77 is a much better bet.
If it is desired to be able to locate pirates and jammers, it requires some method of time-correlating arbitrary modulation waveforms as voice is too periodic and multipath doesn't help.
Regards,
Martin - G8JNJ
Hi All,
Actually I just remembered that I have a U-Blox module with a PPS output that I may be able to use instead. This would be better as I could connect it much closer to the KiWi.
I'll see if I can find it sometime tomorrow and connect it in.
Do you want it to be connected whilst the antenna is connected or just as a separate clean PPS source (or both).
Regards,
Martin - G8JNJ
Is this thing suitable for what is being experimented with? https://www.ebay.com/itm/Trimble-Resolution-T-12-channel-GPS-Timing-Receiver-Module-3-3V-1pps-Ver-1-17-0/302531276883?hash=item467044f053:g:G6AAAOSwaeRZJGCY Ron - KA7U
Hi Christoph,
I have quickly added a 1PPS marker onto my Private KiWi
http://southwest.ddns.net:8077
You can switch between Antenna, 1PPS marker and Antenna & Marker by using the antenna switch extension.
If you wish to change the antenna in use. Then login to my public KiWi and change the antenna using the antenna switch extension. Use the Trask active whip for the LF bands MSF & DCF77.
http://southwest.ddns.net:8073/
The 1PPS pulse is being taken from a U-Blox M5 with built in antenna, so I've coupled the feed from my outdoor GPS antenna into it with a short antenna taped to the side of the module.
I'm not sure if the pulse sync is 100% correct but try it and let me know and try and I'll adjust it as required.
If you are taking recordings or don't want the setup on the Private KiWi to be disturbed just leave a note in the Callsign entry box to warn other users.
Regards,
Martin - G8JNJ
@ka7u
Is this thing suitable for what is being experimented with?
Definitely.
Hi @jks-prv
I am sure you are very busy with all kinds of user requests, but it would be really great to have GPS time stamps in the audio streams.
I might be wrong, but to me it looks like all information is already there can can be put into the header for audio streams with moderate effort.
in kiwi.h the gps timestamp would have to be added to the header
h
insnd_pkt_t
Of course such a change to the header would imply corresponding changes on all client sides.
clk.c: time and ADC ticks for the GPS position solution are already set in clk.c
clock_correction(double t_rx, u64_t ticks)
:In rx/rx_sound.cpp the ADC tick counter is available via
as well as the tick counter + GPS time from the last GPS solution via
clk.gps_secs
andclk.gps_secs
, so this would be the place to fill the gps timestamp into the header.Unfortunately I do not own a KiwiSDR and therefore cannot make tests myself.
Let me know what you think and how I can help.