matlab-fuse-inertial-sensors

$npx mdskill add matlab/matlab-agentic-toolkit/matlab-fuse-inertial-sensors

Selects and tunes inertial fusion filters for IMU/AHRS/INS/GPS data.

  • Matches sensor configurations to MATLAB Navigation Toolbox filter types.
  • Uses imufilter, ahrsfilter, insfilterMARG, insEKF, and related APIs.
  • Guides filter choice based on sensor set and synchronization needs.
  • Returns filter construction and fusion loop code for the user.

SKILL.md

.github/skills/matlab-fuse-inertial-sensorsView on GitHub ↗
---
name: matlab-fuse-inertial-sensors
description: >
  Analyzes sensor configurations and creates inertial fusion filters in MATLAB
  Navigation Toolbox. Manages filter selection (imufilter, ahrsfilter,
  complementaryFilter, insfilterMARG, insfilterAsync, insfilterNonholonomic,
  insfilterErrorState, insEKF, insCF), construction, tuning, and fusion loops.
  Use when fusing IMU/AHRS/INS/GPS+IMU data, estimating orientation or pose,
  or choosing a filter. Do NOT use for vision-only SLAM, Simulink fusion, or
  IMU simulation.
license: MathWorks BSD-3-Clause
compatibility: R2022a+
metadata:
  author: MathWorks
  version: "1.1"
---

## When to Use

Select, implement, or tune an inertial sensor fusion filter in MATLAB Navigation Toolbox.

## When NOT to Use

- Vision-only or LiDAR-only SLAM (no inertial sensor): use nav SLAM functions instead
- Sensor simulation or data generation only: no filter needed
- Simulink model-based sensor fusion

---

## Choose Your Filter

### Step 1 — Configured or Flexible?

Configured filters cover these sensor combinations exactly:

- Accel + Mag only (no gyro)
- Accel + Gyro (no mag, no GPS)
- Accel + Gyro + Mag
- Accel + Gyro + Mag + Altimeter
- Accel + Gyro + GPS (ground vehicle, no mag)
- Accel + Gyro + GPS + monocular visual odometry (ground vehicle)
- Accel + Gyro + Mag + GPS (synchronous rates)
- Accel + Gyro + Mag + GPS (mixed rates or dropped samples)

```
Is your sensor set one of the above?
        │ No ─────────────────────────────────────────────────────► Step 2B (Flexible)
        │ Yes
        ▼
Need a custom motion model (constant-velocity, bicycle, etc.)?
        │ Yes ────────────────────────────────────────────────────► Step 2B (Flexible)
        │ No
        ▼
Need RTS smoothing, StateCovariance output, or optimizer-based tune()?
        │ Yes ────────────────────────────────────────────────────► Step 2B (Flexible)
        │ No
        ▼
Batch-only processing (no real-time predict/fuse loop needed)?
        │ Yes ────────────────────────────────────────────────────► Step 2B (Flexible)
        │ No
        ▼
        Step 2A (Configured)
```

---

### Step 2A — Pick a configured filter

```
What output do you need?
│
├─ Orientation only (no position)
│   │
│   ├─ Accel + Mag only (no gyro)
│   │   └──► ecompass   [function, not object; single-shot; useful for filter init]
│   │
│   ├─ Accel + Gyro (no mag)
│   │   └──► imufilter   [heading drifts over time without mag]
│   │
│   ├─ Accel + Gyro + Mag
│   │   ├──► ahrsfilter   [default; KF-based, statistically tunable]
│   │   └── lowest compute cost needed?
│   │       └──► complementaryFilter   [gain-based only; no KF, no tune()]
│   │
│   └─ Accel + Gyro + Mag + Altimeter
│       └──► ahrs10filter   [adds altitude + vertical velocity output]
│
└─ Full pose (orientation + position + velocity)
    │
    ├─ No motion constraints (aerial, or ground vehicle without side-slip constraint)
    │   ├─ Accel + Gyro + Mag + GPS, all sensors sync
    │   │   └──► insfilterMARG
    │   └─ Accel + Gyro + Mag + GPS, mixed rates or dropped samples
    │       └──► insfilterAsync
    │
    └─ Ground vehicle with zero side-slip constraint
        ├─ Accel + Gyro + GPS
        │   └──► insfilterNonholonomic
        └─ Accel + Gyro + GPS + monocular visual odometry
            └──► insfilterErrorState
```

