1182 lines
59 KiB
Markdown
1182 lines
59 KiB
Markdown
# GPS / IMU ESKF fusion
|
||
|
||
Bu klasör Genesys2 kartından UART ile alınan GPS WLS konumlarını ve PMOD SPI
|
||
üzerindeki TDK ICM-4268x veya ST LSM6DSOX ö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.
|
||
|
||
Bare-metal ürün firmware'i ana dizinden iki profille üretilebilir:
|
||
|
||
```sh
|
||
# TDK + GPS + ESKF (varsayılan GPS_ESKF_ENABLE=1)
|
||
make FPGA_BOARD=genesys2 APP=gps_system \
|
||
GPS_ESKF_ENABLE=1 IMU_SENSOR=tdk fpga-mcs
|
||
|
||
# GPS-only; IMU/ESKF kapalı, WLS/Doppler/PPS açık
|
||
make FPGA_BOARD=genesys2 APP=gps_system \
|
||
GPS_ESKF_ENABLE=0 fpga-mcs
|
||
```
|
||
|
||
Firmware ve UART kayıt aracının varsayılan hızı `460800` baud'dur. İki profil
|
||
aynı MCS/BIN çıktı yolunu kullandığı için ikinci build ilk dosyanın üzerine
|
||
yazar.
|
||
|
||
## Güncel durum ve devralma notu (2026-07-16)
|
||
|
||
Bu bölüm yeni bir geliştirme oturumunun nereden devam edeceğini tek yerde
|
||
özetler. Aşağıdaki Python model ve bare-metal C uygulaması aynı problemi çözer,
|
||
fakat aynı program değildir:
|
||
|
||
### Asenkron IMU/GPS düzeltmesi ve sentetik oran matrisi
|
||
|
||
Önceki prototipte 52 Hz ST akışından yalnız yaklaşık 250 ms'de bir ham örnek
|
||
seçiliyordu. Bu inertial downsampling değildir: kısa gyro hareketi iki seçilen
|
||
örneğin arasında kalınca değişen gravity vektörü görülüyor, dönüş görülmüyor ve
|
||
yanlış yatay ivme entegre ediliyordu. Linux C hızlı-eğim testinde bu yol 8.169 m
|
||
tepe yatay hata ve 1.554 m/s kalıcı hız üretti.
|
||
|
||
Bu seçim katmanı kaldırıldı. Artık her raw sample kendi timestamp'iyle işlenir;
|
||
ardışık accel/gyro örnekleri midpoint mechanization ile entegre edilir. GPS,
|
||
IMU'dan bağımsız bir position observation'dır. WLS yalnız geçerli olduğunda
|
||
ölçüm epoch'unda uygulanır; epoch iki IMU sample'ı arasındaysa input lineer
|
||
interpolate edilir, update sonrası kalan IMU geçmişi current-time horizon'a
|
||
replay edilir. Ana döngü IMU kuyruğunu WLS'den önce ve sonra tamamen boşaltır.
|
||
|
||
`async_rate_matrix_test.c` aynı üretim C kaynaklarına 52 Hz timestamp'li IMU,
|
||
100/200/1000 ms GPS, 73/310 ms delivery delay, farklı eksenlerde ivmelenme ve
|
||
fren, yaw dönüşü ve 10--18 s GPS outage verir. Sonuçlar sırasıyla 0.172/0.180/
|
||
0.389 m yatay RMSE ve outage sırasında 0.634/0.671/0.822 m tepe hatadır; üçünde
|
||
de GPS recovery kabul edilmiş, false ZUPT ve NIS reject sıfırdır. Tam GPS'siz
|
||
koşu da kendine konum feed etmeden yerel dead-reckoning yapar: global origin
|
||
false kalır, kovaryans büyür ve 25 s sonunda 3.674 m drift oluşur. Bu drift
|
||
gizlenmez; mutlak konumun IMU-only durumda gözlenememesinin beklenen sonucudur.
|
||
|
||
`gps_reacquisition_test.c`, canlı UART'ta görülen kötü ilk GPS fix'i senaryosunu
|
||
ENU'da 80/40/-170 m başlangıç ofsetiyle tekrarlar. Hard NIS kapısı tek başına
|
||
sonraki doğru fix'leri sürekli reddettiği için fusion engine zaman tabanlı bir
|
||
position reacquisition uygular: son başarılı position fusion üzerinden yedi
|
||
saniye timeout geçtikten ve en az üç rejected fix kendi içinde devamlı olduktan
|
||
sonra yalnız position state resetlenir. Hız, attitude ve IMU bias'ları korunur.
|
||
Test 100/200/1000 ms GPS periyotlarında sıfır son hata üretir; ayrı
|
||
150/-120/+80 m tek-fix testi aykırı ölçümün reddedildiğini ve state reset
|
||
oluşturmadığını doğrular.
|
||
|
||
Testin `--trace` seçeneği UART'a benzer `IMU ts=...`, `GPS ts=... arrival=...`
|
||
satırları üretir. Standart regression komutu:
|
||
|
||
```sh
|
||
make -C soc/software/fusion/tests test
|
||
```
|
||
|
||
`platform_scenario_matrix_test.c` ayrıca stationary/tilt/vibration, yaya,
|
||
trafik ışığında duran otomobil ve ani dönüşlü/yüksek ivmeli uçak profillerini;
|
||
200/500/1000 ms GNSS ile 19/20/200/300 ms IMU'nun 48 kombinasyonunda çalıştırır.
|
||
GNSS dört uydu kullanır, ilk bölümde 5--10 m, sonra 3--5 m sınıfı yatay gürültü,
|
||
3 saniye outage ve 2 saniye tutarlı büyük hata içerir. Kısa hata yedi saniyelik
|
||
recovery timeout'unu açamaz. 200/300 ms IMU yüksek dinamikteki doğruluk kaybıyla
|
||
birlikte açıkça raporlanır; test bunu daha sık IMU varmış gibi gizlemez.
|
||
|
||
```text
|
||
Offline model:
|
||
UART GPS + IMU logları -> Python parser -> fixed/adaptive ESKF -> CSV/grafik/harita
|
||
|
||
Ürün yolu:
|
||
GPS position + Doppler velocity --\
|
||
-> fusion_engine -> 15-state ESKF -> fused LLH/ENU
|
||
TDK veya ST IMU -> imu_sensor ----/
|
||
```
|
||
|
||
### Doppler ESKF'ye nasıl geliyor?
|
||
|
||
1. Tracking RTL her 20 ms NAV-bit epoch'unda carrier NCO Q7 değerini,
|
||
`ABS_SAMPLE`, remaining code phase ve 20 prompt'un I/Q/WBP toplamlarını
|
||
birlikte latch eder. Payload 20 ms sabit kalır; APB wrapper registered
|
||
synchronizer ve settle süresinden sonra atomik register bankı ile interrupt
|
||
üretir.
|
||
2. Firmware coherent mailbox okumasında sequence'i payload öncesi/sonrası
|
||
kontrol eder. Carrier değeri için
|
||
`doppler_hz = carrier_q7/128 - 4092000`, L1 pseudorange-rate için
|
||
`range_rate = -doppler_hz*c/1575420000` kullanılır.
|
||
3. Aynı PRN'in 50 Hz snapshot'larında C/N0 `alpha=0.2` ile yumuşatılır.
|
||
Doppler'in ham değeri ile `alpha=0.05` software-IIR değeri ayrı tutulur;
|
||
RTL hardware Doppler IIR içermez.
|
||
4. Ham Doppler, en az dört uyduyla C/N0-weighted velocity WLS
|
||
`[receiver_vx, receiver_vy, receiver_vz, receiver_clock_drift_mps]`
|
||
state'ini çözer. Her observation'dan satellite LOS velocity çıkarılır,
|
||
broadcast satellite clock drift eklenir. Inverse normal matrix ve post-fit
|
||
residual ECEF velocity covariance'ini üretir. En az altı kullanılabilir
|
||
uyduda `3.5 sigma` normalized-residual gate açılırsa bütün tek-kanal
|
||
leave-one-out adayları denenir ve en düşük weighted residual'lı aday ESKF
|
||
yolu için seçilir.
|
||
5. GPS adapter velocity ve 3x3 covariance'i ECEF'ten ENU'ya döndürür,
|
||
kart ölçümüne dayalı minimum `2/2/3 m/s` standard-deviation floor'larını
|
||
uygular ve position ile aynı capture timestamp'ini korur.
|
||
6. Fusion engine gecikmiş position ve velocity'yi aynı geçmiş epoch'unda
|
||
uygular. Velocity'nin ayrı 3-DOF `%99.9`, `NIS=16.266` kapısı vardır; bir
|
||
velocity reject aynı epoch'taki kabul edilmiş position update'ini bozmaz.
|
||
Sonra daha yeni IMU history current-time horizon'a kadar replay edilir.
|
||
|
||
Filtreli Doppler ikinci bir velocity WLS'e girer; bu sonuç fusion/ESKF'ye
|
||
yayınlanmaz. Yalnız PPS yazılım filtresinde position-WLS referans datumunun
|
||
clock-bias drift predictor'u ve PPS kalite metriği olarak kullanılır. PPS'in
|
||
ana ölçümü position WLS `clock_bias_m` değeridir. Doppler WLS'nin dördüncü
|
||
`receiver_clock_drift_mps` state'i PPS'e doğrudan verilmez; filtreli receiver
|
||
velocity ve referans uydu ephemeris hızıyla datum türevi ayrıca hesaplanır.
|
||
|
||
Klasik mutlak-pseudorange modelinde receiver clock bias
|
||
`c*delta_t_r`, Doppler clock drift ise bunun türevi
|
||
`c*d(delta_t_r)/dt`'dir. Doppler WLS carrier pseudorange-rate'ten
|
||
`[vx,vy,vz,receiver_clock_drift]` çözer. `0.1 ppm` receiver oscillator
|
||
error'i yaklaşık `29.98 m/s` ortak Doppler drift'idir; dördüncü state
|
||
çözülmezse bunun bir bölümü platform hızı sanılır.
|
||
|
||
Bu projedeki position WLS bias'i ise capture'lar ortak receiver zamanına göre
|
||
farklandığı ve `STARTOFFSET` eklendiği için saf receiver clock bias'i değil,
|
||
referans-uyduya bağlı göreli bir datumdur. Bu yüzden position
|
||
`clock_bias_m` ile Doppler `clock_drift_mps` arasında doğrudan türev kısıtı
|
||
kurulmaz. Doppler WLS ayrı bir normal equation kullanır fakat LOS vektörleri
|
||
için güncel position WLS receiver konumuna, uydu konum/hız/clock drift'i için
|
||
broadcast ephemerise bağlıdır.
|
||
|
||
Bu zincirin RTL/register ayrıntısı
|
||
`hardware/external/gps/rtl/trck_src/README.md`, bare-metal WLS ve kart
|
||
doğrulaması `soc/software/gps_system/README.md` içindedir.
|
||
|
||
Python tarafındaki giriş noktaları:
|
||
|
||
- `serial_capture.py`: UART akışını zaman damgalı CSV olarak toplar;
|
||
- `fusion_eskf.py`: GPS ve TDK/ST IMU kayıtlarını offline ESKF'de oynatır;
|
||
- `compare_eskf_models.py`: sürekli stationary kısıtlı model ile hareketi
|
||
algılayıp ZUPT'yi açıp kapatan adaptif modeli aynı veri üzerinde karşılaştırır;
|
||
- `map_player.py`: ham GPS ve düzeltilmiş ESKF noktalarını Linux masaüstü
|
||
penceresinde OpenStreetMap üzerinde zamana göre oynatır;
|
||
- `compare_firmware_logs.py` ve `synthetic_firmware_ab.py`: standalone GPS
|
||
firmware A/B ve sentetik WLS bütünlük analizlerini üretir.
|
||
|
||
Bare-metal ürün mimarisi sürücüden bağımsızdır. `imu_sensor` aktif TDK veya ST
|
||
backend'ini seçer, `imu_calibration` SI birimine ve ortak eksen takımına
|
||
dönüştürür, `fusion_engine` ise sensör markasını bilmeden motion detector ve
|
||
ESKF'yi çalıştırır. IMU ve GPS asenkrondur; ikisi de aynı monotonik CLINT/CPU
|
||
tick alanında ölçüm anında damgalanır. GPS WLS geç tamamlanırsa fixed-lag IMU
|
||
history replay ile position ve Doppler velocity update'leri atomik olarak
|
||
gerçek ölçüm epoch'unda uygulanır.
|
||
|
||
Doğrulama durumu:
|
||
|
||
- Linux/GCC sentetik hareket, stationary, ani ivmelenme/fren, dönüş, ZUPT,
|
||
position/velocity NIS rejection, gecikmiş aynı-epoch position+velocity
|
||
replay, ECEF->ENU velocity/covariance dönüşümü, covariance invariantları ve
|
||
ASan/UBSan testleri geçti. Ayrıntılı sonuçlar aşağıdadır.
|
||
- STEVAL-MKI217V1 üzerindeki LSM6DSOX'un SPI Mode-0 okuması, 60 saniyelik
|
||
stationary ham veri kaydı ve fiziksel INT1 yolu gerçek Genesys2 kartında
|
||
doğrulandı. 2026-07-16 canlı tekrarında 4084 interrupt'ın tamamı sample'a
|
||
dönüştü; read-fail, queue overflow, unexpected IRQ ve trap sayıları sıfırdı.
|
||
Ölçülen 105.789 Hz hız yapılandırılan 104 Hz ODR ile uyumluydu. Bu, tek
|
||
başına bütünleşik fusion doğrulaması değildir.
|
||
- PMOD asynchronous input -> 3FF synchronizer -> PLIC device 11 -> C ISR yolu
|
||
ASIC/Questa simülasyonunda geçti.
|
||
- Genesys2 fiziksel sensör interrupt girişi son tasarımda `JB1/V29`, GPS PPS
|
||
çıkışı `JC10/AK28`'dir. Eski `JC9/AK30` dokümantasyonu geçersizdir. STEVAL
|
||
`INT1 -> JB1 -> 3FF synchronizer -> PLIC 11 -> C ISR` yolu gerçek kartta
|
||
kesintisiz sample akışıyla doğrulandı.
|
||
- GPS + ST/TDK + ESKF'nin aynı gerçek firmware koşusunda hareketli platform
|
||
testi, Rocket `rdcycle` yük ölçümü, mounting dönüşümü ve sample-loss testi
|
||
henüz tamamlanmadı. Sentetik metre sonuçları gerçek saha accuracy iddiası
|
||
değildir.
|
||
|
||
Git devralma durumu: aktif branch `tdk_ekf`'dir. Çalışma ağacında GPS/nav-timer
|
||
kaynak değişiklikleri ile çok sayıda üretilmiş bitstream, object, simülasyon ve
|
||
log dosyası bulunabilir. Yeni oturum önce `git status`, `git diff` ve
|
||
`git log --oneline --decorate -5` ile tekrar kontrol etmeli; üretilmiş dosyaları
|
||
ayırmadan `git add -A` kullanmamalıdır.
|
||
|
||
Sonraki ana adımlar:
|
||
|
||
1. `gps_system` içinde ST veya TDK seçerek GPS + IMU + ESKF UART telemetry'sini
|
||
gerçek karttan toplamak; fused LLH/ENU, hız, motion state, NIS, GPS accept/
|
||
reject, IRQ/sample-loss ve queue sayaçlarını kaydetmek.
|
||
2. Stationary -> ani hareket -> sabit hız -> fren -> tekrar stationary testini
|
||
yapmak; hareket sırasında ZUPT'nin kapalı kaldığını doğrulamak.
|
||
3. Yeni Doppler-aided firmware'i kartta çalıştırıp `pos_nis`, `vel_nis` ve
|
||
`velocity=accepted/rejected` sayaçlarıyla position-only koşuya karşı A/B
|
||
kayıt almak.
|
||
4. PPS için aşağıdaki lock teşhisini tamamlamak.
|
||
|
||
Prototip montaj notu: STEVAL jumper kablolarıyla serbest durduğu için başlangıç
|
||
sensor yönü sabit kabul edilmemelidir. Her açılışta en az iki saniye stationary
|
||
gravity/bias başlangıcı yapılmalı; roll/pitch gravity'den bulunmalı ve başlangıç
|
||
yaw'ı ayrı bir mutlak gözlem yoksa keyfi referans olarak kalmalıdır. Sensör bir
|
||
fusion koşusu başladıktan sonra gövdeye göre yön değiştirirse bunu yalnız
|
||
accel/gyro ile araç hareketinden güvenilir biçimde ayırmak mümkün değildir;
|
||
hareketli test boyunca sensör geçici de olsa rijitlenmeli veya filtre yeniden
|
||
başlatılmalıdır.
|
||
|
||
### PPS çıkmıyor: lock problemi ve teşhis
|
||
|
||
Gözlenen belirti GPS konumunun UART'ta gelmesi fakat JC10'da PPS pulse
|
||
görülmemesidir. Bu henüz kesinleşmiş bir RTL hatası değildir. Mevcut PPS
|
||
tasarımı lock oluşmadan fiziksel çıkışı bilinçli olarak LOW tutar; dolayısıyla
|
||
konum çözülmesi tek başına PPS üretildiğini kanıtlamaz.
|
||
|
||
İlk kabul edilen WLS/PPS commit'i yalnız coarse alignment yapar. Ardından faz
|
||
hatası en fazla sekiz adet 125 MHz tracking-clock tick'i, yani 64 ns olan beş
|
||
ardışık PI update gerekir. RTL reset release eşiği 256 ns'dir; v2.2 production
|
||
software profile'ları tek seyrek WLS sıçraması pulse kaybettirmesin diye
|
||
release eşiğini runtime `LOOP_CONFIG` ile 1.024 us yapar. WLS receiver-clock
|
||
bias/pseudorange jitter'ı veya epoch capture belirsizliği beş ardışık ölçümde
|
||
64 ns acquire koşulunu bozarsa konum gelmeye devam ederken PPS pini LOW
|
||
kalabilir.
|
||
|
||
Firmware ancak WLS başarılı, `solution_valid=true`, PPS referans satırı FDE ile
|
||
dışlanmamış ve referans kanalın capture sequence'i sıfır değilse PPS mailbox'a
|
||
commit yapar. Bunlardan biri sağlanmazsa PPS daha coarse alignment'a bile
|
||
ulaşmaz.
|
||
|
||
Genesys2 post-route checkpoint kontrolünde `gps_pps` portunun `JC10/AK28`,
|
||
LVCMOS33 olarak yerleştiği, sabit 0/1'e bağlanmadığı ve PPS core
|
||
`pps_out_p_reg/Q` tarafından sürüldüğü doğrulandı. Canlı ayrım için çalışan
|
||
kartta CPU kısa süre durdurulmalı ve önce atomik diagnostic snapshot
|
||
istenmelidir. `ACTIVE_SEQUENCE`, faz/integrator/rate ve `PULSE_COUNT` aynı
|
||
donmuş snapshot grubundadır; `DIAG_SNAPSHOT` yazılmadan okunurlarsa core
|
||
çalışırken bile eski veya reset sıfırı görülebilir:
|
||
|
||
```gdb
|
||
monitor halt
|
||
x/wx 0x1002a07c
|
||
x/wx 0x1002a000
|
||
x/wx 0x1002a004
|
||
monitor mww 0x1002a078 1
|
||
monitor sleep 10
|
||
x/wx 0x1002a004
|
||
x/wx 0x1002a048
|
||
x/wx 0x1002a05c
|
||
x/wx 0x1002a060
|
||
x/wx 0x1002a074
|
||
monitor resume
|
||
```
|
||
|
||
| Register | Beklenen/yorum |
|
||
|---|---|
|
||
| `VERSION @ 0x1002a07c` | Production v2.2 için `0x00020200`; farklıysa ELF/bitstream eşleşmesini kontrol edin |
|
||
| `CONTROL @ 0x1002a000` | Enable + track açıkken alt bitler genellikle `0x3` |
|
||
| `STATUS @ 0x1002a004` | `0x1`: commit/alignment yok; alt bitler `0x7`: aligned fakat lock değil; bit 11 set ve alt bitler `0xf`: locked/valid |
|
||
| `ACTIVE_SEQUENCE @ 0x1002a048` | `0`: firmware hiç geçerli PPS commit'i yapmamış; artıyorsa WLS referansları PPS'ye ulaşıyor |
|
||
| `PULSE_COUNT @ 0x1002a074` | Artıyorsa RTL pulse üretiyor; sorun JC10/prob/GND tarafındadır |
|
||
|
||
Sağlıklı ve sticky hata biti olmayan tipik lock durumu `STATUS=0x0000080f`'tir.
|
||
`ACTIVE_SEQUENCE` artarken `STATUS` yaklaşık `0x7` kalıyorsa problem pin değil,
|
||
lock acquisition/faz jitter'ıdır. `STATUS` lock gösteriyor ve `PULSE_COUNT`
|
||
artıyorsa JC10 sinyali JC11 GND referansıyla osiloskop veya logic analyzer'da
|
||
ölçülmelidir; pulse saniyede bir yaklaşık 100 ms HIGH'dır.
|
||
|
||
Erken 2026-07-25 v2.1 canlı Genesys2 ölçümünde `VERSION=0x00020100`,
|
||
`CONTROL=0x00000003` ve snapshot `ACTIVE_SEQUENCE=11583` görüldü.
|
||
`PULSE_COUNT=314`, PPS core'un resetten beri 314 `pps_out` pulse olayı
|
||
oluşturduğunu kanıtladı; post-route top-level yol da sabit LOW değildir.
|
||
Bu iki kanıt pinin elektriksel seviyesi için prob ölçümünün yerini tutmaz.
|
||
Ölçüm anında lock yoktu. Debugger'ın uzun halt etkisi temizlenip sticky bayraklar
|
||
sıfırlandıktan sonra 50 saniye boyunca status hatasız `0x00000007`
|
||
(enabled/aligned/tracking, unlocked) kaldı; pulse count artmadı. Üç ayrı
|
||
snapshot faz hatası yaklaşık `+1.95 us`, `+1.35 us` ve `-0.58 us` verdi.
|
||
Bunların tamamı beş ardışık update için gereken `+/-64 ns` acquire
|
||
penceresinden büyüktür.
|
||
|
||
Aynı koşudaki beş uydulu çözümlerde `GDOP` yaklaşık 17 ve `TDOP` yaklaşık
|
||
10.5'ti; ham GPS konum/irtifa da onlarca-yüzlerce metre oynuyordu. Bu zayıf
|
||
geometri ve WLS clock-bias gürültüsü, ölçülen mikrosaniye seviyesindeki PPS
|
||
faz oynaklığıyla uyumludur. Dolayısıyla mevcut kart bulgusu bir pin veya
|
||
APB/CDC kopukluğundan çok timing-observation kalite/lock-gating problemine
|
||
işaret eder. Eşik ölçümsüz büyütülmemeli; önce clock-bias/TDOP kalite kapısı,
|
||
outlier reddi veya faz gözlemi süzme stratejisi board A/B testiyle
|
||
değerlendirilmelidir.
|
||
|
||
Bu tarihsel v2.1 teşhisinden sonra v2.2 dinamik PI profilleri, Doppler
|
||
clock-drift prediction, bounded WLS clock-bias filtresi, 2 s validity
|
||
watchdog/30 s state koruma politikası ve fractional capture correction
|
||
eklenmiştir. Güncel sentetik ve kart sonuçları
|
||
`soc/software/gps_system/README.md` altındaki PPS bölümlerinde, register/RTL
|
||
davranışı `hardware/external/gps/rtl/pps/README.md` içinde tutulur.
|
||
|
||
## Ç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.
|
||
|
||
## Bare-metal C ESKF ve Linux doğrulaması (2026-07-13)
|
||
|
||
> **Doğrulama durumu:** Bu ESKF/TDK entegrasyonu henüz real hardware üzerinde
|
||
> çalıştırılmadı. Kart test sırasında bağlı değildi. Aşağıdaki hareket,
|
||
> stationary, accuracy, outlier-rejection ve performans sonuçları Linux/GCC
|
||
> ortamında üretim bare-metal C kaynaklarıyla yapılan sentetik testlere aittir.
|
||
> Bunlar algoritma/regression doğrulamasıdır; gerçek sensör eksenleri, SPI/INT1,
|
||
> IRQ/sample kaybı, 50 MHz Rocket deadline'ı veya gerçek saha GPS doğruluğu için
|
||
> donanım kanıtı değildir.
|
||
|
||
Python modelinden bağımsız olarak aynı algoritma artık `gps_system` içinde
|
||
freestanding C ile çalışır. Algoritma katmanı Linux testinde de kartta da aynı
|
||
kaynaklardan derlenir; Linux için ayrı veya sadeleştirilmiş bir ESKF kopyası
|
||
yoktur.
|
||
|
||
Temel parçalar:
|
||
|
||
- `gps_system/src/fusion/eskf.c`: ENU konum/hız, body-to-ENU quaternion, accel bias,
|
||
gyro bias ve 15x15 covariance içeren 15-hata-durumlu ESKF;
|
||
- `gps_system/src/fusion/fusion_motion.c`: bootstrap/stationary/moving/candidate
|
||
durum makinesi, filtrelenmiş jerk ve ZUPT izni;
|
||
- `gps_system/src/fusion/fusion_engine.c`: başlangıç kalibrasyonu, asenkron IMU/GPS,
|
||
NIS kapısı ve gecikmiş GPS için fixed-lag IMU replay;
|
||
- `gps_system/src/fusion/fusion_gps_adapter.c`: WGS-84 LLH/ECEF/ENU dönüşümü ve
|
||
covariance tabanı;
|
||
- `gps_system/src/drivers/imu/tdk_icm42688.c`: ICM-42688-P SPI/INT1 sürücüsü;
|
||
- `gps_system/src/fusion/navigation_fusion.c`: GPS ve IMU kuyruklarını algoritmaya
|
||
bağlayan üst koordinatör.
|
||
|
||
### ESKF state ve matematik sınırı
|
||
|
||
Nominal state aşağıdaki bileşenlerden oluşur:
|
||
|
||
```text
|
||
x = [p_ENU(3), v_ENU(3), q_body_to_ENU(4), b_accel(3), b_gyro(3)]
|
||
```
|
||
|
||
Covariance içinde quaternion'ın dört elemanı doğrudan tutulmaz. Sağ-taraflı
|
||
küçük açı hatası kullanılarak hata state'i 15 boyutta kalır:
|
||
|
||
```text
|
||
delta_x = [delta_p(3), delta_v(3), delta_theta(3),
|
||
delta_b_accel(3), delta_b_gyro(3)]
|
||
```
|
||
|
||
IMU propagation'da ölçülen specific force ve angular rate'ten bias çıkarılır.
|
||
Quaternion body frame'den ENU frame'e dönüşümü temsil eder. ENU lineer ivmesi
|
||
`R(q) * (accel - b_accel) - [0, 0, g]` ile, quaternion ise gyro exponential
|
||
map ile ilerletilir. Büyük `dt` değerleri en fazla 20 ms'lik alt adımlara
|
||
bölünür. Covariance birinci dereceden error-state transition ve IMU/bias
|
||
process noise ile ilerletilir; her işlemden sonra simetrikleştirilir ve
|
||
diagonal tabanı uygulanır.
|
||
|
||
GPS konum residual'ı `r = z_ENU - p_ENU`, innovation covariance'i
|
||
`S = P_pp + R_GPS` olarak hesaplanır. `NIS = r^T S^-1 r` değeri 3 DOF için
|
||
`16.266236` (%99.9) kapısını aşarsa ölçüm state'e dokunmadan reddedilir.
|
||
Kabul edilen update Joseph covariance formunu, quaternion error injection'ı
|
||
ve attitude reset Jacobian'ını kullanır.
|
||
|
||
Default ESKF process/başlangıç değerleri:
|
||
|
||
| Parametre | Default |
|
||
|---|---:|
|
||
| Accel noise density | 0.03 m/s2/sqrt(Hz), her eksen |
|
||
| Gyro noise density | 0.003 rad/s/sqrt(Hz), her eksen |
|
||
| Accel bias random walk | 0.002 m/s2/sqrt(s) |
|
||
| Gyro bias random walk | 0.002 deg/s/sqrt(s) |
|
||
| İlk yatay/düşey konum sigma | 10 m / 20 m |
|
||
| İlk hız sigma | 1 m/s |
|
||
| İlk roll-pitch/yaw sigma | 5 deg / 30 deg |
|
||
| Gravity | 9.80665 m/s2 |
|
||
| Maksimum propagation alt adımı | 20 ms |
|
||
| Konum NIS kapısı | 16.266236, 3 DOF %99.9 |
|
||
|
||
### Innovation rejection, recovery ve katman siniri (2026-07-16)
|
||
|
||
Standart ESKF position update'i tek basina buyuk ve kalici bir baslangic
|
||
ofsetini duzeltemez. GPS--INS residual'i NIS kapisini astiginda olcum state'e
|
||
hic uygulanmaz; state GPS'e yaklasmadigi icin sonraki dogru GPS fix'leri de
|
||
ayni nedenle sonsuza kadar reddedilebilir. NIS yalniz iki bilgi kaynaginin
|
||
tutarsiz oldugunu soyler. GPS'in mi hatali, yoksa ataletsel cozumun mu yanlis
|
||
ankrajlandigini matematiksel update tek basina belirleyemez.
|
||
|
||
Bu nedenle sorumluluk iki katmana ayrilir:
|
||
|
||
- `eskf.c` innovation, innovation covariance, NIS gate, kabul edilmis Kalman
|
||
correction ve covariance bakimindan dogru position-reset primitive'ini
|
||
icerir. Rejected olcumu gizlice correction'a sokmaz ve NIS'i bypass etmez.
|
||
- `fusion_engine.c` sensor gecmisi ve zaman bilgisine sahip supervisor'dur.
|
||
Ardisik rejected GNSS fix'lerinin kendi aralarinda zamansal olarak tutarli
|
||
olup olmadigini izler ve gerekli recovery/reset kararini burada verir.
|
||
|
||
Mevcut yalın recovery, son başarılı position fusion'dan sonra yedi saniyelik
|
||
timeout dolmuşsa, platform harici rest bilgisi ve IMU/GNSS hareket vetolarıyla
|
||
duragansa ve en az üç rejected position fix'i kendi arasında zamansal
|
||
tutarlıysa yalnız position state ve position covariance'ini GNSS'e yeniden
|
||
ankrajlar. Position cross-covariance'lari gecersiz korelasyon tasimamasi icin
|
||
sifirlanir; velocity, attitude ve IMU bias state'leri korunur. Hard NIS gate
|
||
aktif kalir ve tek aykiri olcum reset uretemez. Bu bir innovation-bypass
|
||
workaround'u degil, kontrollu state recovery mekanizmasidir.
|
||
|
||
PX4 EKF2 de ayni temel ayrimi yapar. Generic `fuseHorizontalPosition()` yalniz
|
||
innovation testinden gecen olcumu fuse eder. GNSS'e baslama, quality check,
|
||
`time_last_fuse` timeout'u, state reset, fusion stop ve sensor-fault kararlari
|
||
ayri GNSS control akisindadir. Otomatik modda baska yatay konum kaynagi yoksa
|
||
uzun fusion timeout'undan sonra GNSS'e reset yapilabilir; alternatif aiding
|
||
varsa veya dead-reckoning politikasinda GNSS durdurulabilir/fault kabul
|
||
edilebilir. Kaynaklar:
|
||
|
||
- <https://github.com/PX4/PX4-Autopilot/blob/main/src/modules/ekf2/EKF/aid_sources/gnss/gps_control.cpp>
|
||
- <https://github.com/PX4/PX4-Autopilot/blob/main/src/modules/ekf2/EKF/position_fusion.cpp>
|
||
- <https://docs.px4.io/main/en/advanced_config/tuning_the_ecl_ekf>
|
||
|
||
Mevcut recovery PX4'teki aiding yoneticisinin sade bare-metal karsiligidir;
|
||
nihai mimari hedefi asagidaki acik GNSS aiding durum makinesidir:
|
||
|
||
```text
|
||
DISABLED -> STARTING -> FUSING -> FAULTED/RECOVERING
|
||
```
|
||
|
||
Karar yalniz rejected-candidate suresine degil son basarili position fusion
|
||
zamanina baglanmalidir. Uydu sayisi, finite covariance, DOP, WLS integrity ve
|
||
alternatif aiding kaynaklari birlikte degerlendirilmelidir. Tam dort uyduda
|
||
WLS residual redundancy/chi-square DOF bulunmadigi icin temporal consistency
|
||
daha onemlidir. Doppler velocity artik ayri 3-DOF innovation/NIS kapisiyla
|
||
fuse edilir; bir velocity reject'i ayni epoch'taki position sonucunu bozmaz.
|
||
Henuz ayri bir velocity fusion-timeout/state-reset politikasi yoktur. Yatay
|
||
position ve height da barometre gibi ek kaynaklar geldiginde birbirinden
|
||
bagimsiz yonetilmelidir.
|
||
|
||
Baslangic GNSS'i icin mutlak bir dogruluk referansi yoksa tutarli fakat yanlis
|
||
bir GNSS kumesini otomatik olarak gercek konumdan ayirmak temel olarak mumkun
|
||
degildir. Kisa bir stable-fix/startup-quality penceresi riski azaltir, fakat
|
||
spoofing veya tutarli multipath'e karsi tek basina kanit degildir.
|
||
|
||
### Asenkron veri akışı ve timestamp
|
||
|
||
IMU ve GPS aynı local monotonic CPU/CLINT tick alanında timestamp edilir.
|
||
Filtre `dt` hesabında GPS week/TOW kullanmaz. GPS ölçümü WLS'nin bittiği anda
|
||
değil, ölçüm epoch interrupt'ında alınan local tick ile filtreye girer. WLS
|
||
geç geldiyse engine son GPS checkpoint'ine dönüp IMU geçmişini gerçek ölçüm
|
||
anına kadar oynatır, GPS update'i uygular ve bugüne kadar tekrar ilerler.
|
||
|
||
Akışın ayrıntısı:
|
||
|
||
1. TDK INT1 ISR'a girildiğinde `BSP_CLINT_MTIME` hemen okunur.
|
||
2. ISR sensörün 14-byte register burst'ünü alır ve yalnız raw integer değerleri
|
||
256-elemanlı SPSC kuyruğa koyar; ISR içinde floating-point ESKF hesabı yoktur.
|
||
3. Foreground raw accel/gyro/temp değerlerini SI birimlerine çevirir ve aynı
|
||
local timestamp ile fusion engine'e verir.
|
||
4. Her uydu nav-solve event'i yakalandığında local tick event kaydına eklenir.
|
||
Coherent WLS epoch'u için geçerli uydu timestamp'lerinin medyanı seçilir.
|
||
5. WLS daha sonra tamamlansa bile GPS mesajı bu ölçüm-epoch timestamp'ini taşır.
|
||
6. Foreground önce bekleyen IMU'ları, sonra GPS kuyruğunu tüketir. Gecikmiş GPS
|
||
son checkpoint'ten kendi timestamp'ine kadar IMU replay edilerek uygulanır;
|
||
kalan IMU geçmişi tekrar oynatılarak current state yeniden oluşturulur.
|
||
|
||
IMU history kapasitesi 2048 örnektir; 500 Hz'de yaklaşık 4.096 s fixed-lag
|
||
alanı sağlar. History dolarsa en eski IMU sessizce zaman aralığı kaybettirilerek
|
||
atılmaz: checkpoint önce o örnekle ilerletilir, sonra ring buffer'dan çıkarılır.
|
||
Gelecek timestamp'li GPS için sekiz-elemanlı sıralı pending queue bulunur;
|
||
checkpoint'ten eski ölçüm stale olarak reddedilir.
|
||
|
||
GPS week/TOW uydu zamanı çözümü ve kanal coherence kontrolü için gereklidir,
|
||
ancak ESKF `dt` kaynağı değildir. Bu ayrım WLS computation latency'sinin IMU
|
||
zaman eksenini bozmasını önler.
|
||
|
||
### Başlangıç kalibrasyonu, hareket kararı ve zero update
|
||
|
||
Engine açılışta doğrudan RUNNING olmaz. Default olarak en az 2 s ve en az 50
|
||
quiet IMU örneği ister. Tek örnekte gravity norm hatası 0.30 m/s2'yi veya gyro
|
||
normu 2 deg/s'yi aşarsa pencere sıfırlanır. Pencere sonunda her eksende accel
|
||
standard deviation 0.12 m/s2, gyro standard deviation 0.15 deg/s altında
|
||
olmalıdır. Gravity ortalaması roll/pitch'i, gyro ortalaması ilk gyro bias'ını
|
||
verir. Yaw gravity ile gözlenemediği için başlangıçta sıfır referanslı kalır.
|
||
Benzer şekilde stationary IMU ile yatay accel bias ve küçük tilt tamamen
|
||
ayrılamaz; sonraki GPS/kinematik update'ler bu error-state'leri düzeltir.
|
||
|
||
IMU motion-state eşikleri tanılama için tutulur, fakat ZUPT yetkisini tek başına
|
||
vermez. PX4 ayrımına uygun olarak `fusion_rest_detector` titreşim metriklerini
|
||
izler ve dışarıdan gelen `platform_landed` kapısıyla birleşir. Prototipin unarmed
|
||
bench modu landed=true başlar; gerçek araç kontrolü bu değeri kendi state'inden
|
||
güncellemelidir. Sessiz IMU, landed=false iken sabit hızlı hareketi stationary
|
||
ilan edemez.
|
||
|
||
Motion-state default eşikleri:
|
||
|
||
| Karar parametresi | Değer |
|
||
|---|---:|
|
||
| Stationary lineer ivme üst sınırı | 0.15 m/s2 |
|
||
| Stationary gyro üst sınırı | 1 deg/s |
|
||
| Güçlü hareket accel eşiği | 0.40 m/s2 |
|
||
| Güçlü hareket gyro eşiği | 3 deg/s |
|
||
| Güçlü hareket jerk eşiği | 4 m/s3 |
|
||
| Jerk düşük-geçiren zaman sabiti | 100 ms |
|
||
| Stationary hız kapısı | 0.40 m/s |
|
||
| Moving hız kapısı | 0.50 m/s |
|
||
| Stationary'e dönüş quiet dwell | 1.0 s |
|
||
| Zayıf hareket doğrulaması | 3 ardışık IMU örneği |
|
||
|
||
Güçlü accel/gyro/jerk veya yüksek ESKF hızı motion tanılamasını tek örnekte
|
||
moving'e çıkarabilir. ZUPT ve zero-gyro ise yalnız ardışık iki timestamp'li
|
||
örnekte dış supervisor `vehicle_at_rest=true` verdiğinde 200 ms periyotla
|
||
uygulanır. ZUPT velocity sigma 0.20 m/s'dir. Zero-gyro aynı 200 ms penceredeki
|
||
delta-angle toplamından ortalama açısal hız üretir; tek bir örneği bias diye
|
||
kabul etmez. Bu politika PX4 EKF2 `ZeroVelocityUpdate`/`ZeroGyroUpdate` ve land
|
||
detector katman ayrımının bare-metal karşılığıdır.
|
||
|
||
Kaynaklar:
|
||
|
||
- <https://github.com/PX4/PX4-Autopilot/blob/main/src/modules/ekf2/EKF/aid_sources/ZeroVelocityUpdate.cpp>
|
||
- <https://github.com/PX4/PX4-Autopilot/blob/main/src/modules/ekf2/EKF/aid_sources/ZeroGyroUpdate.cpp>
|
||
- <https://github.com/PX4/PX4-Autopilot/blob/main/src/modules/land_detector/LandDetector.cpp>
|
||
- <https://github.com/PX4/PX4-Autopilot/blob/main/src/modules/sensors/vehicle_imu/VehicleIMU.cpp>
|
||
|
||
GPS motion evidence, ardışık kabul edilmiş ENU konumları arasındaki yatay
|
||
displacement için 2 DOF `9.21034` (%99) NIS ve en az 0.50 m/s hız ister. Moving
|
||
kararı iki doğrulama ister. Bu metrik GPS position update NIS'inden ayrıdır;
|
||
biri hareket-state veto'su, diğeri ölçüm kabul/reject kapısıdır.
|
||
|
||
GPS adapter ilk valid çözümü ENU origin yapar. WLS covariance yatayda en az
|
||
0.50 m, düşeyde en az 1.00 m sigma ile sınırlandırılır; korelasyonlar clamp
|
||
edilir ve covariance positive-definite değilse ESKF'ye ulaşmadan reddedilir.
|
||
|
||
### WLS çıktısı ESKF'ye nasıl besleniyor?
|
||
|
||
WLS çıktısı ESKF'ye gerçekten beslenmektedir. ESKF yalnız IMU ile serbest INS
|
||
çalıştırmıyor; her valid GPS epoch'unda WLS konumu ve WLS measurement
|
||
covariance'i ile position update yapıyor. Tam veri yolu şöyledir:
|
||
|
||
```text
|
||
Uydu pseudorange ölçümleri
|
||
|
|
||
v
|
||
GPS WLS: konum + ENU covariance + residual/chi-square + validity
|
||
|
|
||
v
|
||
gps_fusion_publisher: ortak local CPU timestamp'li GPS mesajı
|
||
|
|
||
v
|
||
GPS adapter: LLH -> local ENU, covariance sanitize/floor
|
||
|
|
||
v
|
||
ESKF: GPS position innovation + NIS + Kalman update
|
||
```
|
||
|
||
WLS--ESKF sınırındaki alanlar:
|
||
|
||
| WLS çıktısı | ESKF tarafındaki mevcut kullanım |
|
||
|---|---|
|
||
| Latitude/longitude/height | ENU position measurement'a çevrilip update'te kullanılır |
|
||
| 3x3 ENU covariance | GPS measurement covariance `R_GPS` olarak kullanılır |
|
||
| `solution_valid` | False ise GPS update yapılmaz |
|
||
| Measurement local timestamp | GPS update fixed-lag replay ile doğru epoch'ta uygulanır |
|
||
| `chi_square_ratio` | Mesajda taşınır ve source-quality üretilir; Kalman gain'i şu an sürekli ölçeklemez |
|
||
| `hAcc/vAcc` | Mesajda taşınır; ESKF ayrı scalar olarak değil tam 3x3 covariance'i kullanır |
|
||
| Residual RMS | Mesajda taşınır fakat ESKF update denkleminde şu an doğrudan kullanılmaz |
|
||
| Uydu başına post-fit residual | ESKF'ye tek tek gönderilmez; WLS integrity/FDE katmanında kalır |
|
||
|
||
Burada iki farklı residual karıştırılmamalıdır:
|
||
|
||
1. **WLS post-fit pseudorange residual'ı:** Her uydu için ölçülen pseudorange
|
||
ile çözülen geometri/clock modelinin farkıdır. WLS bu residual'lardan
|
||
`sum(weight_i * residual_i^2)`, DOF ve chi-square üretir. Chi-square fail
|
||
olursa `solution_valid=false` olur ve ölçüm ESKF tarafından kullanılmaz.
|
||
2. **ESKF GPS--INS innovation residual'ı:** WLS'nin ürettiği ENU konum ile
|
||
ESKF'nin IMU propagation sonucu tahmin ettiği ENU konumun farkıdır:
|
||
|
||
```text
|
||
r_ESKF = p_WLS_ENU - p_INS_ENU
|
||
S = P_ESKF_position + R_GPS_WLS
|
||
NIS = r_ESKF^T * S^-1 * r_ESKF
|
||
```
|
||
|
||
ESKF bu NIS değeri 3 DOF %99.9 kapısını aşarsa upstream WLS valid olsa bile
|
||
GPS ölçümünü ikinci kez reddeder.
|
||
|
||
Dolayısıyla iki covariance birbirinden farklıdır:
|
||
|
||
- `P_ESKF`, IMU/INS error-state covariance'idir. IMU noise, gyro/accel bias
|
||
random walk, attitude, geçen `dt` ve önceki update'lerle ESKF içinde
|
||
propagation edilir.
|
||
- `R_GPS`, WLS position measurement covariance'idir. Şu anda
|
||
`(A^T * W_absolute * A)^-1` ile uydu geometrisi ve absolute measurement
|
||
weight'lerinden hesaplanıp ENU'ya çevrilir.
|
||
|
||
WLS post-fit residual büyüklüğü mevcut kodda `R_GPS`'yi sürekli/adaptif olarak
|
||
şişirmez. Residual'ın mevcut doğrudan etkisi hard validity/chi-square kapısıdır;
|
||
accepted bir ölçümün Kalman ağırlığı esas olarak `P_ESKF` ve WLS'den gelen
|
||
`R_GPS` ile belirlenir. İleride absolute uydu sigma modeli gerçek loglarla
|
||
kalibre edildikten sonra reduced chi-square tabanlı, sınırlandırılmış bir
|
||
covariance inflation eklenebilir. Bunun için threshold'a bölünmüş mevcut
|
||
`chi_square_ratio` yerine istatistiksel ölçek olarak
|
||
`weighted_residual_sum / DOF` kullanılmalıdır.
|
||
|
||
Hareket kararıyla ilgili iki koruma sentetik test sonucunda eklendi:
|
||
|
||
- 200--500 Hz ham örnek farkı doğrudan jerk sayılmıyor; 100 ms zaman sabitli
|
||
düşük-geçiren ivmeden jerk üretiliyor. Böylece stationary IMU noise yanlış
|
||
hareket kararı üretmiyor, 1 m/s2 ani ivme yine ilk örnekte algılanıyor.
|
||
- Position-only GPS'in tek/iki gürültülü noktadan çıkardığı `still` kararı,
|
||
yüksek ESKF hızını ezip ZUPT başlatamıyor. GPS `moving` ek veto olarak
|
||
kullanılıyor; stationary hız kapısı 0.40 m/s, moving kapısı 0.50 m/s ile
|
||
histerezisli. Doppler velocity artık ESKF hız state'ini düzeltir, fakat kart
|
||
verisindeki birkaç m/s stationary saçılım nedeniyle doğrudan rest/ZUPT
|
||
kararı olarak kullanılmaz. İleride covariance/NIS'e bağlı çoklu-confirmation
|
||
stop evidence ayrı olarak eklenebilir.
|
||
|
||
Linux/GCC testlerini çalıştırma:
|
||
|
||
```sh
|
||
cd soc/software/fusion/tests
|
||
make clean
|
||
make test
|
||
make sanitize
|
||
make profile
|
||
```
|
||
|
||
`fusion_synthetic_test.c`, üretim kaynaklarıyla şu durumları birlikte sınar:
|
||
|
||
- bias ve noise içeren stationary başlangıç kalibrasyonu;
|
||
- 100/200/500 Hz ve düzensiz local-tick IMU aralıkları;
|
||
- ani ivmelenme, sabit hız, ani fren, 90 derece yaw ve tekrar hareket;
|
||
- 0.8--1.2 s değişken GPS periodu ve 180--350 ms teslim gecikmesi;
|
||
- fixed-lag replay, covariance simetrisi/PSD ve uzun IMU geçmişi;
|
||
- iki adet yaklaşık 200 m sınıfı multipath/outlier ve NIS rejection;
|
||
- sekiz ayrı deterministic noise/timing seed'i;
|
||
- 30 s boyunca 500 Hz stationary IMU ve gecikmiş 1 Hz GPS.
|
||
|
||
`gps_failure_scenario_test.c`, gerçek `gps_live_5min_20260713.csv` kaydındaki
|
||
3.297 Hz ölçüm hızı, 300 ms medyan periyot, 1.803 s maksimum boşluk ve yaklaşık
|
||
8.6 m yatay RMS saçılım ölçeğini kullanır. Normal akışın yanında hareket
|
||
sırasında 12 s tam kesinti, yüzde 35 rastgele kayıp ve 1.8 s boşluklar, gecikmiş
|
||
ölçümlerin toplu dönüşü ve kesinti sonrasında tutarlı fakat 80/-50/30 m hatalı
|
||
üç fix senaryoları regression testidir.
|
||
|
||
### Sentetik hareketli senaryo
|
||
|
||
Hareketli senaryo 200 Hz IMU ile 60 s sürer. Ground-truth profil şöyledir:
|
||
|
||
| Zaman | Ground truth hareket |
|
||
|---|---|
|
||
| 0--5 s | Stationary; ilk 2 s calibration alanı |
|
||
| 5--7 s | East yönünde +1.0 m/s2 ani ivmelenme |
|
||
| 7--10 s | East yönünde 2.0 m/s sabit hız |
|
||
| 10--12 s | East yönünde -1.0 m/s2 fren, tam duruş |
|
||
| 12--15 s | Stationary |
|
||
| 15--17 s | Yerinde +45 deg/s yaw, toplam 90 deg dönüş |
|
||
| 17--19 s | North yönünde +0.8 m/s2 ivmelenme |
|
||
| 19--22 s | North yönünde 1.6 m/s sabit hız |
|
||
| 22--24 s | North yönünde -0.8 m/s2 fren, tam duruş |
|
||
| 24--60 s | Stationary |
|
||
|
||
Truth son konumu `[east=10 m, north=8 m, up=0 m]` ve son hızı sıfırdır.
|
||
Body-frame specific force, truth yaw ile ENU ivmesinin ters rotasyonundan
|
||
üretilir; dolayısıyla 90 derece dönüşten sonraki North ivmesi body X eksenine
|
||
doğru düşer ve attitude propagation da test edilir.
|
||
|
||
Sentetik sensör modeli:
|
||
|
||
| Girdi | Bias / noise |
|
||
|---|---|
|
||
| Accel bias | `[+0.030, -0.025, +0.060]` m/s2 |
|
||
| Gyro bias | `[+0.0010, -0.0007, +0.0009]` rad/s |
|
||
| Accel sample noise | Gaussian, 0.025 m/s2 sigma |
|
||
| Gyro sample noise | Gaussian, 0.0008 rad/s sigma |
|
||
| GPS yatay/düşey noise | 1.2 m / 2.0 m sigma |
|
||
| GPS measurement periodu | 0.8--1.2 s deterministic-random |
|
||
| WLS/teslim gecikmesi | 180--350 ms |
|
||
| GPS outlier | İki epoch'ta `[+150, -120, +80]` m; yaklaşık 208 m 3B |
|
||
|
||
Outlier GPS mesajları source-valid bırakılır; böylece sadece upstream validity
|
||
değil ESKF'nin kendi NIS kapısı gerçekten sınanır. Her GPS farklı gecikmeyle
|
||
geldiği için current state'e doğrudan uygulanamaz ve fixed-lag replay yolu her
|
||
update'te çalışır. Sekiz seed IMU noise, GPS noise ve GPS period/delay dizisini
|
||
değiştirir; aynı seed her çalıştırmada aynı sonucu vererek regression testini
|
||
deterministic tutar.
|
||
|
||
### Sentetik stationary senaryo
|
||
|
||
İkinci uçtan uca senaryo 30 s boyunca 500 Hz IMU ve 1 Hz GPS kullanır. GPS
|
||
250 ms gecikmeli gelir; yatay/düşey sigma 0.8/1.5 m'dir. Accel bias
|
||
`[+0.020, -0.015, +0.050]` m/s2, gyro bias
|
||
`[+0.0008, -0.0005, +0.0006]` rad/s; sample noise sırasıyla 0.020 m/s2 ve
|
||
0.0006 rad/s'dir. Testin amacı yalnız position error değil, yüksek IMU rate'te
|
||
ham sample-to-sample noise'un jerk üzerinden sahte `MOVING` üretmediğini ve
|
||
20 Hz ZUPT'nin rate'ten bağımsız kaldığını göstermektir.
|
||
|
||
### Unit-level ve invariant kontrolleri
|
||
|
||
`eskf_motion_test.c` aşağıdaki kontrolleri ayrıca tek tek yapar:
|
||
|
||
- düz ve tilt edilmiş stationary gravity propagation;
|
||
- normal GPS NIS accept ve büyük outlier reject; reject sonrası state'in
|
||
bit seviyesine yakın değişmemesi;
|
||
- Doppler velocity NIS accept/reject; `2/2/3 m/s` konservatif covariance ile
|
||
5 Hz velocity aiding'in sentetik `0.05 m/s2` accel-bias hız sürüklenmesini
|
||
en az `4x` azaltması;
|
||
- ani hızlanma/fren, sabit hız sırasında stationary veto ve quiet dwell;
|
||
- stationary 500 Hz IMU noise altında false-motion olmaması;
|
||
- 100/200/500 Hz ve 3--17 ms düzensiz local-tick `dt` dizileri;
|
||
- 300 ms gecikmiş aynı-epoch position+velocity replay sonucunun on-time filtre
|
||
ile position, velocity,
|
||
quaternion, bias, 15x15 covariance ve motion state'te `1e-11` toleransta
|
||
aynı olması;
|
||
- future GPS pending, checkpoint'ten eski GPS stale reject;
|
||
- GPS kesintisinde 2048-history rollover ve checkpoint'in zaman kaybetmeden
|
||
ilerlemesi;
|
||
- LLH--ECEF--ENU round-trip, ECEF velocity/covariance rotasyonu ve covariance
|
||
floor/PD kontrolü;
|
||
- IMU/GPS SPSC queue FIFO sırası ve overflow sayaçları.
|
||
|
||
Uçtan uca acceptance limitleri test kodunun içinde sabittir: hareketli yatay
|
||
RMSE `<2.0 m`, düşey RMSE `<2.5 m`, son yatay/düşey hata `<1.5/2.0 m`, son
|
||
hız `<0.05 m/s`, constant-velocity false-stationary örneği sıfır, bütün
|
||
outlier'lar reject ve covariance PSD olmalıdır. Stationary 500 Hz koşusunda
|
||
son yatay/düşey hata `<1/1 m`, son hız `<0.02 m/s` ve false-moving örneği
|
||
sıfır olmalıdır. Bunlar gerçek dünya accuracy garantisi değil, regression
|
||
fail sınırlarıdır.
|
||
|
||
Son Linux/GCC `-O2` sonuçları:
|
||
|
||
| Sentetik koşu | Sonuç |
|
||
|---|---:|
|
||
| 60 s hareketli yatay/düşey RMSE | 0.925 m / 0.427 m |
|
||
| 60 s son yatay/düşey hata | 0.306 m / 0.110 m |
|
||
| Moving algılama | 5.005 s, hareket başlangıcından 1 IMU örneği |
|
||
| Son duruşu stationary tanıma | 27.505 s, gerçek duruş 24.000 s |
|
||
| GPS accept/reject | 56 / 2 |
|
||
| Enjekte edilen/reddedilen outlier | 2 / 2 |
|
||
| Reddedilen GPS'in state sıçraması | 0.0 m |
|
||
| Sekiz seed en kötü yatay RMSE | 0.959 m |
|
||
| 30 s / 500 Hz stationary yanlış-moving örneği | 0 |
|
||
| 30 s / 500 Hz son hız | 0.0002 m/s |
|
||
|
||
Baseline hareketli koşuda 58 delayed GPS update için 14,508 IMU örneği replay
|
||
edildi; 56 GPS kabul, iki sentetik outlier reject edildi. Toplam 749 rate-limitli
|
||
zero update uygulandı. Stationary 500 Hz koşusunda 27 GPS kabul edildi, 560
|
||
zero update uygulandı. Final covariance Cholesky tabanlı PSD kontrolünü geçti
|
||
ve maksimum symmetry error test çözünürlüğünde sıfırdı.
|
||
|
||
### Sentetik testin ortaya çıkardığı iki hata
|
||
|
||
İlk sürümde jerk doğrudan iki ham accel örneğinin farkının `dt`'ye bölünmesiyle
|
||
üretiliyordu. 500 Hz'de küçük sample noise bile 4 m/s3 eşiğini sık geçebildiği
|
||
için stationary kartın motion state'i chatter edebilirdi. Jerk için 100 ms
|
||
low-pass state eklenince 10 s/500 Hz detector testi ve 30 s/500 Hz uçtan uca
|
||
test sıfır false-moving ile geçti; 1 m/s2 step yine ilk örnekte moving yaptı.
|
||
|
||
İkinci ara sürüm, iki position-only GPS örneğinin `STILL` kararına ESKF hızını
|
||
ezme yetkisi veriyordu. 1.2 m GPS sigma ile 2 m/s sabit hareketin tek-epoch
|
||
displacement'i her zaman istatistiksel olarak güçlü değildir. Bazı seed'lerde
|
||
yanlış stationary kararı ZUPT'yi gerçek hareket sırasında açtı; sekiz-seed
|
||
testinde yatay RMSE 480 m ve son hata 1 km üzerini görerek regression'ı
|
||
yakaladı. Kalıcı düzeltmede GPS-still yüksek ESKF hızını artık geçersiz
|
||
kılamaz; GPS-moving yalnız ek veto olur. Düzeltme sonrası sekiz seed'in en kötü
|
||
yatay RMSE'si 0.959 m, false-stationary sayısı sıfır oldu.
|
||
|
||
Bu sonuç GPS Doppler velocity'nin neden değerli olduğunu da gösterir. Position
|
||
farkından stationary/moving ayırımı düşük hızda ve kısa periodda zayıftır.
|
||
Ürün yolu artık WLS'nin ECEF velocity covariance'ini ENU'ya döndürüp ayrı
|
||
velocity measurement update'inde kullanır. Default `2.0/2.0/3.0 m/s`
|
||
covariance floor ve 3-DOF `%99.9` NIS gate kartta ölçülen zayıf-geometri
|
||
saçılımına karşı konservatiftir. Daha hızlı stop confirmation, bu update'ten
|
||
ayrı ve çoklu-epoch istatistiksel kanıt gerektiren sonraki adımdır.
|
||
|
||
ASan ve UBSan hata vermedi. Sekiz adet 60 s hareketli koşu ile 30 s/500 Hz
|
||
stationary koşunun tamamı masaüstünde yaklaşık 0.70 s user CPU süresinde
|
||
tamamlandı. `gprof`te sürenin yaklaşık %73'ü covariance dahil ESKF
|
||
propagation, %18'i measurement/ZUPT update içindeydi. Bu yüzdeler darboğazı
|
||
gösterir; masaüstü süresi 50 MHz Rocket için doğrudan cycle tahmini değildir.
|
||
Profil koşusunda fixed-lag replay dahil 111,009 `fusion_engine_push_imu`,
|
||
239,075 covariance propagation step ve 30,352 selected measurement/ZUPT
|
||
update çağrısı oluştu. Host maksimum RSS yaklaşık 2.6 MB idi; bu değer glibc,
|
||
sanitizer/profiler ve process overhead içerdiğinden bare-metal BSS ile aynı
|
||
metrik değildir.
|
||
|
||
Genesys2/RISC-V bare-metal build'i de geçti:
|
||
|
||
```sh
|
||
make FPGA_BOARD=genesys2 fpga-elf-flash-image APP=gps_system \
|
||
GPS_DEBUG=1 GPS_DEBUG_LEVEL=3 \
|
||
TDK_IMU_ODR_HZ=500 GPS_NAV_SOLVE_TIMER_TICKS=50
|
||
```
|
||
|
||
Son ELF boyutu text/data/bss olarak `103840 / 2944 / 204816` bayt, flash
|
||
payload `106784` bayt ve CRC32 `0x16dbc828` oldu. Kart bu test sırasında bağlı
|
||
olmadığı için SPI interrupt hızı, gerçek Rocket cycle yükü ve UART telemetry
|
||
henüz donanım üzerinde ölçülmedi.
|
||
|
||
Build yeni fusion kaynaklarında compiler warning üretmedi. Linker'ın RAM
|
||
imajındaki mevcut `LOAD segment with RWX permissions` uyarısı devam ediyor;
|
||
bu ESKF değişikliğine özel değildir fakat ileride linker-script güvenlik/segment
|
||
ayrımı çalışmasında ele alınmalıdır.
|
||
|
||
Kart tekrar bağlandığında sentetik testin yerine geçmeyen şu donanım
|
||
doğrulamaları yapılmalıdır:
|
||
|
||
1. ICM-42688-P `WHO_AM_I=0x47`, gerçek accel/gyro eksen yönleri ve kart mounting
|
||
dönüşümü doğrulanmalı.
|
||
2. 100/200/500 Hz seçeneklerinde INT1 IRQ sayısı, sample sayısı, spurious IRQ,
|
||
estimated missed sample ve 256-raw-queue overflow sayaçları izlenmeli.
|
||
3. `navigation_fusion_service()` ve tek `eskf_propagate_step()` için Rocket
|
||
`rdcycle` ortalama/maksimum değerleri ölçülmeli; 50 MHz'deki gerçek CPU payı
|
||
bu cycle ölçümünden çıkarılmalı.
|
||
4. En az 2 s fiziksel stationary başlangıçta calibration reset sayısı, accel/
|
||
gyro varyansı ve bulunan bias'lar sıcaklıkla birlikte loglanmalı.
|
||
5. Elle hareket testinde stationary -> moving çıkış süresi, sabit hızda ZUPT'nin
|
||
kapalı kaldığı ve durduktan sonra candidate -> stationary geçişi doğrulanmalı.
|
||
6. GPS WLS ölçüm timestamp'i ile IMU local tick'lerinin aynı CLINT domaininde
|
||
monoton kaldığı; replay/stale/pending/history-overflow sayaçlarının beklenen
|
||
değerlerde olduğu kontrol edilmeli.
|
||
7. Fused LLH/ENU, velocity, motion state, NIS, GPS accept/reject ve covariance
|
||
sigma değerleri UART'a kaydedilip fiziksel ground truth veya surveyed nokta
|
||
ile karşılaştırılmalı.
|
||
|
||
Sentetik test; SPI elektrik bağlantısını, interrupt polarity/clear davranışını,
|
||
sensor scale/mounting hatasını, gerçek multipath dağılımını, sıcaklıkla bias
|
||
driftini veya 50 MHz timing deadline'ını kanıtlamaz. Buradaki metre sonuçları
|
||
gerçek ürün accuracy iddiası değil; bilinen truth ve covariance ile algoritma
|
||
tutarlılığı/regression sonucudur.
|
||
|
||
## 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/gps_time_anchor.h` ve `src/gps/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.
|