Production-ready MoonBit state estimation, smoothing, and sensor fusion library
let filter = @kalman.Kalman1D::new(0.0, 1.0, 0.02, 0.1)
filter.set_gate_threshold(9.210340371976184)
filter.predict_without_control()
let result = filter.update_if_valid(1.0)
println("result=\{result}, state=\{filter.state()}, variance=\{filter.uncertainty()}")moon run examples/sensor_fusionmoon run --target native --release benchmarksmoon version --all
moon update
moon check --target all --deny-warn
moon test --target all --deny-warn
moon fmt && git diff --exit-code
moon info && git diff --exit-codepub struct AdaptiveNoiseController {
process_scale : Double
measurement_scale : Double
minimum_scale : Double
maximum_scale : Double
target_nis : Double
learning_rate : Double
}fn AdaptiveNoiseController::new(minimum_scale : Double, maximum_scale : Double, target_nis : Double, learning_rate : Double) -> AdaptiveNoiseControllerpub struct BatchGate {
policy : ResidualPolicy
inspected : Int
accepted : Int
downweighted : Int
rejected : Int
}fn CalibrationTransform::apply(self : CalibrationTransform, values : Array[Double]) -> Array[Double]fn CalibrationTransform::inverse(self : CalibrationTransform, values : Array[Double]) -> Array[Double]pub struct ConsistencyReport {
count : Int
average_nees : Double
average_nis : Double
accepted_rate : Double
covariance_failures : Int
} derive(Debug)pub struct ConstantVelocityTracker2D {
filter : KalmanND
acceleration_variance : Double
position_variance : Double
last_timestamp : Int
initialized_timestamp : Bool
}fn ConstantVelocityTracker2D::new(initial_position : Array[Double], initial_velocity : Array[Double], initial_variance : Double, acceleration_variance : Double, position_variance : Double) -> ConstantVelocityTracker2Dfn ConstantVelocityTracker2D::set_gate_threshold(self : ConstantVelocityTracker2D, threshold : Double) -> Unitfn ConstantVelocityTracker2D::step(self : ConstantVelocityTracker2D, timestamp : Int, position : Array[Double], covariance : Matrix) -> UpdateResultfn ConstantVelocityTracker2D::step_position(self : ConstantVelocityTracker2D, timestamp : Int, x : Double, y : Double) -> UpdateResultpub struct ContractIssue {
code : String
severity : ContractSeverity
message : String
} derive(Debug)fn ContractIssue::new(code : String, severity : ContractSeverity, message : String) -> ContractIssuefn ControlCommand::new(timestamp : Int, values : Array[Double], duration : Double) -> ControlCommandpub struct ControlIntegrator {
dimension : Int
state : Array[Double]
limits : ControlLimits
response : Double
}fn ControlIntegrator::new(dimension : Int, limits : ControlLimits, response : Double) -> ControlIntegratorfn ControlIntegrator::step(self : ControlIntegrator, command : Array[Double], dt : Double) -> Array[Double]pub struct CovarianceReport {
health : CovarianceHealth
dimension : Int
symmetry_error : Double
minimum_eigenvalue : Double
maximum_eigenvalue : Double
condition_estimate : Double
finite : Bool
positive_diagonal : Bool
} derive(Debug)pub struct DataQualityReport {
total : Int
valid : Int
missing : Int
non_finite : Int
non_monotonic_timestamps : Int
duplicate_timestamps : Int
finite_fraction : Double
} derive(Debug)pub struct DeterministicRng {
state : Int
}pub struct EKF {
x : Array[Double]
p : Matrix
q : Matrix
r : Matrix
initial_state : Array[Double]
initial_covariance : Matrix
last_innovation : Array[Double]
last_innovation_covariance : Matrix
last_gain : Matrix
last_nis : Double
gate_threshold : Double
predict_count : Int
accepted_count : Int
rejected_count : Int
missing_count : Int
}pub(all) struct ErrorMetrics {
count : Int
rmse : Double
mae : Double
max_error : Double
final_error : Double
} derive(Debug)pub struct ExponentialStats {
alpha : Double
count : Int
mean : Double
variance : Double
minimum : Double
maximum : Double
}pub struct FeatureVector {
mean : Double
variance : Double
slope : Double
minimum : Double
maximum : Double
energy : Double
} derive(Debug)fn FilterCheckpoint::new(state : Array[Double], covariance : Matrix, timestamp : Int) -> FilterCheckpointfn FixedLagSmoother::push(self : FixedLagSmoother, filtered_state : Array[Double], filtered_covariance : Matrix, predicted_state : Array[Double], predicted_covariance : Matrix, transition : Matrix) -> Unitpub struct FusionEvent {
timestamp : Int
sensor : String
result : UpdateResult
state : Array[Double]
covariance : Matrix
nis : Double
} derive(Debug)fn FusionMeasurement::new(sensor : String, timestamp : Int, values : Array[Double], covariance : Matrix, confidence : Double) -> FusionMeasurementpub struct FusionPolicy {
gate_threshold : Double
max_time_gap : Int
covariance_inflation : Double
reject_non_finite : Bool
predict_on_missing : Bool
} derive(Debug)fn FusionPolicy::new(gate_threshold : Double, max_time_gap : Int, covariance_inflation : Double, reject_non_finite : Bool, predict_on_missing : Bool) -> FusionPolicypub struct FusionResult {
strategy : FusionStrategy
timestamp : Int
values : Array[Double]
covariance : Matrix
used : Int
rejected : Int
} derive(Debug)pub struct FusionStatistics {
total_packets : Int
accepted_packets : Int
rejected_packets : Int
missing_packets : Int
last_timestamp : Int
} derive(Debug)pub struct GateSchedule {
base_threshold : Double
minimum_threshold : Double
maximum_threshold : Double
consecutive_rejections : Int
recovery_steps : Int
}fn GateSchedule::new(base_threshold : Double, minimum_threshold : Double, maximum_threshold : Double, recovery_steps : Int) -> GateSchedulepub struct Histogram {
minimum : Double
maximum : Double
buckets : Array[HistogramBucket]
underflow : Int
overflow : Int
samples : Int
}pub struct InnovationMonitor {
dimension : Int
threshold : Double
samples : Int
accepted : Int
rejected : Int
nis_stats : RunningStats
last_nis : Double
}fn InnovationMonitor::observe(self : InnovationMonitor, innovation : Array[Double], covariance : Matrix) -> Boolpub struct Kalman1D {
x : Double
p : Double
q : Double
r : Double
initial_state : Double
initial_uncertainty : Double
last_innovation : Double
last_innovation_variance : Double
last_gain : Double
last_nis : Double
gate_threshold : Double
predict_count : Int
accepted_count : Int
rejected_count : Int
missing_count : Int
}fn KalmanDiagnostics::check_covariance(self : KalmanDiagnostics, covariance : Array[Array[Double]]) -> Boolpub struct KalmanND {
x : Array[Double]
p : Matrix
q : Matrix
r : Matrix
f : Matrix
h : Matrix
initial_state : Array[Double]
initial_covariance : Matrix
last_innovation : Array[Double]
last_innovation_covariance : Matrix
last_gain : Matrix
last_nis : Double
gate_threshold : Double
predict_count : Int
accepted_count : Int
rejected_count : Int
missing_count : Int
}fn KalmanND::from_model(model : LinearModel, initial_state : Array[Double], initial_covariance : Matrix) -> KalmanNDfn KalmanND::update_gated(self : KalmanND, measurement : Array[Double], threshold : Double) -> UpdateResultfn LinearModel::new(transition : Matrix, process_noise : Matrix, observation : Matrix, measurement_noise : Matrix, control : Matrix) -> LinearModelfn Matrix::regularized_least_squares(self : Matrix, rhs : Array[Double], regularization : Double) -> MatrixSolveResultpub struct MeasurementSchedule {
period : Int
elapsed : Int
}pub struct MeasurementWindow {
measurements : Array[FusionMeasurement]
capacity : Int
dimension : Int
}pub struct MissingObservationPolicy {
max_consecutive : Int
inflate_factor : Double
action : MissingObservationAction
} derive(Debug)fn MissingObservationPolicy::new(max_consecutive : Int, inflate_factor : Double, action : MissingObservationAction) -> MissingObservationPolicypub struct ModelScore {
name : String
rmse : Double
mae : Double
complexity : Int
consistency : Double
} derive(Debug)fn ModelScore::new(name : String, rmse : Double, mae : Double, complexity : Int, consistency : Double) -> ModelScorepub struct NoiseEstimate {
variance : Double
standard_deviation : Double
samples : Int
confidence : Double
} derive(Debug)pub struct NoiseSchedule {
nominal : Double
minimum : Double
maximum : Double
growth : Double
decay : Double
factor : Double
stressed_steps : Int
}fn NoiseSchedule::new(nominal : Double, minimum : Double, maximum : Double, growth : Double, decay : Double) -> NoiseSchedulefn ObservationPacket::new(timestamp : Int, sensor : String, values : Array[Double], covariance : Matrix) -> ObservationPacketfn ObservationPacket::with_inflated_noise(self : ObservationPacket, factor : Double) -> ObservationPacketpub struct OperationalMonitor {
samples : Int
accepted : Int
failures : Int
covariance_failures : Int
consecutive_failures : Int
worst_nis : Double
score : Double
warmup_samples : Int
failure_limit : Int
nis_limit : Double
}fn OperationalMonitor::new(warmup_samples : Int, failure_limit : Int, nis_limit : Double) -> OperationalMonitorfn OperationalMonitor::observe(self : OperationalMonitor, timestamp : Int, filter : KalmanND, result : UpdateResult) -> OperationalSnapshotpub struct OperationalSnapshot {
timestamp : Int
result : UpdateResult
status : FilterStatus
score : Double
nis : Double
state : Array[Double]
covariance : Matrix
} derive(Debug)pub struct PacketQuality {
sensor : String
report : DataQualityReport
accepted : Bool
reason : String
} derive(Debug)pub struct PipelineEvent {
fusion : FusionEvent
lifecycle : TrackLifecycle
sensor_score : Double
rolling_mean : Double
rolling_variance : Double
} derive(Debug)pub struct PipelineReport {
events : Int
accepted : Int
rejected : Int
missing : Int
final_lifecycle : TrackLifecycle
final_sensor_score : Double
} derive(Debug)fn RangeMeasurement::new(reference : Array[Double], value : Double, variance : Double) -> RangeMeasurementpub(all) enum ReplayEvent {
Predict(Int)
Measure(Int, Array[Double])
Missing(Int)
Restore(FilterCheckpoint)
} derive(Debug)pub struct ReplayRecord {
timestamp : Int
result : UpdateResult
state : Array[Double]
covariance : Matrix
nis : Double
} derive(Debug)fn ReplayRecord::new(timestamp : Int, result : UpdateResult, state : Array[Double], covariance : Matrix, nis : Double) -> ReplayRecordpub struct ReplaySession {
filter : KalmanND
trace : ReplayTrace
timestamp : Int
steps : Int
accepted : Int
rejected : Int
missing : Int
invalid : Int
}pub struct ResidualPolicy {
soft_limit : Double
hard_limit : Double
minimum_weight : Double
accepted : Int
downweighted : Int
rejected : Int
}fn ResidualPolicy::new(soft_limit : Double, hard_limit : Double, minimum_weight : Double) -> ResidualPolicypub struct RunningStats {
count : Int
mean : Double
second_moment : Double
minimum : Double
maximum : Double
}pub struct ScalarCalibration {
measurement : NoiseEstimate
process : NoiseEstimate
recommended_process_noise : Double
recommended_measurement_noise : Double
} derive(Debug)fn SensorCalibrator::add(self : SensorCalibrator, raw : Array[Double], reference : Array[Double]) -> Boolpub struct SensorClock {
period : Int
last_timestamp : Int?
samples : Int
late : Int
early : Int
jitter : RunningStats
}fn SensorConfiguration::new(name : String, dimension : Int, period : Int, timeout : Int, covariance : Matrix) -> SensorConfigurationfn SensorConfiguration::with_covariance(self : SensorConfiguration, covariance : Matrix) -> SensorConfigurationpub struct SensorFusion {
filter : KalmanND
policy : FusionPolicy
statistics : FusionStatistics
consecutive_missing : Int
}fn SensorFusion::process_missing(self : SensorFusion, timestamp : Int, sensor : String) -> FusionEventpub struct SensorHealth {
name : String
score : Double
decay : Double
recovery : Double
minimum_score : Double
accepted : Int
rejected : Int
}fn SensorModelPair::constant_velocity(dimensions : Int, dt : Double, acceleration_variance : Double, position_variance : Double, velocity_variance : Double) -> SensorModelPairpub struct SensorPacketBuilder {
configuration : SensorConfiguration
calibration : CalibrationTransform
built : Int
rejected : Int
}fn SensorPacketBuilder::build(self : SensorPacketBuilder, timestamp : Int, values : Array[Double]) -> ObservationPacket?fn SensorPacketBuilder::set_calibration(self : SensorPacketBuilder, calibration : CalibrationTransform) -> Boolpub struct SensorPipeline {
fusion : SensorFusion
tracker : TrackManager
health : Map[String, SensorHealth]
windows : Map[String, RollingWindow]
window_capacity : Int
}fn SensorPipeline::new(fusion : SensorFusion, confirmation_hits : Int, deletion_misses : Int, window_capacity : Int) -> SensorPipelinefn SensorPipeline::process_missing(self : SensorPipeline, timestamp : Int, sensor : String) -> PipelineEventfn SensorPipeline::run(self : SensorPipeline, packets : Array[ObservationPacket]) -> Array[PipelineEvent]fn SensorSample::new(timestamp : Int, truth : Array[Double], measurement : Array[Double], missing : Bool, outlier : Bool) -> SensorSamplepub struct SimulationResult {
samples : Array[SensorSample]
truth : Array[Array[Double]]
estimates : Array[Array[Double]]
metrics : ErrorMetrics
} derive(Debug)pub struct StateCandidate {
name : String
state : Array[Double]
covariance : Matrix
weight : Double
result : UpdateResult
} derive(Debug)fn StateCandidate::new(name : String, state : Array[Double], covariance : Matrix, weight : Double, result : UpdateResult) -> StateCandidatepub struct Synchronizer {
tolerance : Int
last_timestamp : Int?
accepted : Int
rejected : Int
}pub struct TelemetrySample {
timestamp : Int
channel : String
value : Double
quality : Double
result : UpdateResult
} derive(Debug)fn TelemetrySample::new(timestamp : Int, channel : String, value : Double, quality : Double, result : UpdateResult) -> TelemetrySamplepub struct TelemetrySummary {
samples : Int
accepted : Int
missing : Int
rejected : Int
mean : Double
variance : Double
quality : Double
status : FilterStatus
} derive(Debug)pub struct TrackManager {
lifecycle : TrackLifecycle
confirmation_hits : Int
deletion_misses : Int
hits : Int
misses : Int
age : Int
}fn TrajectoryPoint::new(timestamp : Int, position : Array[Double], velocity : Array[Double], covariance : Matrix) -> TrajectoryPointpub struct UKF {
x : Array[Double]
p : Matrix
q : Matrix
r : Matrix
initial_state : Array[Double]
initial_covariance : Matrix
alpha : Double
beta : Double
kappa : Double
predicted_sigma_points : Array[Array[Double]]
last_innovation : Array[Double]
last_innovation_covariance : Matrix
last_gain : Matrix
last_nis : Double
gate_threshold : Double
predict_count : Int
accepted_count : Int
rejected_count : Int
missing_count : Int
}pub struct UpdateSummary {
result : UpdateResult
innovation : Array[Double]
innovation_covariance : Matrix
normalized_innovation_squared : Double
} derive(Debug)pub struct ValidationReport {
name : String
checks : Int
passed : Int
issues : Array[ContractIssue]
}fn ValidationReport::check(self : ValidationReport, code : String, condition : Bool, severity : ContractSeverity, message : String) -> Boolpub struct WeightedAccumulator {
dimension : Int
total_weight : Double
weighted_sum : Array[Double]
}fn WeightedAccumulator::add(self : WeightedAccumulator, value : Array[Double], weight : Double) -> Boolfn calibrate_scalar(measurements : Array[Double], expected : Array[Double], spacing : Double, minimum_noise : Double) -> ScalarCalibrationfn candidate_from_filter(name : String, filter : KalmanND, result : UpdateResult, confidence : Double) -> StateCandidatefn candidate_from_scalar(name : String, filter : Kalman1D, result : UpdateResult, confidence : Double) -> StateCandidatefn constant_acceleration_process_noise(dimensions : Int, dt : Double, jerk_variance : Double) -> Matrixfn constant_velocity_model(dimensions : Int, dt : Double, acceleration_variance : Double, measurement_variance : Double) -> LinearModelfn constant_velocity_process_noise(dimensions : Int, dt : Double, acceleration_variance : Double) -> Matrixfn control_interpolate(left : ControlCommand, right : ControlCommand, timestamp : Int) -> ControlCommandfn filter_quality_score(metrics : ErrorMetrics, rejected : Int, covariance_failures : Int) -> Doublefn fuse_measurements(measurements : Array[FusionMeasurement], strategy : FusionStrategy, covariance_floor : Double) -> FusionResultfn inflate_for_residual(covariance : Matrix, residual : Array[Double], policy : ResidualPolicy) -> Matrixfn interpolate_trajectory_point(left : TrajectoryPoint, right : TrajectoryPoint, timestamp : Int) -> TrajectoryPointfn make_innovation_diagnostics(innovation : Array[Double], covariance : Matrix, gate_threshold : Double) -> InnovationDiagnosticsfn make_replay_events(start_timestamp : Int, count : Int, first_value : Double, velocity : Double, missing_period : Int) -> Array[ReplayEvent]fn proportional_control(state : Array[Double], target : Array[Double], gain : Double, limits : ControlLimits) -> Array[Double]fn quality_adjusted_covariance(covariance : Matrix, report : DataQualityReport, floor : Double) -> Matrixfn resample_trajectory(points : Array[TrajectoryPoint], timestamps : Array[Int]) -> Array[TrajectoryPoint]fn robust_weight(residual : Double, tuning : Double) -> Doublefn run_constant_velocity_2d_simulation(steps : Int, dt : Double, measurement_noise : Double, missing_period : Int, outlier_period : Int, seed : Int) -> SimulationResultfn run_scalar_simulation(steps : Int, measurement_noise : Double, missing_period : Int, outlier_period : Int, seed : Int) -> SimulationResultfn score_model(name : String, residuals : Array[Array[Double]], parameter_count : Int, consistency : Double) -> ModelScorefn simulate_constant_velocity_2d(steps : Int, dt : Double, initial_position : Array[Double], velocity : Array[Double], measurement_noise : Double, missing_period : Int, outlier_period : Int, seed : Int) -> Array[SensorSample]fn simulate_scalar_measurements(steps : Int, initial_value : Double, drift : Double, noise : Double, missing_period : Int, outlier_period : Int, seed : Int) -> Array[SensorSample]fn telemetry_from_filter(timestamp : Int, channel : String, filter : Kalman1D, result : UpdateResult) -> TelemetrySamplefn telemetry_merge(left : Array[TelemetrySample], right : Array[TelemetrySample]) -> Array[TelemetrySample]fn telemetry_resample(samples : Array[TelemetrySample], timestamps : Array[Int]) -> Array[TelemetrySample]fn validate_matrix(name : String, matrix : Matrix, expected_rows : Int, expected_cols : Int) -> ValidationReportProduction-ready MoonBit state estimation, smoothing, and sensor fusion library