Matlab Fuse Inertial Sensors
MathWorksOfficialCreated by MathWorks
- Skill
- Tool integration
- Science and research
- BSD-2-Clause
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to selecting, constructing, and tuning inertial fusion filters within the MATLAB Navigation Toolbox. It covers the full lifecycle of sensor fusion, from choosing between configured filters (like imufilter or ahrsfilter) and flexible filters (like insEKF) to data preparation, real-time or batch fusion loops, and parameter tuning. It emphasizes correct sensor configuration, handling of sample rates, and proper use of tuning signatures to ensure accurate orientation, pose, and velocity estimation.
What it does
- Guides selection of appropriate inertial fusion filters based on sensor availability and motion models.
- Provides implementation patterns for real-time and batch fusion workflows.
- Details data preparation steps including timestamp conversion and handling of time gaps.
- Explains how to tune filter noise properties using both in-place and struct-based signatures.
- Offers guidance on visualizing tuning progress and extracting state estimates.
- Defines conventions for reference frames, orientation outputs, and sensor-specific properties.
When to use it
- When you need to fuse IMU, AHRS, INS, or GPS+IMU data for orientation or pose estimation.
- When choosing the right filter object from the MATLAB Navigation Toolbox for a specific sensor suite.
- When implementing or tuning a filter for real-time streaming or batch processing.
- When troubleshooting filter performance or tuning noise parameters.
Advantages
- Provides a clear decision tree for selecting the optimal filter for specific sensor combinations.
- Clarifies the distinction between different tuning signatures to prevent common implementation errors.
- Offers robust patterns for handling real-world data issues like non-uniform sample rates and time gaps.
- Centralizes configuration and reference frame conventions for multiple filter types.
Usage examples
- “How do I choose a filter for an IMU with accelerometer, gyroscope, and magnetometer?”
- The skill guides you to use ahrsfilter for orientation estimation, or insfilterMARG if you also require position and velocity output.
- “How do I tune the noise parameters for an insfilterMARG object?”
- It explains using the Signature B tuning pattern: call tunernoise(filt) to get the struct, update the noise fields, and pass it to the tune function.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/matlab/matlab-fuse-inertial-sensors/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip matlab-fuse-inertial-sensors.zip -d .agents/skills
Documentation by MathWorks
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
└──► insfilterErrorStateStep 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:
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):
if numel(unique(tSec)) < 2 || ~isfinite(fs)
fs = 100; % use the stated or datasheet rate
endTime 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.
gapThreshold = 5 / fs; % 5× the expected sample interval
gapIdx = find(diff(tSec) > gapThreshold);
segments = [1; gapIdx+1]; % start index of each segmentGroup 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 |
| Navigation filters | references/navigation-filters.md |
insEKF | references/insekf.md |
insCF | 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 manuallyinsCF— usegainparts(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").
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 and 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): theorientationFormatpositional arg is required before any name-value pairs —ecompass(a, m, 'quaternion', 'ReferenceFrame', 'ENU'). Omitting it errors: "Expected input number 3, FORMAT..."insEKF/insCF:ReferenceFrameis read-only after construction; set viainsOptions/insCFOptionsat construction time
Orientation output:
quaternionobject by default.GPS position input: LLA vector in degrees / degrees / meters.
Sample rate property:
imufilter,ahrsfilter,complementaryFilter:SampleRateahrs10filter,insfilterMARG,insfilterNonholonomic,insfilterErrorState:IMUSampleRateinsfilterAsync,insEKF,insCF: no sample rate property (sensors carry their own timestamps)
ReferenceLocation: must be set oninsfilterMARG,insfilterAsync,insfilterNonholonomic, andinsfilterErrorStatebefore the fusion loop. ForinsEKF/insCF, set it on theinsGPS/insCFGPSsensor 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.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.1 KiB
- LICENSELicence file added by AutoGineer1.4 KiB
- SKILL.md11.3 KiB
- manifest.yaml471 B
- references/attitude-filters.md7.9 KiB
- references/inscf.md4.5 KiB
- references/insekf.md12.6 KiB
- references/navigation-filters.md9.6 KiB
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
The author says: R2022a+
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- MathWorks
- Publisher
- MathWorks (Official)
- Source
- matlab/matlab-agentic-toolkit · skills-catalog/robotics-and-autonomous-systems/matlab-fuse-inertial-sensors · commit 2a7f215
- Licence
- BSD 2-Clause License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by MathWorks or MathWorks.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-fuse-inertial-sensors.zip