Skills DirectorySearch all skills ↗

AI agent skill · by @matlab

Simulink Instrument Real Time Application

Set up signal capture for a Simulink Real-Time application using `slrealtime.Instrument`. Use when choosing which signals a real-time application captures and where the data goes — test-pointing or canvas-badging a signal before build (`TestPoint`, `DataLogging`), constructing an Instrument from an `.mldatx`, calling `addSignal`, `addInstrumentedSignals`, `addFileLogSignals`, `validate`, `connectCallback`, `copy`, or `generateScript`, attaching an instrument to `tg.Instruments` via `addForFileLog`, `addForSDI`, or `addForMATLAB`, setting up live-streaming signals, dynamic file-log workflows, or persisting an instrument as M-code. Selects and routes signals only — not for configuring, building, running, or connecting applications onto targets.

Archived 2026-10-23 · Source updated 2026-10-07. Check the original repository for the latest version.

SKILL.md instructions

# Instrumenting Simulink Real-Time Applications

Use this skill to **set up signal capture** for a Simulink Real-Time application via
`slrealtime.Instrument` — a runtime-configurable object that attaches to a target computer to
stream, visualize, or file-log data from a running application. Instruments are **dynamic**: they
are not stored in the SLX, and `generateScript(inst)` is the canonical persistence path.

> **Release compatibility:** designed and validated for MATLAB R2026a and later. The
> `addForFileLog`/`addForSDI`/`addForMATLAB` bucket API was introduced in R2026a. For earlier
> releases, use that release's documentation.

## When to Use

- Setting up signal capture for a Simulink Real-Time application via `slrealtime.Instrument`
- Test-pointing or badging signals **before build** so they survive code-gen and are picked up by
  `addInstrumentedSignals()`
- Adding signals by label, block path + port, block path + state name, or canvas badge
- Choosing a destination and attaching to the target (`addForFileLog`/`addForSDI`/`addForMATLAB`)
- Validating an instrument against an `.mldatx`, or configuring callback-driven MATLAB delivery
- Persisting an instrument as M-code, or detaching instruments from the target

## When NOT to Use

If the task crosses one of these lines, **load the named skill first**, then come back.

- Target IP, credentials, RTOS, `connect(tg)` troubleshooting, `status(tg)`, `reboot(tg)` →
  `simulink-configure-real-time-target`
- Model STF, fixed-step solver, Simulink Real-Time options → `simulink-configure-real-time-model`
  (`SLRTFileLogMaxRuns` only caps retained runs; it selects no signals)
- `slbuild`, `load(tg, app)`, `start`, `stop`, `tg.Stimulation`, `getparam`/`setparam`,
  `startRecording`/`stopRecording`, `import(tg.FileLog, app)`, `slrealtime.exportRun` →
  `simulink-run-real-time-application`. This skill picks *which* signals and *where*; it never
  starts or stops capture.
- UI binding (`connectScalar`, `connectLine`, `connectXYPlot`) — the App Designer path, not this
  skill

## Prerequisites

- MATLAB **R2026a or newer**, with Simulink Real-Time installed (`ver` lists it)
- Support package for the hardware: **Speedgoat** → Speedgoat Add-On; **Linux x86-64 devices** →
  Embedded Coder Support Package for Real-Time Linux (requires Embedded Coder)
- Model configured for Simulink Real-Time and a fresh `.mldatx` in the build folder
- A configured, reachable target computer

## API Forms

Use **only** the forms in `references/instrument-api.md` § API Signature Reference (instrument
methods, `addSignal` shapes, model-tool calls for canvas prep) and `references/destinations.md`
(bucket methods on `tg.Instruments`). Anything else is invented — the Never table in Guardrails
lists the forms agents produce most often. `addSignal` takes only two Name-Value parameters,
`Decimation` and `BusElement`; the settable properties are `Name`, `Enable`, `AxesTimeSpan`, and
`AxesTimeSpanOverrun`.

## Workflow

Steps 1–4 happen **before** `slbuild` when the canvas must change. Steps 5–11 happen after build.
The run itself is owned by `simulink-run-real-time-application`.

### 1. Identify the Signals to Capture

Decide what to log and which `addSignal` shape expresses it: signal label, block path + outport
index, or block path + state name. If the user gave a block path but no port, use `model_read` to
list the block's output ports and show them.

- **Bus leaf — Ask First.** Gate only when the user wants a leaf *inside* a bus, uses
  `BusElement`, names a Bus Selector path as a leaf source, or asks for "one element" of a bus.
  Whole-bus streaming is **not** gated. Present both remedies from `references/bus-elements.md` —
  convert the source bus to non-virtual and rebuild, or instrument the upstream leaf — and **wait
  for the user to choose**. Probing virtuality is not a substitute for asking.
