winds-engine 0.1.1

Deterministic wind profiles and radiosonde validation for trajectory simulation
Documentation
  • Coverage
  • 100%
    64 out of 64 items documented0 out of 27 items with examples
  • Size
  • Source code size: 64.7 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 757.7 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 1s Average build duration of successful builds.
  • all releases: 3s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • ajokela/winds-engine
    1 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • ajokela

winds-engine

Deterministic wind profiles and radiosonde validation for trajectory simulation — the wind data pipeline for rocket modeling, consumed by rockets-engine. Kernel-side wind modeling (the WindField trait, profile types, analytic profiles) is staged here pending promotion to ballistics-engine's wind module; see docs/winds-engine-plan.md.

use winds_engine::{Sounding, WindField, validate};

// A measured sounding in the line-based interchange format. Heights are
// metres above sea level; this station's surface report is at 287 m.
let sounding = Sounding::parse("287 0.0 0\n305 3.09 125\n610 3.60 145\n")?;
// The profile keeps those heights, so it is read with y = height above sea
// level, the frame rockets-engine uses.
let profile = sounding.to_profile_field()?;
let wind = profile.wind(0.0, [0.0, 500.0, 0.0]); // 500 m above sea level
// Or score a candidate profile against the measurement.
let report = validate::validate(&profile, &sounding);
  • WindField trait: stateless, deterministic wind(time, position) — the same sampling pattern trajectory integrators already rely on.
  • ProfileField (piecewise-linear, circular direction interpolation), ConstantField, LogProfile, EkmanProfile.
  • Sounding: radiosonde interchange format (tested against a real 115-level KMPX sounding from the IEM RAOB archive). Heights are above sea level and stay that way in to_profile_field(), so the profile reads directly in a frame whose y is altitude above sea level, as in rockets-engine (with BallisticForces and in its flat-frame CLI, whose ground sits at --ground-altitude-m, sea level by default).
  • Datum conversion: LogProfile and EkmanProfile take y as height above the ground, where they are calm. This crate's staged types have no offset wrapper; ballistics-engine's HeightOffset (from its next release, which rockets-engine's =0.48.0 pin does not have) wraps only ballistics-engine's own WindField, not this crate's. So a caller in a sea-level frame either reads them at y - ground elevation at its single call site, or builds ballistics-engine's ProfileField/LogProfile/EkmanProfile from the same values and wraps those in HeightOffset (offset = the height of the caller's y = 0 in the field's datum: minus the ground elevation for a log or Ekman profile, none for a sea-level sounding). Convert in one place only: sounding heights stay above sea level, and shifting them as well would move every wind by the site elevation.
  • validate: speed/direction RMSE and per-layer errors vs a sounding.
  • Relationship to ballistics-engine: these types are this crate's own. ballistics-engine's wind fields (unreleased) were adapted from them and differ: WindField::wind takes and returns nalgebra::Vector3<f64> and there is no Wind type, ConstantField is a tuple struct over that vector, LogProfile/EkmanProfile keep their fields private behind getters, and constructors return WindFieldError. Moving winds-engine onto them changes this crate's public API (the example above, validate()'s signature), so it is a deliberate breaking release, not a drop-in re-export.

Zero dependencies, no network, no wall clock, no unseeded randomness. GRIB2/HRRR/GFS acquisition is the next milestone (risk item in the plan).

MIT licensed (see LICENSE).