fix(pps): align firmware TOW with current RTL
@@ -76,9 +76,9 @@ python3 -m unittest pps_end_to_end_validation/test_pps_end_to_end.py
|
||||
|
||||
```text
|
||||
scenario bits correction reference error DUT - trusted PPS
|
||||
current-rtl/180ms 9 180 ms -0.000032 ms +0.000032 ms
|
||||
current-rtl/160ms 9 160 ms -20.000032 ms +20.000032 ms
|
||||
current-bit/160ms 8 160 ms -0.000032 ms +0.000032 ms
|
||||
current-rtl/180ms 9 180 ms -0.000032 ms +0.000032 ms
|
||||
```
|
||||
|
||||
Kısa veya farklı PI koşusu:
|
||||
@@ -167,10 +167,11 @@ bias_drift =
|
||||
uydunun transmit subframe sınırı etiketidir. Full-subframe interrupt'ının
|
||||
receiver'a ulaştığı an değildir.
|
||||
|
||||
Mevcut hardware, subframe doğrulama/parity akışında takip eden subframe'den
|
||||
8 bit daha bekler. Navigation data 50 bit/s olduğu için bu sabit readout
|
||||
gecikmesi `8 × 20 ms = 160 ms` olur ve yazılımda `POSTPONE_TOW=0.160` ile
|
||||
temsil edilir. Bu yüzden ilk teslim edilen subframe için:
|
||||
Mevcut hardware, subframe doğrulama/parity akışında eski shift register'i
|
||||
okuduğu için takip eden subframe'in dokuzuncu bitinde teslim yapar. Navigation
|
||||
data 50 bit/s olduğu için sabit readout gecikmesi `9 × 20 ms = 180 ms` olur ve
|
||||
production yazılımda `POSTPONE_TOW=0.180` ile temsil edilir. Bu yüzden ilk
|
||||
teslim edilen subframe için:
|
||||
|
||||
```text
|
||||
transmit_epoch_TOW = HOW_TOW + POSTPONE_TOW
|
||||
@@ -187,6 +188,10 @@ epoch-aligned transmit time'ı baremetal navigation katmanında tam bir kez
|
||||
oluşturmalıdır. PPS APB periferiki kendisine verilen GPS reference time'a
|
||||
`POSTPONE_TOW` değerini tekrar eklememelidir.
|
||||
|
||||
Tracking RTL ileride current-bit candidate window ile sekizinci bitte validate
|
||||
edecek şekilde düzeltilirse aynı release'de firmware değeri 160 ms'ye geri
|
||||
alınmalıdır; RTL ve firmware düzeltmeleri birbirinden bağımsız uygulanamaz.
|
||||
|
||||
İlk HOW'un hangi kanaldan geleceği sadece uydunun yakınlığına bağlı değildir.
|
||||
Acquisition tamamlanma anı, bit lock ve bir sonraki tam subframe sınırı çoğu
|
||||
zaman propagation delay farkından daha baskındır. Monte Carlo startup modeli
|
||||
@@ -195,8 +200,9 @@ bu üç etkiyi ayrı gösterir.
|
||||
Önerilen ownership:
|
||||
|
||||
1. Raw 125 MHz counter resetten itibaren free-running çalışır.
|
||||
2. İlk geçerli HOW week/6-second mutlak zaman etiketini sağlar; ilk hardware
|
||||
delivery epoch'u için 160 ms sabit readout düzeltmesi ayrıca eklenir.
|
||||
2. İlk geçerli HOW week/6-second mutlak zaman etiketini sağlar; mevcut RTL'nin
|
||||
ilk hardware delivery epoch'u için 180 ms sabit readout düzeltmesi ayrıca
|
||||
eklenir.
|
||||
3. İlk coherent WLS çözümünde minimum corrected-ABS kanalı datum olarak
|
||||
seçilir; aynı SVID mevcut kaldığı sürece onun uçuş süresi
|
||||
`STARTOFFSET - b/c` ile elde edilir.
|
||||
@@ -325,9 +331,10 @@ yapar.
|
||||
çözümde minimum corrected ABS kanalı seçiliyor ve aynı SVID coherent
|
||||
snapshot'ta kaldığı sürece datum sabit tutuluyor. O kanalın TOW'u ve aynı
|
||||
nav-solve olayındaki C125 capture'ı birlikte taşınıyor.
|
||||
5. `POSTPONE_TOW=0.160`, hardware'ın mevcut subframe'i doğrulamak için takip
|
||||
eden subframe'den 8 bit daha beklemesinden oluşan sabit readout gecikmesidir.
|
||||
Uydu konum/saat epoch'u buna göre 160 ms ileri alınır. Bu değer signal
|
||||
5. `POSTPONE_TOW=0.180`, hardware'ın mevcut subframe'i eski shift register
|
||||
üzerinden doğrulayıp dokuzuncu takip eden bitte teslim etmesinden oluşan
|
||||
sabit readout gecikmesidir. Uydu konum/saat epoch'u buna göre 180 ms ileri
|
||||
alınır. Bu değer signal
|
||||
flight time veya WLS receiver clock bias ile birleştirilmemelidir. Mevcut
|
||||
`satpos()` zaten kullanım anında bir kez ekler; PPS peripheral tekrar eklemez.
|
||||
6. 125 MHz timestamp `ABS_SAMPLE` ve `REM_CODE_PHASE` ile aynı hardware
|
||||
|
||||
@@ -338,7 +338,7 @@ def page_executive(report: Report) -> None:
|
||||
ax,
|
||||
0.55,
|
||||
r"T_{GPS,k}=T_{TX,k}+S-\frac{b_k}{c}",
|
||||
"Minimum corrected-ABS kanalının receive GPS zamanı; ilk delivery için TTX,k = HOW + 0.160 s",
|
||||
"Minimum corrected-ABS kanalının receive GPS zamanı; ilk delivery için TTX,k = HOW + 0.180 s",
|
||||
)
|
||||
report.equation(
|
||||
ax,
|
||||
@@ -455,7 +455,7 @@ def page_lnav_timeline(report: Report) -> None:
|
||||
ax.text(x + 0.039, 0.58, label, color="white" if index < 2 else INK, ha="center", va="center", fontsize=7.5, weight="bold" if index < 2 else "normal")
|
||||
report.arrow(ax, (0.205, 0.545), (0.86, 0.49), color=ORANGE, text="HOW Z-count: sonraki 6 s subframe sınırının transmit-time etiketi", rad=-0.12)
|
||||
ax.add_patch(FancyBboxPatch((0.18, 0.445), 0.64, 0.045, boxstyle="round,pad=0.006", facecolor=PALE_ORANGE, edgecolor=ORANGE))
|
||||
ax.text(0.50, 0.467, "Hardware takip eden subframe'den 8 bit bekler: 8 × 20 ms = POSTPONE_TOW = 160 ms", fontsize=7.6, color=ORANGE, ha="center", va="center", weight="bold")
|
||||
ax.text(0.50, 0.467, "Mevcut hardware 9. takip eden bitte teslim eder: 9 × 20 ms = POSTPONE_TOW = 180 ms", fontsize=7.6, color=ORANGE, ha="center", va="center", weight="bold")
|
||||
|
||||
report.box(
|
||||
ax,
|
||||
@@ -518,7 +518,7 @@ def page_tx_rx(report: Report) -> None:
|
||||
color=ORANGE,
|
||||
)
|
||||
report.equation(ax, 0.42, r"T_{RX,i}=T_{HOW}+\frac{\rho_i+I_i+T_i}{c}-\delta t_{SV,i}", "Aynı transmit sınırı her kanalda farklı receive timestamp üretir")
|
||||
ax.text(0.50, 0.325, r"Hardware delivery epoch: $T_{event,i}=T_{HOW}+0.160\,s+\tau_i$", fontsize=9.2, color=ORANGE, ha="center", weight="bold")
|
||||
ax.text(0.50, 0.325, r"Hardware delivery epoch: $T_{event,i}=T_{HOW}+0.180\,s+\tau_i$", fontsize=9.2, color=ORANGE, ha="center", weight="bold")
|
||||
report.box(
|
||||
ax,
|
||||
0.07,
|
||||
@@ -557,7 +557,7 @@ def page_project_map(report: Report) -> None:
|
||||
(0.54, 0.54, 0.18, 0.10, "Linked-list state", "TOW owner\nsequence + sample", LIGHT, NAVY),
|
||||
(0.28, 0.54, 0.20, 0.10, "Coherent snapshot", "25 ms window\nmodulo unwrap", PALE_GREEN, GREEN),
|
||||
(0.06, 0.54, 0.17, 0.10, "Pseudorange", "minimum +\n68.802 ms", PALE_GREEN, GREEN),
|
||||
(0.06, 0.34, 0.17, 0.10, "Satellite model", "TOW + 160 ms\nephemeris/clock", PALE_BLUE, BLUE),
|
||||
(0.06, 0.34, 0.17, 0.10, "Satellite model", "TOW + 180 ms\nephemeris/clock", PALE_BLUE, BLUE),
|
||||
(0.32, 0.34, 0.23, 0.10, "Weighted LS", "[X Y Z b]\niono + tropo + URA/el", PALE_GREEN, GREEN),
|
||||
(0.64, 0.34, 0.30, 0.10, "Bugünkü çıkış", "position log + static last_solution[4]\nclock bias dışarı taşınmıyor", "#FBEAEA", RED),
|
||||
]
|
||||
@@ -796,7 +796,7 @@ def page_counter_mapping(report: Report) -> None:
|
||||
fig, ax = report.new_page("GPS time ile 125 MHz counter mapping'i")
|
||||
ax.text(0.08, 0.84, "İlk coherent WLS epoch'u k", fontsize=11, color=NAVY, weight="bold")
|
||||
boxes = [
|
||||
(0.07, 0.68, 0.25, 0.11, "Transmit etiketi", "İlk delivery: HOW + 0.160 s\nsonra nav-solve epoch", PALE_BLUE, BLUE),
|
||||
(0.07, 0.68, 0.25, 0.11, "Transmit etiketi", "İlk delivery: HOW + 0.180 s\nsonra nav-solve epoch", PALE_BLUE, BLUE),
|
||||
(0.375, 0.68, 0.25, 0.11, "WLS flight time", "τmin = S − b/c\nall-satellite solution", PALE_GREEN, GREEN),
|
||||
(0.68, 0.68, 0.25, 0.11, "Receive reference", "T_GPS,k = T_TX,k + τmin", PALE_ORANGE, ORANGE),
|
||||
(0.375, 0.47, 0.25, 0.11, "Hardware timestamp", "C125,k\naynı ABS/REM event", PALE_BLUE, BLUE),
|
||||
@@ -1304,7 +1304,7 @@ def page_open_points(report: Report) -> None:
|
||||
fig, ax = report.new_page("Projede ölçülerek kapatılacak açık noktalar")
|
||||
points = [
|
||||
("HOW boundary semantiği", "parse_subframe Z-count × 6 yapıyor. Full-subframe interrupt, bit_gen ABS_SAMPLE ve gerçek transmit next-subframe sınırı arasındaki sabit pipeline cycle sayısı scope/ILA ile ölçülmeli."),
|
||||
("POSTPONE_TOW = 0.160", "Doğrulanmış hardware readout gecikmesidir: takip eden subframe'den 8 bit beklenir; 50 bit/s hızda 160 ms. Mevcut satpos() kullanım anında bir kez ekler; PPS peripheral tekrar eklemez."),
|
||||
("POSTPONE_TOW = 0.180", "Mevcut RTL readout gecikmesidir: doğrulama dokuzuncu takip eden bitte yapılır; 50 bit/s hızda 180 ms. Mevcut satpos() kullanım anında bir kez ekler; PPS peripheral tekrar eklemez."),
|
||||
("RF ↔ 125 MHz bağı", "Aynı PLL/reference mı, bağımsız mı? Ortak drift ve independent jitter ölçülmeli; cross-timestamp uncertainty buna göre bütçelenmeli."),
|
||||
("Cold-start WLS timing", "Dört uyduda vertical/clock korelasyonu yüksek. Coarse alignment yapılabilir; PPS quality düşük işaretlenmeli ve PI bandwidth agresif seçilmemeli."),
|
||||
("Atmosfer/multipath", "Iono/tropo modele girse de residual b ve position'a sızar. Timing-only mode veya sabit/smoothed position ileride clock çözümünü iyileştirebilir."),
|
||||
@@ -1361,7 +1361,7 @@ def page_conclusion(report: Report) -> None:
|
||||
0.80,
|
||||
0.09,
|
||||
"En önemli mimari karar",
|
||||
"İlk uydu PPS'i başlatmaz. Baremetal HOW'a 160 ms readout düzeltmesini bir kez uygular; ilk coherent WLS bu etiketi free-running 125 MHz counter'a bağlar. PPS peripheral 160 ms'yi tekrar eklemez.",
|
||||
"İlk uydu PPS'i başlatmaz. Baremetal HOW'a 180 ms readout düzeltmesini bir kez uygular; ilk coherent WLS bu etiketi free-running 125 MHz counter'a bağlar. PPS peripheral 180 ms'yi tekrar eklemez.",
|
||||
face=NAVY,
|
||||
edge=NAVY,
|
||||
title_color="#8ED6E8",
|
||||
@@ -1414,7 +1414,7 @@ def generate(output_pdf: Path) -> None:
|
||||
report,
|
||||
"İlk HOW neden PPS receive-now değildir?",
|
||||
required_plots[4],
|
||||
"Sentetik acquisition/subframe Monte Carlo: hardware delivery, takip eden subframe'in 8 biti nedeniyle HOW sınırından 160 ms ve signal flight time kadar sonradır. HOW +160 ms +68.802 ms kaba yaklaşım bırakır; WLS flight-time + paired timestamp doğru handover'dır.",
|
||||
"Sentetik acquisition/subframe Monte Carlo: mevcut hardware delivery, dokuzuncu takip eden bit nedeniyle HOW sınırından 180 ms ve signal flight time kadar sonradır. HOW +180 ms +68.802 ms kaba yaklaşım bırakır; WLS flight-time + paired timestamp doğru handover'dır.",
|
||||
)
|
||||
plot_page(
|
||||
report,
|
||||
|
||||
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 333 KiB |
|
Before Width: | Height: | Size: 213 KiB After Width: | Height: | Size: 213 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 130 KiB |
@@ -4,18 +4,18 @@ epochs: 900
|
||||
raw WLS bias/c range: -5.888015 .. 0.673753 ms
|
||||
derived GPS reference RMS error: 60.522 ns
|
||||
capture-to-commit delay mean/p99: 21.600 / 31.529 ms
|
||||
first HOW used as receive-now, median phase error: -229.876 ms
|
||||
first HOW + 160 ms + 68.802 ms, median phase error: -1.074 ms
|
||||
first HOW used as receive-now, median phase error: -249.876 ms
|
||||
first HOW + 180 ms + 68.802 ms, median phase error: -1.074 ms
|
||||
4 satellites: position RMS=103.877 m, timing RMS=144.920 ns
|
||||
5 satellites: position RMS=20.194 m, timing RMS=45.603 ns
|
||||
7 satellites / drop-reacquisition: position RMS=14.626 m, timing RMS=36.888 ns
|
||||
timestamped PI: tail phase RMS=274.599 ns, |phase| p95=409.200 ns, PPS RMS=815.734 ns, rejected stale commits=0
|
||||
timestamped, PI disabled: tail phase RMS=233591.232 ns, |phase| p95=302909.699 ns, PPS RMS=181359.923 ns, rejected stale commits=0
|
||||
timestamped PI: tail phase RMS=274.256 ns, |phase| p95=410.422 ns, PPS RMS=815.642 ns, rejected stale commits=0
|
||||
timestamped, PI disabled: tail phase RMS=233589.285 ns, |phase| p95=302907.720 ns, PPS RMS=181358.257 ns, rejected stale commits=0
|
||||
untagged APB-now PI: tail phase RMS=18651473.186 ns, |phase| p95=19146158.593 ns, PPS RMS=18060541.154 ns, rejected stale commits=0
|
||||
|
||||
Interpretation:
|
||||
- bias/c is millisecond-scale because it contains the 68.802 ms synthetic datum and the minimum satellite path.
|
||||
- epoch-aligned TOW (first delivery: HOW + 160 ms) + STARTOFFSET - bias/c reconstructs GPS time at the paired timestamp.
|
||||
- epoch-aligned TOW (first delivery: HOW + 180 ms) + STARTOFFSET - bias/c reconstructs GPS time at the paired timestamp.
|
||||
- treating that old reference as valid at APB arrival converts software latency into PPS phase error.
|
||||
- timestamping removes that phase misassociation; control application delay remains only as loop delay.
|
||||
- baremetal applies the fixed 160 ms readout correction once; the PPS peripheral must not add it again.
|
||||
- baremetal applies the fixed 180 ms readout correction once; the PPS peripheral must not add it again.
|
||||
|
||||
@@ -30,7 +30,7 @@ CODE_FREQ_BASIS = 1.023e6
|
||||
START_OFFSET_MS = 68.802
|
||||
START_OFFSET_S = START_OFFSET_MS / 1000.0
|
||||
NAV_SOLVE_PERIOD_S = 10 * 0.020
|
||||
POSTPONE_TOW_S = 0.160
|
||||
POSTPONE_TOW_S = 0.180
|
||||
OMEGA_EARTH = 7.2921151467e-5
|
||||
WEEK_S = 604_800.0
|
||||
|
||||
|
||||
@@ -298,8 +298,9 @@ def simulate_startup_tow(
|
||||
acquisition_ready = rng.uniform(0.0, 18.0, size=(trial_count, len(satellites)))
|
||||
complete_subframe_tx = (np.floor(acquisition_ready / 6.0) + 2.0) * 6.0
|
||||
# The current hardware validates/delivers the completed subframe only
|
||||
# after receiving eight bits from the following subframe. At 50 bit/s
|
||||
# this is a deterministic 160 ms readout delay (POSTPONE_TOW), distinct
|
||||
# on the ninth following bit because validation reads the old shift
|
||||
# register. At 50 bit/s
|
||||
# this is a deterministic 180 ms readout delay (POSTPONE_TOW), distinct
|
||||
# from satellite signal flight time.
|
||||
how_interrupt_rx = (
|
||||
complete_subframe_tx + POSTPONE_TOW_S + flight_times[None, :]
|
||||
@@ -354,7 +355,7 @@ def plot_startup_tow(output_dir: Path, startup: dict[str, np.ndarray]) -> None:
|
||||
alpha=0.8,
|
||||
)
|
||||
axes[1, 0].set_xlabel("Phase error [ms]")
|
||||
axes[1, 0].set_title("Provisional: HOW + 160 ms + 68.802 ms")
|
||||
axes[1, 0].set_title("Provisional: HOW + 180 ms + 68.802 ms")
|
||||
axes[1, 0].grid(True, alpha=0.3)
|
||||
|
||||
axes[1, 1].hist(
|
||||
@@ -397,7 +398,7 @@ def build_summary(
|
||||
f"derived GPS reference RMS error: {finite_rms(timing_error)*1e9:.3f} ns",
|
||||
f"capture-to-commit delay mean/p99: {np.mean(latency)*1e3:.3f} / {np.percentile(latency, 99)*1e3:.3f} ms",
|
||||
f"first HOW used as receive-now, median phase error: {np.median(startup['how_as_receive_error_s'])*1e3:.3f} ms",
|
||||
f"first HOW + 160 ms + 68.802 ms, median phase error: {np.median(startup['how_plus_pipeline_startoffset_error_s'])*1e3:.3f} ms",
|
||||
f"first HOW + 180 ms + 68.802 ms, median phase error: {np.median(startup['how_plus_pipeline_startoffset_error_s'])*1e3:.3f} ms",
|
||||
]
|
||||
for start, stop, label in [
|
||||
(0.0, 20.0, "4 satellites"),
|
||||
@@ -426,10 +427,10 @@ def build_summary(
|
||||
"",
|
||||
"Interpretation:",
|
||||
"- bias/c is millisecond-scale because it contains the 68.802 ms synthetic datum and the minimum satellite path.",
|
||||
"- epoch-aligned TOW (first delivery: HOW + 160 ms) + STARTOFFSET - bias/c reconstructs GPS time at the paired timestamp.",
|
||||
"- epoch-aligned TOW (first delivery: HOW + 180 ms) + STARTOFFSET - bias/c reconstructs GPS time at the paired timestamp.",
|
||||
"- treating that old reference as valid at APB arrival converts software latency into PPS phase error.",
|
||||
"- timestamping removes that phase misassociation; control application delay remains only as loop delay.",
|
||||
"- baremetal applies the fixed 160 ms readout correction once; the PPS peripheral must not add it again.",
|
||||
"- baremetal applies the fixed 180 ms readout correction once; the PPS peripheral must not add it again.",
|
||||
]
|
||||
)
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||