- **Array of buses:** prefix `BusElement` with `(N).` (1-based). If the user named the element,
  format it directly (`"(2).signal1.signal2"`); otherwise add the leaf path alone, and on
  `BusElementRequiresDims` / `BusElementInvalidDims` **remove the signal**, surface the warning,
  and ask which element. Never guess an index.
- **Cannot be logged by name:** optimized-away signals (fix: test-point, Step 3), complex or
  multiword types (hard limit), source blocks named only with spaces, and `BusElement` on a
  virtual bus. `validate` only **warns**, and `generateScript` still emits the signal — silence is
  not success.
- **Conditional and Iteration subsystems:** the instrument logs **post-step**, so it produces
  wrong data when gating or per-iteration values matter. Use a **File Log block** instead (model
  edit, rebuild — Ask First).

Details: `references/instrument-api.md`, `references/bus-elements.md`.

### 2. Decide the Destination

Each instrument attaches to **one** of three buckets:

| Destination | Use when |
|---|---|
| File log (`addForFileLog`) | Target-side capture for **post-run analysis**, high-rate or long runs, or no development computer attached |
| SDI (`addForSDI`) | **Live operator monitoring** in the Simulation Data Inspector |
| MATLAB (`addForMATLAB`) | **Custom MATLAB code** reacting to samples via a callback |

Decision tree, per-bucket constraints, and the "stream that signal" disambiguation:
`references/destinations.md`.

### 3. Prep the Signal on the Canvas — Before Build (Ask First)

Get block IDs from `model_read`, then set both signal properties in one `model_edit` `configure`
on the **signal** (`blk_X.yN -> blk_Y.uM`); verify with `model_query_params`:

- **`TestPoint: "on"`** — for any signal that *might* be optimized out and will be added by name
  or block path.
- **`DataLogging: "on"`** — for the canvas badge, `addInstrumentedSignals()` pickup, or the
  default SDI instrument.

Both are model edits: ask first, and say that a save and rebuild are needed. There is no rescuing
an optimized-out signal after build. Payload, outport-without-destination exception, and
`DataLoggingSampleTime`: `references/canvas-prep.md`.

### 4. Build the Application (route)

Building is owned by `simulink-run-real-time-application` (`slbuild(model)`). The resulting
`.mldatx` is what the instrument validates against.

### 5. Construct the Instrument

```matlab
inst = slrealtime.Instrument("myModel.mldatx");
inst.Name = "TargetInstrument";
```

Construct one when the user wants a controlled destination, a manual signal list, dynamic file
logging, MATLAB delivery, or to suppress the transient default SDI instrument that otherwise
streams `DataLogging`-badged signals at `start(tg)` (`references/destinations.md`).

### 6. Add Signals

```matlab
addSignal(inst, "SigGen");
addSignal(inst, "myModel/Gain", 1, "Decimation", 10);
addSignal(inst, "myModel/Integrator", "x");
```

`Decimation` is an **integer `1`–`256`**, default 1; anything else errors. State it explicitly when
set.

Bulk-add finds **different** things: `addInstrumentedSignals(inst)` takes streaming-badged
signals, `addFileLogSignals(inst)` takes signals wired to File Log blocks. Both return nothing and
silently add nothing on a mismatch — confirm which the model contains, and check the result by
counting `addSignal` lines in `generateScript(inst)` (`references/instrument-api.md` § Bulk-Add).

### 7. Set Capture Options

Set `Name`, `Enable`, `AxesTimeSpan`, or `AxesTimeSpanOverrun` as needed
(`references/instrument-api.md` § Public Properties). For MATLAB delivery, register the callback
now — **before** attaching:

```matlab
connectCallback(inst, @onData);

function onData(srcInst, evt)
    [t, d] = getCallbackDataForSignal(srcInst, evt, "SigGen");
end
```

### 8. Attach to `tg.Instruments`

```matlab
tg = slrealtime;
connect(tg);
addForFileLog(tg.Instruments, inst);    % or addForSDI / addForMATLAB
```

Once attached the instrument is **locked** — detach, edit, re-attach. SDI and MATLAB instruments
can attach while the application runs. A file-log instrument can too, but **only while recording
is inactive**: route `stopRecording(tg)` / attach / `startRecording(tg)` to
`simulink-run-real-time-application`, and surface the recording gap first
(`references/destinations.md`).

### 9. Hand Off to the Run Lifecycle

