368 lines
16 KiB
Markdown
368 lines
16 KiB
Markdown
# 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.
|