Files
gps/soc/software/fusion
onur cayan 471ff12e70 test(fusion): guard the deadlock and calibration regressions, add noise tool
The existing suite passed both before and after the fusion fixes, so it
never covered either failure. Two tests close that gap; both were checked
against the pre-fix sources and fail there.

calibration_offset_test reproduces the bench part's +28 mg zero-g offset
and requires startup to complete, while still refusing a sustained 3 m/s2
acceleration. It also asserts the blind spot rather than leaving it
implicit: horizontal acceleration adds to gravity in quadrature, so
1.5 m/s2 moves the magnitude by only 0.11 m/s2 and is not separable from
offset by any accelerometer gate. Separating it needs GNSS velocity.

long_outage_trajectory_test drives pedestrian, gentle-car (0-100 km/h in
30 s), slow-city and isolated-mount profiles across 1 and 5 minute
outages, using the production rest supervisor rather than a hand-set
flag. Only the isolated-mount slow-city case reproduces the field bug:
GNSS motion evidence compares displacement against covariance, so 4 m/s
under 6 m sigma scores a displacement NIS of 0.22 against a 9.21 gate and
reads as stationary, whereas highway speed scores 42.9 and is correctly
called moving. Pre-fix that case produces 608 zero-velocity updates while
driving, matching the 609 in the board logs.

Drift is judged against the filter's own covariance rather than a fixed
distance. Five minutes unaided legitimately reaches kilometres on this
hardware; what must not happen is the error outrunning the covariance,
which is divergence rather than honest coasting.

tdk_noise_test characterises the sensor at rest through the production
driver, so ODR, full scale, UI filter and LSB scaling match the flight
build, and reports the norms fusion_motion_update() actually gates on.
It also carries an INT1-to-PLIC continuity test that drives the pin to a
static level and reads the PLIC pending bit directly, separating a broken
line from a source that never fires.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 22:06:24 +03:00
..

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:

# 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:

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.

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:

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ı:

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:

python3 fusion_eskf.py

Sabit-kısıtlı ve hareket-kabiliyetli modelleri aynı kayıt üzerinde karşılaştırma:

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:

python3 map_player.py

5 dakikalık sabit/adaptif model karşılaştırmasını doğrudan açma:

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:

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:

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:

Mevcut recovery PX4'teki aiding yoneticisinin sade bare-metal karsiligidir; nihai mimari hedefi asagidaki acik GNSS aiding durum makinesidir:

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:

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:

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:

    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:

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ı. gprofte 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:

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:

23e2d5be11ab0bf23213c5253b4213277f11e5785d90484c9d624b4fcae944dc

FDE kapalı 5 dakika log SHA-256:

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 mden 16.74 mye, yatay maksimum 44.90 mden 22.56 mye ve 3B P95 78.95 mden 40.90 mye 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:

#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:

    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:

fb1de03aafacf46d95bde375f3f744635472e9893a9aff6f3c3db9a16444c5ce

5 dakika log SHA-256:

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.