Files
gps/soc/software/fusion/README.md
T

368 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:
<https://archive.gps.gov/technical/icwg/IS-GPS-200N.pdf>, 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.