`load(tg, app)` and `start(tg, ...)` belong to `simulink-run-real-time-application`. Capture is
automatic while the application runs; tell the user where the data lands
(`references/destinations.md` § Where the Data Appears).

### 10. Persist the Instrument as an M-Script

```matlab
txt = generateScript(inst);
writelines(txt, "createMyInstrument.m");
```

The script is bound to **this build**: after a model rebuild, reconstruct and re-`validate` the
instrument against the fresh `.mldatx`. To keep only SDI streaming choices with the model,
`DataLogging` badges are the saved-model alternative.

### 11. Tear Down

```matlab
removeForFileLog(tg.Instruments, inst);   % one instrument
removeAllForFileLog(tg.Instruments);      % every instrument in the bucket — Ask First
```

## Verification

```matlab
unavail = validate(inst, "myModel.mldatx");
disp(getAllForFileLog(tg.Instruments));   % or getAllForSDI / getAllForMATLAB
```

`validate` returns a fresh instrument holding the signals that **could not** be resolved. Empty
means everything resolved; anything listed is missing from the build — usually a missing
test-point.

## Guardrails

`references/guardrails.md` carries the reasoning behind each rule, the silent-wrong-data traps,
and the hard limits.

**Always:**

- Tell the user the instrument's **workspace variable name and where it was created** (e.g.
  "created in the base workspace as `inst`").
- Apply `TestPoint` and canvas badges **before** `slbuild`.
- Run `validate(inst, mldatx)` before attaching and surface unresolved signals.
- Pick **one** destination per instrument.
- Save constructed instruments with `generateScript()`.
- State `Decimation` explicitly when set — the default of 1 is otherwise silent.
- Reconstruct and re-`validate` the instrument after any model rebuild.

**Ask first:**

- **Bus-leaf capture** — any `BusElement` use, "log one element of this bus", or a Bus Selector
  path naming a leaf. Present **both** remedies and wait. Whole-bus streaming is not gated.
- Setting `TestPoint` or `DataLogging` on a signal — model edits needing a rebuild.
- `removeAllForFileLog` / `removeAllForSDI` / `removeAllForMATLAB` — affects every attached
  instrument, not just the user's.
- Hundreds of high-rate signals — warn about target CPU/SSD for file logging, network and
  development-computer load for streaming.
- Reconfiguring an attached instrument — it is locked; detach first.
- Attaching a file-log instrument to a running application — surface the recording gap.

**Never invent** function names, properties, Name-Value parameters, or destination methods. Every
left-hand form below is a hallucination agents produce regularly — refuse it and use the
right-hand column.

| Never | Use instead |
|---|---|
| `inst.attach(tg, "filelog")` | `addForFileLog(tg.Instruments, inst)` / `addForSDI` / `addForMATLAB` |
| `inst.signals.add("Sig")` | `addSignal(inst, "Sig")` |
| `inst.start()` / `inst.stop()` | Capture begins with the **application** (`start(tg, ...)`) or with `startRecording` |
| `inst.record()` / `inst.capture()` | Attach to a bucket; capture is automatic |
| `inst.getData()` / `inst.read()` | `connectCallback(inst, @onData)` + `getCallbackDataForSignal` |
| `inst.save()` / `inst.export()` | `generateScript(inst)` + `writelines` |
| `addSignal(..., "SampleRate"/"Period"/"RateLimit", N)` | `Decimation` (integer 1–256), or `DataLoggingSampleTime` on the model |
| `set_param(..., "TestPoint"/"DataLogging", "on")` | `model_edit` → `configure` on the signal `blk_X.yN -> blk_Y.uM` |
| `Simulink.sdi.markSignalForStreaming(port, "on")` | `model_edit` → `configure` with `DataLogging: "on"` |
| Bus-expansion or bulk-add helpers for buses | Add leaves individually — see `references/bus-elements.md` |

`addInstrument` / `removeInstrument` / `getAllInstruments` are **real** target functions, but they
belong to the App Designer / UI-connector path. This skill uses the bucket API. Do not mix the two.

**Also never:**

- Try to rescue an optimized-out signal after build — test-point and rebuild instead.
- Use `BusElement` or capture a bus leaf without the Ask-First gate above.
- Guess an array index for an array-of-buses signal.
- Use `slrealtime.Instrument` for a signal inside a Conditional or Iteration subsystem when gating
  or per-iteration values matter — use a **File Log block**.
- Modify a locked instrument's signal list, or attach one instrument to two buckets.
- Conflate `addInstrumentedSignals()` with `addFileLogSignals()`.
- Embed instrument logic in the SLX — use `generateScript()`.

----

Copyright 2026 The MathWorks, Inc.

----

Related skills