Skip to content
bareboat-necessitiesPublic

About

Collection of algorithms for IMU data processing in marine environment. Boat heave, wave direction, wave height, attitude (yaw, roll, pitch), tilt compensated compass, ship MRU, GPS fusion, NMEA sensors with IMU, marine AHRS/INS, marine Kalman filters, Arduino/MCU code for marine IMU. Aimed for quality

Resources

Stars

39 stars

Watchers

1 watching

Forks

Repository files navigation

ocean-imu

Marine IMU and wave-processing algorithms in modern C++ for sensor fusion, sea-state estimation, and simulation-driven validation. Designed for ship MRU (Motion Reference Unit), Marine INS (Inertial Navigation System), AHRS (Attitude and Heading Reference System).

Motivation

A marine AHRS cannot just reuse typical popular drone and aerospace IMU filters unchanged. In aerospace, motion is usually modeled as rotation about the center of mass (satellite), and drones often initialize while sitting still before takeoff, so the accelerometer gives a clean gravity direction. On a ship, the system may be turned on while already moving in waves and wind, with heave, roll, pitch, and translational accelerations all mixed into the IMU signals. That means the filter has to learn tilt during motion, avoid trusting wave-distorted acceleration as pure gravity, and keep working across very different sea conditions. In practice, a ship AHRS/INS needs wave-aware initialization, motion compensation, and tuning that can adapt to different sea states dynamically.

The algorithms presented here not only implement tilt-compensated compass and basic roll/pitch/rate-of-turn sensors, they provide corrections for wave induced motion, and additionally reconstruct 3D displacement of a vessel (heave - strongly observable, surge/sway - weakly) in real-time and estimate apparent (to the vessel being observer) waves direction.

The code of filters is written in C++ and can run on a microcontroller such as esp32 or on a regular computer. The compass calibration implemented as a part of this library can be run directly on your microcontroller unit. The testing framework uses Stokes/Airy waves with Pierson-Moskowitz or JONSWAP spectrums and a choice of a directional spread model (cosine by default).

Methods

The articles describing the math behind the methods:

INS Filters:

Heave-only filters (comparison baselines, see docs/heave-only.md):

Research Studies:

IMU Calibration:

Frequency tracking:

Wave Models:

Autopilot Use Cases:

There are several versions of Kalman INS filters and two filters (PII observer and NLO) based on control theory:

  • CARMA(4,1) stochastic process with Two Frame Lie Group filter delivers the lowest RMS of heave error (below 3% of significant wave height).
  • CARMA(4,1) with QMEKF is a quaternion counterpart of the previous one.
  • OU_III uses higher-order integral drift correction. It is a 21-dimensional-state Kalman filter and is the OU variant used for the main 3-D navigation study.
  • TFG is a right-invariant two-frame Lie-group error-state EKF. Same 21 dimensional state and the same OU wave model as OU_III, but attitude, the world-frame kinematic states and the body-frame biases live on one group, so an attitude correction rotates velocity, position, integral displacement and wave acceleration coherently instead of leaving them behind.
  • OU_II uses more direct integral drift correction and is more responsive to sea-state changes. It is an 18-dimensional-state Kalman filter.
  • PII observer is based on control theory. It is very computationally light-weight with no matrix operations. It's less accurate than Kalman filters.
  • NLO is a time-varying-gain nonlinear observer. It uses explicit attitude and translational injection terms with the gains published by Bryne/Fossen/Johansen instead of a propagated covariance, and its translational loop is scheduled on the tracked wave frequency.
  • All above filters are adaptive.
  • All filters tested to run on esp32s3.
  • All filters tested to run on Windows and Linux as well.

Arduino .ino sketches for esp32s3 (on atomS3R):

Overview

