# Stationary GPS / ICM-4268x fusion Bu klasör Genesys2 kartından UART ile alınan GPS WLS konumlarını ve PMOD SPI üzerindeki ICM-42686/ICM-42688 ölçümlerini Python'da işler. Filtre 15 hata durumlu bir ESKF'dir: ENU konum/hız, quaternion tutum, ivmeölçer biası ve jiroskop biası. Kartın durağan olduğu deneyde zero-velocity update (ZUPT) uygulanır ve GPS innovation değerlerine aykırı-ölçüm kapısı konur. ## Çalıştırma UART kaydı: ```sh python3 serial_capture.py --duration 60 --output logs/gps_60s.csv python3 serial_capture.py --duration 75 --stop-text 'Complete:' \ --output logs/imu_60s.csv ``` Mevcut logları işleme: ```sh python3 fusion_eskf.py ``` Sabit-kısıtlı ve hareket-kabiliyetli modelleri aynı kayıt üzerinde karşılaştırma: ```sh python3 compare_eskf_models.py \ --gps logs/gps_live_5min_20260713.csv \ --imu logs/imu_live_5min_20260713.csv \ --output output/model_compare_5min ``` Sabit model her IMU penceresinde zero-velocity ve zero-gyro ölçümü uygular. Hareket-kabiliyetli model bunları sürekli uygulamaz; ivme normu ve gyro normundan üç ardışık durağan pencere algıladığında etkinleştirir. PMOD testinin UART çıktısı 500 ms pencere ortalaması olduğundan bu deney durağan gürültü ve model davranışı karşılaştırmasıdır. Gerçek hareketli kullanım için ham veya yüksek hızlı IMU örnekleri ile GPS ölçümleri aynı CPU sayacıyla firmware içinde zaman damgalanmalıdır. Linux masaüstü OpenStreetMap oynatıcısını açma: ```sh python3 map_player.py ``` 5 dakikalık sabit/adaptif model karşılaştırmasını doğrudan açma: ```sh python3 map_player.py \ --comparison output/model_compare_5min_20260713/model_comparison.csv \ --model adaptive ``` `--model fixed` aynı kaydı sürekli-stationary modelle gösterir. Pencerede oynat/duraklat, sample sürgüsü, 0.5–4x hız, zoom/pan, ham GPS ve ESKF izleri bulunur. Tile'lar `output/osm_tile_cache/` altında cache edilir; ilk açılışta harita tabanı için internet bağlantısı gerekir. ## Deney sınırı İstenen akışta GPS ve IMU UART logları peş peşe toplandı. Kart durağan olduğu için iki 0–60 s ekseni offline modellemede üst üste bindirilmiştir. Bu sonuç durağan bias/noise ve konum kararlılığı deneyidir. Hareketli bir sistemde aynı ESKF'nin anlamlı olması için GPS ve ham/decimate edilmiş IMU örnekleri aynı firmware çalışmasında ortak donanım zaman damgasıyla kaydedilmelidir; 500 ms ortalamalar hızlı dinamiği korumaz. ## Standalone GPS WLS bütünlük çalışması (2026-07-12) Bu bölüm, standalone GPS konumundaki 20--30 m ve daha büyük sıçramaları araştırmak için yapılan firmware karşılaştırmasını kaydeder. Karşılaştırılan eski kaynak commit'i `07ddf29` (`first draft`) idi. Yeni kaynakta residual, chi-square, covariance, validity, leave-one-out FDE, çalışma süresi ve ISR tanıları bulunuyordu. ### Karşılaştırma yöntemi GDB ile çalışan DTIM imajının üzerine başka bir ELF yazıldığında Rocket I-cache'in eski firmware satırlarını yürütmeye devam ettiği gözlendi. Örneğin `0x80002f58` adresi eski ELF'te `gps_pps_init`, yeni ELF'te ise `gps_process_isr_events` içindeydi; access-fault anındaki return address yeni ELF anlamına uyuyordu. `fence.i` stub'ı çalıştırılması da bu kart/akışta güvenilir bir hot-load sağlamadı. Bu nedenle aşağıdaki A/B ölçümlerinde GDB hot-load kullanılmadı: 1. İlgili ELF bootloader formatındaki application flash image'a çevrildi. 2. Image `0x01800000` application flash bölgesine yazıldı. 3. FPGA SRAM aynı bitstream ile yeniden programlandı. 4. Bootloader ELF'i flash'tan DTIM'e kopyaladı; ilk I-cache dolumu ile RAM imajının aynı firmware olması sağlandı. 5. İlk konum çözümü acquisition süresinden sonra beklendi. 6. Kart ve anten sabitken 300 saniyelik UART kaydı alındı. Sapmalar surveyed bir koordinata göre değil, her koşunun kendi medyan konumuna göre hesaplandı. Bu nedenle aşağıdaki değerler mutlak doğruluktan çok durağan konum dağılımını/hassasiyetini gösterir. Farklı koşulardaki uydu sayısı ve DOP ayrıca belirtilmiştir. ### Kullanılan imajlar ve loglar - Exact eski ELF: `artifacts/firmware_ab/gps_old.elf` - FDE açık yeni ELF: `artifacts/firmware_ab/gps_new.elf` - FDE kapalı yeni ELF: `artifacts/firmware_ab/gps_new_fde_off.elf` - Eski log: `logs/ab_live_old_5min.csv` - FDE açık yeni log: `logs/ab_live_new_5min.csv` - FDE kapalı yeni log: `logs/ab_live_new_fde_off_5min.csv` - Uydu/FDE gruplu sonuç: `output/firmware_ab_live_5min_by_satellites.csv` - FDE kapalı karşılaştırma: `output/firmware_ab_live_fde_off_5min_by_satellites.csv` - Analiz programı: `compare_firmware_logs.py` FDE kapalı ELF SHA-256: ```text 23e2d5be11ab0bf23213c5253b4213277f11e5785d90484c9d624b4fcae944dc ``` FDE kapalı 5 dakika log SHA-256: ```text c2815c0cf3e7f76dd0a19db9526421355d6699c4bc1edc6407fde496e09bafc8 ``` ### Canlı A/B sonuçları | Firmware/çözüm | Kullanılabilir uydu | Örnek | Yatay ort. | Yatay P95 | Yatay maks. | Düşey mutlak ort. | 3B P95 | 3B maks. | |---|---:|---:|---:|---:|---:|---:|---:|---:| | Eski firmware | 8 | 485 | 6.01 m | 11.70 m | 20.79 m | 9.60 m | 25.05 m | 38.97 m | | Yeni, FDE açık, tümü | çoğunlukla 7 | 300 | 9.71 m | 30.34 m | 44.90 m | 16.43 m | 78.95 m | 128.96 m | | Yeni, FDE açık ama FDE seçilmeyen epoch | 7 | 231 | 6.84 m | 13.41 m | 17.33 m | 10.85 m | 28.03 m | 37.80 m | | Yeni, FDE tarafından 7'den 6'ya düşürülen epoch | 7 -> 6 | 68 | 19.22 m | 37.09 m | 44.90 m | 34.52 m | 108.30 m | 128.96 m | | Yeni, FDE compile-time kapalı | 7 | 300 | 8.64 m | 16.74 m | 22.56 m | 14.34 m | 40.90 m | 88.73 m | DOP medyanları aynı değildi: | Koşu | HDOP | VDOP | |---|---:|---:| | Eski, 8 uydu | 1.222 | 1.991 | | Yeni, FDE açık | 1.339 | 2.102 | | Yeni, FDE kapalı | 1.642 | 2.852 | FDE kapalı koşu daha kötü geometriye rağmen FDE açık toplam sonuçtan daha kararlıydı. Yatay P95 `30.34 m`den `16.74 m`ye, yatay maksimum `44.90 m`den `22.56 m`ye ve 3B P95 `78.95 m`den `40.90 m`ye düştü. ### FDE teşhisi ve alınan karar FDE açık koşuda 300 epoch'un 68'inde (%22.7) leave-one-out FDE uygulandı. 99% chi-square kapısının nominal false-alarm oranı yaklaşık %1 olmalıydı. Çıkarılan uydu tek bir SVID değildi: SVID 13, 19, 20, 21, 6 ve 29 farklı epoch'larda seçildi. Bu davranış tek ve sürekli arızalı bir uydudan çok, measurement sigma/covariance modelinin gerçek tracking gürültüsü ve multipath'i küçümsemesiyle uyumludur. FDE açık koşuda exclusion içeren ardışık konum çiftlerinin 3B step ortalaması `47.40 m`, FDE içermeyen çiftlerde `18.45 m` idi. Bazı kötü FDE seçimleri integrity-valid olarak işaretlendi. Altı uydu için FDE daha önce sentetik testte ayrıca engellenmişti; çünkü 6 -> 5 leave-one-out çözümü yalnız bir residual serbestlik derecesi bırakıp 123 m hatalı bir çözümü geçerli gösterebilmişti. Ürün firmware'inde otomatik FDE seçimi şu anda compile-time kapalıdır: ```c #define GPS_NAV_ENABLE_FDE 0u ``` Full-WLS konumu üretilmeye devam eder. Post-fit residual, chi-square, DOF, threshold, covariance, hAcc/vAcc ve validity hesapları/logları korunur. Chi-square fail eden çözüm konum olarak görülebilir fakat `valid=0` olur; PPS ve sonraki WLS seed'i invalid çözümle güncellenmez. FDE kapalı koşuda: - 300/300 epoch'ta `fde=0` ve `fde_trials=0`; - 235/300 epoch integrity-valid (%78.3); - ISR overflow, PLIC repeat, drain-limit, coalesced event, satellite loss ve period overrun sayaçları sıfır; - maksimum foreground süresi 288.74 ms; - maksimum WLS süresi 28.11 ms; - 1 saniyelik/50 milyon cycle bütçe hiç aşılmadı. FDE ancak C/N0, tracking variance, URA, elevation ve multipath bileşenlerinden kalibre edilmiş absolute measurement sigma üretildikten; normalized residual, solution separation, exclusion uniqueness ve zaman hysteresis'i eklendikten sonra yeniden açılmalıdır. ## Eski firmware'deki kalıcı 0.2 s TOW faz hatası ### Ölçüm kanıtı Eski firmware acquisition logunun ilk çözümü 5 uyduyla yapıldı ve bu ilk epoch'ta bütün TOW değerleri `64620.200 s` idi. SVID 6 daha sonra tracking kanalı 7'ye bağlandı. Sekiz uydulu 5 dakika kaydında: - 485 epoch'un 485'i TOW-incoherent idi; - çoğunluk TOW ile SVID 6 arasındaki fark her epoch'ta tam `-0.200 s` idi; - ilk epoch: çoğunluk `64634.200`, SVID 6 `64634.000`; - son epoch: çoğunluk `64933.400`, SVID 6 `64933.200`; - sonraki subframe/HOW alımları farkı düzeltmedi. Dolayısıyla hata geçici değildi. SVID 6 çözümde kaldığı sürece uydu konumu 0.2 saniye yanlış epoch için hesaplandı. Bunun alıcı WLS konumuna etkisi uydu geometrisine bağlıdır; iki firmware medyanı arasındaki 3B fark bu nedenle mutlak doğruluk ölçümü olarak yorumlanamaz. Yeni 1 saniyelik koşuların her ikisinde de 300/300 epoch TOW-coherent idi; `tow_aligned=0` ve `tow_rejected=0` kaldı. Bu, eski hatanın her bootta zorunlu olmadığını fakat kanal geç katıldığında kalıcı olabildiğini gösterir. ### Kök mekanizma Mevcut yazılım her tracking kanalı için ayrı TOW state'i yürütüyor: 1. Kanal önce LNAV HOW alanından TOW alıyor. 2. İlk nav-solve interrupt'ında TOW ownership `HOW` kaynağından `NAV_SOLVE` kaynağına geçiriliyor. 3. Bundan sonra kanal TOW'u recursively `tow += event_count * NAV_SOLVE_TIMER * 20 ms` ile artırılıyor. 4. Ownership geçtikten sonra daha sonraki HOW değerleri TOW'u yeniden anchor etmiyor. Kanalın enable/ilk interrupt sınırında bir tick off-by-one oluşursa bütün sonraki artışlar doğru miktarda fakat yanlış başlangıçtan yapılır; sabit faz hatası bu yüzden kalıcı olur. Log, SVID 6'nın geç katıldığını ve hatanın tam bir eski nav periodu olduğunu kanıtlıyor. İlk yanlış tick'in enable/flag sıralamasından mı yoksa aynı olayda HOW ve nav-solve işlenmesinden mi geldiği geçiş anı iki UART dosyası arasındaki kısa boşlukta kaldığı için logdan tek başına kesinleştirilemiyor. Ancak recursive kanal-bağımsız TOW mimarisinin hatayı kendi kendine düzeltemediği kesindir. IS-GPS-200N'e göre HOW içindeki TOW sayacı bir sonraki subframe'in başlangıç zamanını ifade eder. Kodun `(HOW >> 13) * 6` dönüşümü bu 6 saniyelik değeri üretir. Kalıcı düzeltme, bu absolute yayın zamanını yalnız ilk başlangıç için değil sürekli time anchor olarak kullanmalıdır. Referans: , bölüm 3.3.4 ve 20.3.3.2. ### Uygulanan kalıcı TOW mimarisi 2026-07-12'de kanal başına recursive TOW artışı kaldırıldı ve aşağıdaki HOW/receiver-sample anchor modeli ürün firmware'ine uygulandı. Snapshot'ta azınlık TOW'unu çoğunluğa kopyalayan geçici recovery yolu da kaldırıldı: 1. Her geçerli LNAV subframe sonunda kanal için şu anchor saklanır: `how_tow`, `how_week`, `how_abs_sample_raw`, düzeltilmiş `how_abs_sample` ve anchor-valid bilgisi. 2. HOW TOW bir sonraki subframe başlangıcını gösterdiği ve nav-bits event'i alınan subframe'in sonuna karşılık geldiği için bu ikisi aynı zaman sınırında anchor edilir. RTL incelemesinde `bit_gen.sv` içindeki `absolute_sample_o` değerinin geçerli 20 ms bit sınırında üretildiği ve `tracking_wrapper.sv` içindeki `load_sigs` yolunun geçerli/pariteli subframe'de `ABS_SAMPLE` ile `REM_CODE_PHASE`'ı birlikte latch ettiği doğrulandı. 3. Her nav-solve ölçümünün TOW'u önceki nav-solve TOW'una ekleme yapılarak değil, son HOW anchor'ından tekrar hesaplanır: ```text delta_samples = signed_wrap(nav_abs_sample - how_abs_sample) measurement_tow = normalize(how_tow + delta_samples / 16_368_000) ``` `REM_CODE_PHASE` düzeltmesi iki uçta da hesaba katılmalıdır. 32-bit `ABS_SAMPLE` farkı signed/wrapped alınmalıdır; anchor 6 saniyede bir yenilendiği için wrap belirsizliği oluşmaz. 4. Aynı interrupt'ta hem nav-bits hem nav-solve flag varsa önce HOW anchor güncellenir; nav-solve için `delta_samples=0` olur. Eski koddaki koşulsuz `+period` off-by-one riski ortadan kalkar. 5. Anchor yaşı, subframe/parity geçerliliği ve finite/range kontrolleri zorunlu yapıldı. Geçerli anchor olmayan veya 12 saniyeden eski anchor'a sahip kanalın nav-solve ölçümü kabul edilmez. 6. `gps_tow_source` ownership state'i ve `gps_advance_tow_from_nav_timer()` kaldırılır. Interrupt count yalnız event kaybı tanısı için tutulur, absolute GPS zamanının kaynağı olmaz. 7. Coherent snapshot kontrolü son savunma olarak kalır; fark görülürse epoch veya problemli kanal reject edilir. TOW değeri sessizce başka kanalın değeriyle değiştirilmez. Üretim kodu `header/gps_time_anchor.h` ve `src/gps_time_anchor.c` içindedir. `parse_subframe()` artık TOW state'ini değiştirmez; yalnız HOW TOW değerini dışarı verir. `gps_time_from_sample_anchor()` her nav-solve için GPS zamanını son HOW ve iki receiver-sample latch'i arasındaki farktan baştan üretir. Uygulanan birim testler: - HOW ile aynı anda gelen ilk nav-solve (`delta=0`); - 200 ms ve 1 s sonraki nav-solve; - geç enable edilen kanal; - bir veya birkaç coalesced/missed interrupt; - 32-bit `ABS_SAMPLE` wrap; - GPS week rollover; - stale HOW anchor; - aynı coherent epoch'ta bütün kanalların TOW farkının tolerans içinde olması. Host testleri normal optimizasyonla ve AddressSanitizer/UndefinedBehaviorSanitizer ile geçti. 50 MHz Rocket ürün build'i de başarılı oldu. Yeni anchor fonksiyonları ELF'te toplam yaklaşık 264 bayt text alanı kullanıyor; 1 Hz'de kanal başına bir kez çalıştığı için WLS yanında CPU etkisi ihmal edilebilir düzeydedir. ### Flash-boot donanım doğrulaması GDB hot-load kullanılmadan yeni ELF application flash bölgesine yazıldı ve FPGA yeniden programlanarak bootloader üzerinden temiz DTIM/I-cache başlangıcı yapıldı. Kullanılan dosyalar: - `artifacts/firmware_ab/gps_new_how_anchor_fde_off.elf` - `artifacts/firmware_ab/gps_new_how_anchor_fde_off.flash.bin` - `logs/how_anchor_acquisition.csv` - `logs/how_anchor_fde_off_5min.csv` - `output/firmware_ab_how_anchor_fde_off_5min_by_satellites.csv` ELF SHA-256: ```text fb1de03aafacf46d95bde375f3f744635472e9893a9aff6f3c3db9a16444c5ce ``` 5 dakika log SHA-256: ```text 82b08bd35d4452f92db6af609b2a03db2ff7b8f78443414ca7a0238c3cb603ed ``` Acquisition sırasında bir kanal diğerlerinden altı nav-solve epoch daha geç katıldı (`seq=8`, diğer kanallar `seq=14`). Buna rağmen ortak ölçüm epoch'unda bütün kanallar `67640.000 s` TOW üretti; eski yazılımdaki `-0.200 s` kalıcı faz farkı yeniden oluşmadı. 5 dakikalık sabit anten ölçümü: | Metrik | Sonuç | |---|---:| | NAV çözümü | 300 | | Kanal zaman ölçümü | 2100 | | TOW yayılımı P95 | 19 us | | TOW yayılımı maksimum | 33 us | | 1 ms üstü TOW epoch'u | 0 | | `tow_mismatch` / `tow_rejected` | 0 / 0 | | ISR overflow / PLIC repeat / drain limit | 0 / 0 / 0 | | Coalesced / lost / period overrun | 0 / 0 / 0 | | Integrity-valid | 270/300 (%90.0) | | FDE uygulanması | 0/300 | | Maksimum foreground / WLS | 290.13 ms / 28.34 ms | | HDOP / VDOP medyan | 1.511 / 2.407 | | Yatay ortalama / P95 / maksimum | 8.34 m / 16.36 m / 24.93 m | | 3B P95 | 32.64 m | FDE kapalı önceki yeni-firmware koşusu yatay ortalama/P95 olarak `8.64/16.74 m`, HOW-anchor koşusu `8.34/16.36 m` verdi. Dolayısıyla FDE kapatılınca full-WLS dağılımı eski firmware'e yakın seviyeye döndü. Eski firmware 8 uydu ve daha iyi geometriyle `6.01/11.70 m`, yeni koşu çoğunlukla 7 uyduyla `8.34/16.36 m` üretti. Bu farkın tamamı algoritma farkı sayılamaz; koşuların uydu sayıları/DOP'ları farklıdır ve surveyed ground truth yoktur. FDE açık yeni koşunun `9.71/30.34 m` toplam sonucu ise belirgin daha kötüydü. Not: Eski logdaki hata `0.2 ms` değil, `0.2 s = 200 ms` idi. Yeni ölçümdeki en büyük kanallar arası TOW farkı 33 us, yani 0.033 ms oldu. ### Son savunma Anchor düzeltmesine rağmen TOW farkı görülürse epoch invalid/reject edilir. SVID'e özel `+0.2 s` eklenmez ve azınlık TOW'u çoğunluğa kopyalanmaz; böylece başka kanal veya başka nav periodundaki gerçek zaman hatası gizlenmez.