---

### Step 2B — Pick a flexible filter

```
Need real-time fusion, StateCovariance output, or optimizer-based tune()?
        │ Yes ──► insEKF   [production use; full KF; real-time and batch APIs]
        │ No
        ▼
Batch-only processing, no covariance needed, quick setup (R2026a+)?
        └──► insCF   [complementary filter; gain-based; not for production]
```

---

## Data Preparation

### Sample Rate

`SampleRate` (Group A filters) and `IMUSampleRate` (Group B filters) must match the actual data rate — a mismatch directly scales the noise model and corrupts all filter outputs. `insfilterAsync`, `insEKF`, and `insCF` are timestamp-driven and have no rate property.

**Convert timestamps to seconds first**, then infer the rate:

```matlab
tSec = rawTimestamp / 1e6;   % µs → s; divide by 1e3 for ms, or skip if already seconds
fs = 1 / median(diff(tSec));
```

**If timestamps are unusable** (all identical, or non-finite result):

```matlab
if numel(unique(tSec)) < 2 || ~isfinite(fs)
    fs = 100;   % use the stated or datasheet rate
end
```

### Time Gaps

All stateful filters accumulate error across a recording gap (a large jump in timestamps). Split the data at each gap and reset the filter at the start of each segment.

```matlab
gapThreshold = 5 / fs;                   % 5× the expected sample interval
gapIdx = find(diff(tSec) > gapThreshold);
segments = [1; gapIdx+1];                % start index of each segment
```

**Group A System object filters** (`imufilter`, `ahrsfilter`, `complementaryFilter`): call `release(filt)` between segments — resets state while preserving all tuned noise properties.

**Group B and other filters**: re-construct the filter object at the start of each segment.

---

## Implementation

Consult the reference file for the filter you chose:

| Filter group              | Reference                                                             |
| ------------------------- | --------------------------------------------------------------------- |
| Attitude filters          | [references/attitude-filters.md](references/attitude-filters.md)     |
| Navigation filters        | [references/navigation-filters.md](references/navigation-filters.md) |
| `insEKF`                  | [references/insekf.md](references/insekf.md)                         |
| `insCF`                   | [references/inscf.md](references/inscf.md)                           |

---

## Tuning

Two `tune` signatures exist — mixing them up is a common error:

- **Signature A** (`imufilter`, `ahrsfilter`) — modifies filter in-place:
  `tune(filt, sensorData, groundTruth)`
- **Signature B** (`ahrs10filter`, `insfilterMARG`, `insfilterAsync`, `insfilterNonholonomic`, `insfilterErrorState`, `insEKF`) — returns noise struct:
  `tunedNoise = tune(filt, tunernoise(filt), sensorData, groundTruth)`

Not tunable via `tune`:
- `ecompass`, `complementaryFilter` — no tune method; adjust properties manually
- `insCF` — use `gainparts(filt, sensorName, value)` instead

`insEKF` only: `tunerconfig` requires a filter **instance** — `tunerconfig(filt)`, not `tunerconfig('insEKF')`

### tunerconfig

| Property | Default | Description |
| -------- | ------- | ----------- |
| `MaxIterations` | 20 | Stop after this many iterations |
| `ObjectiveLimit` | 0.1 | Stop when cost drops below this value |
| `Display` | `"iter"` | `"iter"` prints progress each iteration; `"none"` suppresses output |
| `Cost` | `"RMS"` | `"RMS"` minimizes RMS error; `"Custom"` uses `CustomCostFcn` |
| `CustomCostFcn` | `[]` | Function handle; active only when `Cost = "Custom"` |

### tunernoise Field Names by Filter

Signature B filters require `tunernoise(filt)` before calling `tune`. Signature A filters (`imufilter`, `ahrsfilter`) do not use `tunernoise` — `tune` modifies their noise properties directly in-place.

