(k: Kinematics, dtSec: number)
| 193 | * deadReckon conventions, but in geodetic coordinates and with altitude. |
| 194 | */ |
| 195 | export function predictGeo(k: Kinematics, dtSec: number): GeoPoint { |
| 196 | let east = 0; |
| 197 | let north = 0; |
| 198 | if (k.trackDeg != null && k.gsKt != null && k.gsKt > 0 && dtSec !== 0) { |
| 199 | const v = k.gsKt * KT_TO_MS; |
| 200 | const tr = k.trackDeg * DEG; |
| 201 | const w = (k.turnRateDps ?? 0) * DEG; // rad/s |
| 202 | if (Math.abs(w) > 1e-4) { |
| 203 | // Constant-rate turn: integrate the arc. |
| 204 | east = (v / w) * (Math.cos(tr) - Math.cos(tr + w * dtSec)); |
| 205 | north = (v / w) * (Math.sin(tr + w * dtSec) - Math.sin(tr)); |
| 206 | } else { |
| 207 | east = v * Math.sin(tr) * dtSec; |
| 208 | north = v * Math.cos(tr) * dtSec; |
| 209 | } |
| 210 | } |
| 211 | const altM = k.altM + ((k.vRateFpm ?? 0) * FT_TO_M / 60) * dtSec; |
| 212 | return { |
| 213 | lat: k.lat + north / 110540, |
| 214 | lon: k.lon + east / (111320 * Math.cos(k.lat * DEG)), |
| 215 | altM, |
| 216 | }; |
| 217 | } |
| 218 | |
| 219 | /** |
| 220 | * Turn-rate estimate (deg/s) from a short track history, with angle |
no outgoing calls