fix(pps): align firmware TOW with current RTL
@@ -954,7 +954,9 @@ olarak yayinlanir.
|
||||
Ionosphere correction receiver azimut/elevasyonu hazir oldugunda WLS icinde
|
||||
uygulanir.
|
||||
- Ephemeris alanlarinin mevcut isimleri ile ICD anlamlari su sekildedir: `omgdot` gercekte `Omega0`, `omg0` gercekte argument of perigee `omega`, `omgkdot` gercekte `OmegaDot` degeridir. `satpos()` bunlari dogru matematiksel yerde kullanir; konu su an hesap hatasi degil, ileride yapilacak kontrollu isim duzeltmesidir.
|
||||
- `POSTPONE_TOW=0.160` donanim/pipeline zaman kalibrasyonunun bir parcasidir; kaynagi dogrulanmadan kaldirilmamalidir.
|
||||
- `POSTPONE_TOW=0.180` mevcut RTL'nin dokuzuncu takip eden navigation bitinde
|
||||
yaptigi teslimi duzeltir. `satpos()` ve PPS receive-time anchor bu degeri
|
||||
tam bir kez ve ayni firmware surumunde kullanir.
|
||||
- Ilk nav-solve interrupt'i geldiginde o anda allocated, hardware busy ve nav-solve interrupt'i etkin olan kanallar epoch'un sabit bekleme maskesine alinir. Unlock interrupt'i gelen kanal artik tracked olmadigi icin bekleme maskesinden cikarilir; epoch ortasinda navigation-ready olan yeni kanal ise aktif maskeyi buyutmez ve sonraki epoch'tan itibaren beklenir. Kalan beklenen kanallarin tamami gelirse snapshot son interrupt'ta hemen yayinlanir. 30 ms holdoff dolarsa veya daha yeni fiziksel epoch baslarsa eksik eski epoch WLS calistirilmadan discard edilir; eski ve yeni olcumler birlestirilmez.
|
||||
- Interrupt bekleme maskesi tamamlandiktan sonra frozen kanallarin tumu ortak TOW/`ABS_SAMPLE` kumesinde degilse epoch reddedilir. Selector'in buldugu daha kucuk alt kume yalniz diagnostic bilgidir ve WLS girdisi olamaz.
|
||||
- Dort uydu 3D konum + receiver clock bias icin minimum ve yeterlidir. Bu durumda
|
||||
@@ -1348,9 +1350,11 @@ Bu timer/scheduler yavasligi degildir. Firmware start ediyor; tamamlanma icin RF
|
||||
T_rx = TOW_ref + POSTPONE_TOW + STARTOFFSET/1000 - b/c
|
||||
```
|
||||
|
||||
- `POSTPONE_TOW=0.160 s`, takip eden subframe'dan parity icin beklenen sekiz
|
||||
bitin gecikmesidir ve yazilim tarafinda tam bir kez uygulanir. PPS RTL bu
|
||||
degeri tekrar eklemez.
|
||||
- `POSTPONE_TOW=0.180 s`, mevcut tracking RTL'nin parity kontrolunu dokuzuncu
|
||||
takip eden bitte tamamlamasinin gecikmesidir ve yazilim tarafinda tam bir kez
|
||||
uygulanir. PPS RTL bu degeri tekrar eklemez. Tracking RTL sekizinci bitte
|
||||
validate edecek sekilde degistirilirse bu sabit ayni release'de 160 ms'ye
|
||||
geri alinmalidir.
|
||||
- Bu GPS zamani, ayni kalici referans kanalinin 125 MHz capture counter'i ile atomik
|
||||
APB mailbox uzerinden eslenir. Ilk cozum coarse-align, sonraki cozumler Q2.46
|
||||
dusuk bant genislikli PI rate discipline yapar. WLS/APB calisma suresi faz
|
||||
|
||||
@@ -174,7 +174,10 @@
|
||||
|
||||
// gps defines from plutogpssim.
|
||||
|
||||
#define POSTPONE_TOW (double)(0.160)
|
||||
/* Current tracking RTL validates the subframe on the ninth following
|
||||
* navigation bit: 9 * 20 ms = 180 ms. satpos() and the PPS receive-time
|
||||
* anchor must use this same delivery-epoch correction exactly once. */
|
||||
#define POSTPONE_TOW (double)(0.180)
|
||||
#define MAX_SAT (12) // 32 (TODO. OBSOLATED)
|
||||
|
||||
#define SECONDS_IN_WEEK 604800.0
|
||||
|
||||
@@ -49,9 +49,9 @@ The default command executes the diagnostic matrix:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Positive `DUT - trusted PPS` means the project output is late. The default
|
||||
@@ -110,7 +110,8 @@ jitter assertion or synthetic run cannot certify it.
|
||||
The sweep includes the current coefficients, quieter/faster precision loops,
|
||||
a robust-noise guard, a larger Doppler-drift gain, and a quality-scheduled
|
||||
candidate. The generated report contains the current numerical comparison.
|
||||
No production constants are changed by the analysis.
|
||||
The stability analysis does not alter loop constants. Production firmware now
|
||||
uses the current-RTL-compatible 180 ms epoch correction described below.
|
||||
|
||||
## 20 ms diagnosis
|
||||
|
||||
@@ -124,15 +125,18 @@ The implemented interface is consequently:
|
||||
|
||||
```text
|
||||
current RTL delivery 9 * 20 ms = 180 ms
|
||||
firmware POSTPONE_TOW 8 * 20 ms = 160 ms
|
||||
signed epoch mismatch 20 ms
|
||||
production POSTPONE_TOW 9 * 20 ms = 180 ms
|
||||
signed epoch mismatch 0 ms
|
||||
|
||||
former firmware value 8 * 20 ms = 160 ms
|
||||
former signed mismatch 20 ms
|
||||
```
|
||||
|
||||
With the current bitstream, `POSTPONE_TOW=0.180` is a firmware-only workaround
|
||||
and must be used consistently by both satellite-state and PPS calculations.
|
||||
It is 180 ms, not 190 ms. The preferred permanent correction is to validate a
|
||||
candidate window containing the current eighth bit and retain the intended
|
||||
160 ms firmware compensation.
|
||||
Production firmware now uses `POSTPONE_TOW=0.180` as the current-RTL-compatible
|
||||
correction, consistently in both satellite-state and PPS calculations. It is
|
||||
180 ms, not 190 ms. If RTL is later changed to validate a candidate window
|
||||
containing the current eighth bit, firmware must return to 160 ms in the same
|
||||
coordinated release.
|
||||
|
||||
The validation intentionally does not modify production RTL or firmware.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ This report is generated by `stability_analysis.py`. The absolute LNAV epoch pat
|
||||
- Current RTL delivered the validated subframe after 9 following bits.
|
||||
- With 180 ms postponement, reference error was -0.000032 ms.
|
||||
- DUT minus trusted PPS was 32.01 ns. That remainder is the model's configured four-PCLK capture pipeline, not a measured board delay.
|
||||
- The production source still defines `POSTPONE_TOW` as 160 ms; this analysis uses the requested 180 ms candidate configuration.
|
||||
- Production firmware and this analysis both define `POSTPONE_TOW` as 180 ms for the current RTL delivery semantics.
|
||||
|
||||
## Repository hardware data
|
||||
|
||||
|
||||
@@ -589,7 +589,7 @@ def simulate_pps_core(
|
||||
@dataclass(frozen=True)
|
||||
class EndToEndConfig:
|
||||
decoder_mode: DecoderMode = DecoderMode.CURRENT_RTL
|
||||
postpone_tow_s: float = 0.160
|
||||
postpone_tow_s: float = 0.180
|
||||
nav_solve_period_bits: int = 10
|
||||
propagation_s: float = 0.070
|
||||
pps_capture_pipeline_ticks: int = 4
|
||||
@@ -790,14 +790,14 @@ def default_comparison() -> tuple[EndToEndResult, ...]:
|
||||
run_end_to_end(EndToEndConfig()),
|
||||
run_end_to_end(
|
||||
EndToEndConfig(
|
||||
decoder_mode=DecoderMode.CURRENT_BIT,
|
||||
decoder_mode=DecoderMode.CURRENT_RTL,
|
||||
postpone_tow_s=0.160,
|
||||
)
|
||||
),
|
||||
run_end_to_end(
|
||||
EndToEndConfig(
|
||||
decoder_mode=DecoderMode.CURRENT_RTL,
|
||||
postpone_tow_s=0.180,
|
||||
decoder_mode=DecoderMode.CURRENT_BIT,
|
||||
postpone_tow_s=0.160,
|
||||
)
|
||||
),
|
||||
)
|
||||
@@ -838,7 +838,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
||||
default="matrix",
|
||||
help="run the three-way diagnosis matrix or one decoder mode",
|
||||
)
|
||||
parser.add_argument("--postpone-ms", type=float, default=160.0)
|
||||
parser.add_argument("--postpone-ms", type=float, default=180.0)
|
||||
parser.add_argument("--propagation-ms", type=float, default=70.0)
|
||||
parser.add_argument("--capture-pipeline-ticks", type=int, default=4)
|
||||
parser.add_argument("--compute-delay-ms", type=float, default=10.0)
|
||||
|
||||
@@ -597,8 +597,8 @@ def write_report(
|
||||
f"{epoch_result.pps.edges[0].dut_minus_trusted_s * 1.0e9:.2f} ns. "
|
||||
"That remainder is the model's configured four-PCLK capture pipeline, "
|
||||
"not a measured board delay.",
|
||||
"- The production source still defines `POSTPONE_TOW` as 160 ms; this "
|
||||
"analysis uses the requested 180 ms candidate configuration.",
|
||||
"- Production firmware and this analysis both define `POSTPONE_TOW` "
|
||||
"as 180 ms for the current RTL delivery semantics.",
|
||||
"",
|
||||
"## Repository hardware data",
|
||||
"",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import re
|
||||
import unittest
|
||||
|
||||
from pps_end_to_end_validation.pps_end_to_end import (
|
||||
@@ -50,6 +52,22 @@ class LnavDecoderTests(unittest.TestCase):
|
||||
|
||||
|
||||
class PpsEndToEndTests(unittest.TestCase):
|
||||
def test_model_default_matches_production_firmware_postpone_tow(self):
|
||||
header = (
|
||||
Path(__file__).resolve().parents[1]
|
||||
/ "gps_system/header/gps/gps_ip_defines.h"
|
||||
).read_text(encoding="utf-8")
|
||||
match = re.search(
|
||||
r"#define\s+POSTPONE_TOW\s+\(double\)\(([0-9.]+)\)",
|
||||
header,
|
||||
)
|
||||
self.assertIsNotNone(match)
|
||||
self.assertAlmostEqual(float(match.group(1)), 0.180)
|
||||
self.assertAlmostEqual(
|
||||
EndToEndConfig().postpone_tow_s,
|
||||
float(match.group(1)),
|
||||
)
|
||||
|
||||
def test_bit_generator_recreates_50bps_stream_and_registered_sample_lag(self):
|
||||
result = run_end_to_end(EndToEndConfig())
|
||||
self.assertEqual(result.bit_valid_events, 2 + 3 * 300)
|
||||
@@ -76,7 +94,7 @@ class PpsEndToEndTests(unittest.TestCase):
|
||||
self.assertGreater(result.firmware_rejected_nav_solves, 0)
|
||||
|
||||
def test_current_rtl_and_160ms_correction_make_pps_20ms_late(self):
|
||||
result = run_end_to_end(EndToEndConfig())
|
||||
result = run_end_to_end(EndToEndConfig(postpone_tow_s=0.160))
|
||||
offset_s = result.pps.edges[0].dut_minus_trusted_s
|
||||
self.assertAlmostEqual(result.expected_semantic_offset_ms, 20.0, places=9)
|
||||
self.assertGreater(offset_s, 0.019999)
|
||||
@@ -86,17 +104,18 @@ class PpsEndToEndTests(unittest.TestCase):
|
||||
|
||||
def test_current_bit_validation_and_160ms_remove_lnav_bit_error(self):
|
||||
result = run_end_to_end(
|
||||
EndToEndConfig(decoder_mode=DecoderMode.CURRENT_BIT)
|
||||
EndToEndConfig(
|
||||
decoder_mode=DecoderMode.CURRENT_BIT,
|
||||
postpone_tow_s=0.160,
|
||||
)
|
||||
)
|
||||
self.assertEqual(result.first_subframe_readout_bits, 8)
|
||||
self.assertEqual(result.first_nav_solve_bit, 18)
|
||||
self.assertAlmostEqual(result.expected_semantic_offset_ms, 0.0, places=9)
|
||||
self.assertLess(abs(result.pps.edges[0].dut_minus_trusted_s), 100.0e-9)
|
||||
|
||||
def test_180ms_firmware_workaround_matches_current_rtl(self):
|
||||
result = run_end_to_end(
|
||||
EndToEndConfig(postpone_tow_s=0.180)
|
||||
)
|
||||
def test_180ms_production_firmware_matches_current_rtl(self):
|
||||
result = run_end_to_end(EndToEndConfig())
|
||||
self.assertEqual(result.first_subframe_readout_bits, 9)
|
||||
self.assertAlmostEqual(result.expected_semantic_offset_ms, 0.0, places=9)
|
||||
self.assertLess(abs(result.pps.edges[0].dut_minus_trusted_s), 100.0e-9)
|
||||
@@ -119,12 +138,16 @@ class PpsEndToEndTests(unittest.TestCase):
|
||||
result = run_end_to_end(
|
||||
EndToEndConfig(
|
||||
decoder_mode=DecoderMode.CURRENT_BIT,
|
||||
postpone_tow_s=0.160,
|
||||
dut_output_delay_s=12.0e-9,
|
||||
trusted_output_delay_s=35.0e-9,
|
||||
)
|
||||
)
|
||||
baseline = run_end_to_end(
|
||||
EndToEndConfig(decoder_mode=DecoderMode.CURRENT_BIT)
|
||||
EndToEndConfig(
|
||||
decoder_mode=DecoderMode.CURRENT_BIT,
|
||||
postpone_tow_s=0.160,
|
||||
)
|
||||
)
|
||||
delta = (
|
||||
result.pps.edges[0].dut_minus_trusted_s
|
||||
|
||||
@@ -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"
|
||||
|
||||