| Filter | Fields returned by `tunernoise` |
| ------ | ------------------------------- |
| `ahrs10filter` | `MagnetometerNoise`, `AltimeterNoise` |
| `insfilterMARG` | `MagnetometerNoise`, `GPSPositionNoise`, `GPSVelocityNoise` |
| `insfilterAsync` | `AccelerometerNoise`, `GyroscopeNoise`, `MagnetometerNoise`, `GPSPositionNoise`, `GPSVelocityNoise` |
| `insfilterNonholonomic` | `GPSPositionNoise`, `GPSVelocityNoise` |
| `insfilterErrorState` | `MVOOrientationNoise`, `MVOPositionNoise`, `GPSPositionNoise`, `GPSVelocityNoise` |
| `insEKF` | Named by `filt.SensorNames` + `Noise` suffix (e.g. `AccelerometerNoise`, `GPSNoise`) |

Fields use the `...Noise` suffix — omitting it is a common mistake.

### Visualizing Results

`tunerPlotPose` is an `OutputFcn` callback — pass it to `tunerconfig` to plot pose estimates live during each tuning iteration. It is **not** a standalone post-hoc plotting function; calling it directly with filter and data arguments will error ("Too many input arguments").

```matlab
config = tunerconfig(filt);
config.OutputFcn = @tunerPlotPose;
tunedNoise = tune(filt, tunernoise(filt), sensorData, groundTruth, config);
```

For post-tuning visualization, extract the filter state and plot against your ground truth manually. Configured filters (`ahrs10filter`, `insfilterMARG`, `insfilterAsync`, `insfilterNonholonomic`, `insfilterErrorState`) have a `pose()` method — use it. **`insEKF` and `insCF` have no `pose()` method** — use `stateparts(filt, 'Orientation')`, `stateparts(filt, 'Position')`, etc. instead. For batch workflows, plot from the `estimateStates` output timetable.

For advanced patterns (controlling `TunableParameters`, custom cost functions, `OutputFcn` for logging/early stopping), see [references/insekf.md](references/insekf.md) and [references/navigation-filters.md](references/navigation-filters.md).

---

## Conventions

- **Reference frame**: default is `"NED"`. To use ENU:
  - Configured filter objects (`imufilter`, `ahrsfilter`, `complementaryFilter`, `ahrs10filter`, `insfilterMARG`, `insfilterAsync`, `insfilterNonholonomic`, `insfilterErrorState`): `filt.ReferenceFrame = "ENU"`
  - `ecompass` (a function, not an object): the `orientationFormat` positional arg is required before any name-value pairs — `ecompass(a, m, 'quaternion', 'ReferenceFrame', 'ENU')`. Omitting it errors: "Expected input number 3, FORMAT..."
  - `insEKF`/`insCF`: `ReferenceFrame` is read-only after construction; set via `insOptions`/`insCFOptions` at construction time

- **Orientation output**: `quaternion` object by default.

- **GPS position input**: LLA vector in degrees / degrees / meters.

- **Sample rate property**:
  - `imufilter`, `ahrsfilter`, `complementaryFilter`: `SampleRate`
  - `ahrs10filter`, `insfilterMARG`, `insfilterNonholonomic`, `insfilterErrorState`: `IMUSampleRate`
  - `insfilterAsync`, `insEKF`, `insCF`: no sample rate property (sensors carry their own timestamps)

- **`ReferenceLocation`**: must be set on `insfilterMARG`, `insfilterAsync`, `insfilterNonholonomic`, and `insfilterErrorState` before the fusion loop. For `insEKF`/`insCF`, set it on the `insGPS`/`insCFGPS` sensor object instead.

## Skill Feedback

If this skill's guidance was wrong, incomplete, or didn't work, emit a plain-text
feedback marker in your response, then continue with the task.