ocean-imu collects reusable components for marine motion estimation and wave analytics. The codebase is organized so individual modules can be built and exercised from tests/* without requiring a monolithic build system.

UI

GUI client (Windows and Linux):

https://github.com/bareboat-necessities/ins-dashboard-gtk

Main capabilities

  • Attitude and heading workflows (yaw/roll/pitch, AHRS-oriented utilities)
  • Wave and frequency-domain analysis
  • Wave direction detection
  • Kalman-based sea-state models (OU-II and OU-III variants)
  • Tuning and filtering helpers for marine sensor pipelines

Results

Results of the tests, simulations and documentation built from the development branch are published at https://github.com/bareboat-necessities/ocean-imu/releases/tag/v2.7.0

The figures below are the current OU-III diagnostics and validation evidence. The per-wave and spectrum figures under reports/results/readme/ are copied from SVG artifacts generated by successful build runs on main; the aggregate error plots come from the versioned full validation bundle under reports/results/ou_validation/, and the transition, engine-vibration, and lever-arm figures come from their own versioned study bundles under reports/results/. Every figure ships with the CSV, summary, and manifest that produced it, so the front page stays tied to reproducible outputs instead of manually copied sample images.

Directional wave spectrum

The simulator is driven by directional spectral seas, not only scalar sinusoidal heave. The existing build-generated 3-D spectrum below shows the frequency-direction energy surface for the same representative medium PM/Stokes case used by the motion plots above.

Medium PM Stokes three-dimensional directional spectrum

3-D motion tracking on the same sea

The two plots below use the same medium PM/Stokes wave case (H_s = 1.5 m). The vertical plot shows heave-chain tracking; the companion plot shows the more weakly observable horizontal surge/sway channels rather than presenting Z alone.

OU-III vertical displacement, velocity and acceleration tracking OU-III horizontal X/Y displacement, velocity and acceleration tracking
Z kinematics X/Y kinematics

The corresponding attitude trace from that same generated case is also retained with the gallery:

OU-III roll pitch and yaw tracking

Bias tracking

OU-III estimates inertial-sensor biases as filter states. These plots show the simulated truth and estimated accelerometer and gyroscope biases over the same wave record, so bias convergence is visible rather than only final RMS navigation error.

OU-III accelerometer bias tracking OU-III gyroscope bias tracking
Accelerometer bias Gyroscope bias

Validation errors and sea-state transitions

The validation plots summarize the full paired noisy study rather than one selected trajectory. Displacement and attitude error plots expose performance across the declared sea cases, while the transition plot exercises adaptation as the sea state changes.

OU validation displacement errors OU validation attitude errors
3-D displacement error Attitude error

The transition figure is the round trip, not a one-way build. A single realization holds H_s = 1.5 m for the first 400 s, blends up to H_s = 4.0 m over the next two minutes, holds the big sea until 800 s, blends back down to H_s = 1.5 m by 920 s, and finishes in the mild sea it started in. A low-to-high record only exercises the tightening half of the scheduler; coming back down is the direction where an adaptive filter can be left stuck on a sea that is no longer there, so it is the half worth showing. The low-sea and high-sea reference lines on the schedule panel are independently calibrated frozen operating points for the two endpoint records: the applied tau, sigma_aw, and R_s traces should leave the low fixed point, reach the high one, and come back to the low one without hysteresis.

OU-III bidirectional low-high-low sea-state transition

Engine vibration on the IMU

Motoring puts machinery vibration straight into the IMU. The engine-noise degradation study replays the eight stationary JONSWAP / PM-Stokes records through OU-II, OU-III, and TFG with a sensor-path model of a mid-size cruising sailboat's auxiliary diesel added on top of the ordinary sensor noise: crank orders, shaft- and blade-rate lines, a broadband structural floor, governor hunting, mount transmissibility, the sensor's finite anti-alias bandwidth, accelerometer vibration rectification, and gyroscope g-sensitivity. The vessel's rigid-body response to the sea is unchanged, so what the figures bound is the sensor-path cost of running the engine.

Displacement, pitch and yaw error against engine speed Vibration level and bandwidth sweeps collapsed onto recorded vibration power
Response against engine speed What actually drives it

The left figure sweeps engine speed at a fixed hull vibration level; the dotted horizontals are each family's engine-off baseline. The right figure is the mechanism: a level sweep, a bandwidth sweep with its matched-power control, every cell of the study collapsed onto recorded vibration RMS, and the rectified static tilt offset underneath it all. The damage tracks recorded out-of-band accelerometer power, not where the aliased crank orders happen to land, and it is largely a standing tilt bias rather than added jitter. At nominal cruise, OU-III's pooled 3-D error is 8.1x its engine-off baseline; a sensor bolted near the engine bed reaches 72x.

Because the cause is out-of-band power in one sensor, it has a front-end remedy. AccelVibrationGuard low-passes the accelerometer in the empty decade between the wave band and the machinery band (2 poles at 14 Hz), engages only when a separate high-pass detector says there is machinery to remove, and raises the commanded accelerometer sigma from the same gated excess so the covariance describes the conditioned signal.

Pooled 3-D error and standing tilt offset with the vibration guard off, on, and with the covariance arm

Across the sweep the guard pulls OU-III back to within 1.08-1.17x of engine-off, and the engine-off rows are identical to every digit because the detector never crosses its lower rail with no machinery running. The residual does not reach 1.00 and cannot: conditioning costs group delay, which is paid whether or not there is anything left to remove. The 800 rpm row is the other limit showing itself - machinery whose orders reach into the wave band cannot be separated from the sea by any front-end filter.

Off-CG IMU installation and lever arm

The wave records define motion at the vessel's centre of gravity, but an IMU is bolted wherever the installation allows. A rigid sensor displaced by a body-frame vector r additionally measures alpha x r + omega x (omega x r). The lever-arm study applies that term to the accelerometer truth before sensor corruption and the filter's own lever-arm model after it, over a matrix of 8 records, 3 axes (athwartships, fore-aft, vertical), 3 offsets (10/20/30 cm), and 3 modelling arms: unmodeled (no filter-side correction), gyro (compensated from the measured rate - the deployable one), and exact (compensated from truth kinematics - an oracle bound). Nothing else is retuned.

Pooled 3-D displacement penalty against IMU offset from the CG, per axis and per modelling arm Pooled attitude penalty against IMU offset from the CG, per axis and per modelling arm
Displacement penalty and its removal Attitude penalty and its removal

The two channels are hurt by different axes. Displacement degrades most with a vertical offset (1.022x at 30 cm unmodeled); attitude degrades most with an athwartships offset, where 30 cm nearly doubles the tilt RMS. The exact arm returns to the CG baseline to numerical precision in every cell, so the whole penalty is deterministic and recoverable rather than an intrinsic OU-III limit, and the gyro arm recovers most of it from the measured rate alone.

Injected specific force against offset, and the residual each modelling arm leaves behind Pooled 3-D error against the derivative low-pass corner of the deployable lever-arm model
What is injected, what is left Derivative band of the deployable model

The deployable arm reconstructs the angular acceleration through a two-pole low-pass followed by a causal second-order difference, and that corner is its one design parameter. The sweep on the right is why it is set to 15 Hz: too narrow and the phase lag misaligns a correction of the right magnitude, too wide and differentiated gyro noise dominates. Both failure directions cost more than the raw penalty they were meant to remove.

Per-sea lever-arm penalty at a 30 cm offset across the eight wave records

Pooled ratios understate the effect and the per-sea figure is the honest one. An RMS over all eight seas is dominated by the largest, where the injected rotational term is smallest relative to the wave signal; broken out sea by sea, the displacement penalty is worst in the mildest seas and the attitude penalty worst in the steepest.

The experimental CARMA3 and TFG-CARMA3 filters carry the same deployable model, applied at their fusion wrapper's input; their own off-CoG study, out to 2 m and against OU-III's in-filter placement, is docs/carma-imu-lever-arm.md.

Embedded target: M5Stack AtomS3R

M5Stack AtomS3R

The OU-III implementation is not only a desktop simulation. The repository includes an AtomS3R marine-INS sketch that runs the adaptive SeaStateFusion OU-III estimator at 200 Hz on the M5Stack AtomS3R. Keeping the embedded target visible here matters because computational feasibility, startup behavior, calibration, heading lock, and real-time estimator integration are part of the intended marine use case, not an after-the-fact port of an offline algorithm.

Repository layout

src/                 core algorithms and reusable components
  ahrs/              attitude and heading routines
  avg/               averaging and smoothing helpers
  detrend/           detrending helpers
  discrete/          discrete-time utilities
  freq/              frequency-domain utilities
  imu_calibrate/     IMU calibration logic
  kalman_ou_ii/      OU-II Kalman model components
  kalman_ou_iii/     OU-III Kalman model components
  kalman_tfg/        two-frame Lie-group filter components
  lie/               Lie group operations the TFG filter is built on
  nmea/              NMEA parsing/helpers
  pii_observer/      observer/filter components
  tuner/             auto-tuning helpers
  util/              shared support code
  wave_dir/          wave direction estimation

tests/               module-level build and validation targets
  ahrs/              AHRS-focused tests and examples
  detrend/           detrending tests
  freq/              builds freq-track
  heave_only/        heave-only filters (Godhavn, Richter, Kuchler) and heave_only-sim
  imu_calibrate/     IMU calibration tests
  kalman_ou_ii/      builds kalman_ou_ii-sim
  kalman_ou_iii/     builds kalman_ou_iii-sim
  pii_observer/      builds pii_observer-adaptive
  wave_sim/          wave simulation programs

sensors/             sensor integration and application examples
  */                 standalone sensor-oriented demos/utilities