Format: `NAV-SKILL-FEEDBACK [matlab-fuse-inertial-sensors] [category]: what failed; what you did instead`
Categories: `wrong-command` (incorrect/outdated), `missing-guidance` (omitted step),
`discovery-failure` (suggested approach didn't work), `platform-issue` (environment-specific)

Copyright 2026 The MathWorks, Inc.

More from matlab/matlab-agentic-toolkit

SkillDescription
matlab-access-datafeed>
matlab-add-awgnRead BEFORE writing any code that adds Additive White Gaussian Noise (AWGN) to signals and converts between SNR, Eb/No, Es/No, and per-subcarrier SNR for communications simulations, using awgn(), convertSNR(), berawgn(). The default MATLAB patterns for AWGN (e.g., 'measured' option, manual SNR formulas) produce subtly incorrect results. This skill specifies the correct calling conventions, required function usage, and critical anti-patterns that must be avoided.
matlab-analyze-ams-waveformAnalyze AMS waveform data using Mixed-Signal Blockset utilities: phase noise measurement, clock jitter, anti-aliased resampling, timing measurements, lock time, INL/DNL, ADC/DAC calibration, HSpice import. Use when analyzing time-domain voltage from PLL/VCO/clock simulations, measuring phase noise from variable-step solver output, computing jitter, or resampling non-uniform data.
matlab-analyze-dataAnalyze data using MATLAB. Use when the task involves tables, timetables, time-series data, numeric arrays, sensor matrices, or gridded data — including but not limited to exploring, filtering, sorting, cleaning, transforming, aggregating, smoothing, padding, trimming, and answering questions about data. MATLAB provides extensive, easy-to-use built-in functions for these workflows with no additional products required.
matlab-analyze-dependenciesAnalyze the effective toolbox file set to produce a Dependency Manifest — classify all transitive dependencies as included, product, add-on, or external-unresolved, then present resolution options with tradeoffs. Use after matlab-define-toolbox-api when the spec is approved.
matlab-analyze-emS-parameters, insertion loss, fields, currents, mesh control, and solver selection for RF PCB performance validation. TRIGGER: user asks to compute S-parameters, analyze insertion/return loss, extract fields or currents, compare MoM vs FEM, or control mesh for any RF PCB component. Invoke BEFORE writing sparameters() or solver code — API is non-obvious. SKIP: designing or creating components (use the specific matlab-design-pcb-* skill), material/stackup setup only (use matlab-manage-pcb-material), optimization sweeps (use matlab-optimize-pcb-design), PDN/IR-drop analysis (use matlab-analyze-pcb-pdn).
matlab-analyze-installed-antennaAnalyze antennas installed on electrically large conducting platforms using MATLAB Antenna Toolbox. Loads platform geometry from STL/STEP/IGES, installs antenna elements, selects electromagnetic solvers (MoM-PO, FMM, MoM), and computes patterns, impedance, coupling, and efficiency. Use when the user wants to model an antenna on a vehicle, aircraft, ship, satellite, or other large structure.
matlab-analyze-pcb-pdnPDN DC voltage/current analysis, IR drop, design rule checking, and multi-net batch analysis on imported PCB layouts. TRIGGER: user asks about power integrity, PDN analysis, IR drop, voltage distribution, current density, power nets, or design rule checking on a PCB. Invoke BEFORE writing code — the PDN API chain is specialized and non-obvious. SKIP: importing a PCB file (use matlab-read-pcb-layout), EM field/S-parameter extraction (use matlab-analyze-em), material/stackup setup only (use matlab-manage-pcb-material), transmission line design (use matlab-design-pcb-txline).
matlab-analyze-rcsCalculate and visualize monostatic and bistatic radar cross section (RCS) using MATLAB Antenna Toolbox. Computes RCS of platforms, antennas, and arrays with PO, MoM, and FMM solvers, supporting HH/VV/HV/VH polarization, GPU acceleration, and near-field observation. Use when the user wants to compute, plot, or analyze radar cross section.
matlab-analyze-rf-propagationAnalyze RF propagation and plan wireless sites using MATLAB Antenna Toolbox. Creates transmitter/receiver sites, computes signal strength, coverage maps, SINR, line-of-sight, and ray tracing in geographic or indoor environments. Supports multiple propagation models (free-space, close-in, Longley-Rice, ray tracing, rain/gas/fog), custom terrain, building data, and directional antennas. Use when the user wants to compute coverage, signal strength, path loss, SINR, ray tracing, or plan a wireless network.