doc/                 module documentation and notes
plots/               generated plotting scripts/assets
img/                 images and sample result figures

Prerequisites

  • g++ with C++20 support
  • make
  • Eigen headers (typically from libeigen3-dev)

Typical Eigen include location on Linux:

  • /usr/include/eigen3

Simulation data dependency

Some validation and simulation workflows depend on data released in:

All simulations use release v1.2.3 and sim-data-files-vessel-rao-28ft.zip: an estimated stationary 28 ft fin-keel sailboat RAO at the CG. Motion CSVs contain vessel response; spectrum CSVs and filename heights describe the incident sea. The preset is analytical, not a measured hull response. make ensure-sim-data verifies the pinned SHA-256 and replaces stale surface inputs.

You can fetch and unpack this data for local runs with:

make fetch-sim-data

Build

Run builds from the specific test folder you want to validate:

cd tests/freq && make all
cd tests/kalman_ou_ii && make all
cd tests/kalman_ou_iii && make all
cd tests/pii_observer && make all

If Eigen is not on the default include path for your environment, pass an include override:

make all CPPFLAGS+='-I/usr/include/eigen3'

Validation

Primary project validation command (when available in your environment):

make all

For module-level validation, run make all inside the relevant folder under tests/.

Paired OU validation

The OU-II/OU-III statistical validation runner scores continuous metrics over the final 15 minutes of each 20-minute run. Deterministic simulator regression gates remain executable diagnostics, but they are not Monte Carlo inclusion criteria and are not exported as pass/fail evidence. Wave realization, IMU noise, and initialization are paired across both filters and matched ablations.

python3 tools/ou_validation.py --mode smoke
python3 tools/ou_validation.py --mode full

Full mode produces raw and summary CSV, JSON, LaTeX, paired-effect, manifest, and SVG plot artifacts under reports/results/ou_validation/. See docs/ou-validation.md for the protocol, provenance contract, seed controls, and interpretation.

About

Collection of algorithms for IMU data processing in marine environment. Boat heave, wave direction, wave height, attitude (yaw, roll, pitch), tilt compensated compass, ship MRU, GPS fusion, NMEA sensors with IMU, marine AHRS/INS, marine Kalman filters, Arduino/MCU code for marine IMU. Aimed for quality

Resources

Stars

39 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages