---
name: matlab/matlab-model-serdes-systems
source: https://app.decimal.ai/s/matlab-matlab-model-serdes-systems@1/SKILL.md
source_sha256: 4820d6ac75d6
---

# Modeling and Simulating SerDes Systems

Design, analyze, and deliver high-speed serial link models using SerDes Toolbox. From
architecture exploration through IBIS-AMI model generation, covers the full workflow
for NRZ and PAM-N links (PAM3 through PAM16).

## When to Use

**System design and architecture exploration**
- Designing SerDes links for a target data rate, signaling scheme (NRZ, PAM4, PAM-N), and channel loss
- Evaluating equalization architectures (FFE, CTLE, DFE) and optimizing tap settings
- Sweeping design parameters to find optimal configurations
- Using industry reference designs (PCIe, USB4, DDR5, CEI, UCIe) as starting points
- Characterizing Tx/Rx analog effects (parasitic capacitance, rise time, termination impedance)
- Building custom datapath blocks for nonstandard equalization

**Channel modeling and characterization**
- Loading S-parameter Touchstone files into SerdesSystem
- Modeling channels with loss profiles, crosstalk (FEXT/NEXT), and aggressors
- Fitting CTLE transfer functions from measured data via `ctlefit`

**IBIS-AMI model generation**
- Building IBIS-AMI models for Tx, Rx, Redriver, or Retimer configurations
- Exporting to Simulink, configuring AMI parameters, and compiling `.ami`/`.ibs`/`.dll`/`.so`
- Scripting Simulink simulations and parameter sweeps with `sim`/`parsim`

**Analysis and validation**
- Running statistical and time-domain simulations
- Processing eye diagrams (eye height, eye width, COM, VEC, bathtub curves)
- Decomposing jitter (TJ, RJ, DJ, DDJ, DCD, ISI)
- Validating compiled AMI models against behavioral baselines
- Running compliance checks with eye masks and jitter budgets

## When NOT to Use

- RF/microwave circuit design, antenna modeling, or baseband DSP filter design
- General Simulink model scripting unrelated to SerDes

## Must-Follow Rules

### System Setup
- **SymbolTime / SampleInterval must yield an integer SamplesPerSymbol** — fractional ratios cause silent errors
- **`TxModel`/`RxModel` are `Transmitter`/`Receiver` objects** — not cell arrays. Construct with `Transmitter('Blocks', {block1, block2})`. **`Transmitter` requires single-quoted property names** — `Transmitter("Blocks", ...)` throws an `ismember` error. `Receiver` and all other classes accept double quotes
- **Signal conversion functions require column vectors** — `impulse2pulse`, `pulse2stateye`, etc. error on row vectors
- **Include `AnalogModel` and `JitterAndNoise`** for realistic results — bare `Transmitter`/`Receiver` without analog models produce optimistic COM (1-2 dB higher). See `reference/equalization-tuning.md` for parameter guidance (rise time, parasitic C, termination R)

### Equalization
- **Set `WaveType` explicitly** when using datapath blocks directly in MATLAB — Simulink sets this automatically, but MATLAB defaults to `"Sample"`
- **Adapted DFE/CTLE parameters are in `results.outparams`** — NOT on the block object. After `analysis()`, `sys.RxModel.Blocks{k}.TapWeights` still holds initial values. In system objects chains, adapted taps are the **second output**: `[y, taps] = dfecdr(x)`
- **DFECDR Mode=0 is passthrough in Sample mode** — DFE only applies with Mode≥1. Pre-load adapted taps from `outparams` with Mode=1 for instant convergence, or use Mode=2 with 10x `EqualizationGain` (9.6e-04) for self-converging chains
- **Set `Modulation` on DFECDR for PAM-N** in system objects chains — Simulink inherits it from the model workspace, but MATLAB defaults to 2 (NRZ). Without this, PAM4 DFE adaptation fails silently

### Metrics and Waveforms
- **`Metrics.summary.EW` is in picoseconds** (already scaled) — do NOT multiply by 1e12. `EH` is in volts. PAM-N returns N-1 values per metric (e.g., PAM4 → 3 eyes, PAM8 → 7 eyes)
- **Channel impulse from `analysis()` is in V/s** — when using `filter()` for time-domain convolution, multiply by `dt`: `filter(impulse * dt, 1, wave)`. Without scaling, amplitudes blow up by ~10^11
- **`pulse2wave` operates on the stimulus provided** — the output modulation depends on the input pattern (NRZ or PAM-N)

### AMI and Simulink
- **Init-Only models cannot adapt** — if DFE taps or CDR converge at runtime, you need a Dual model (both Init and GetWave)
- **AMI validation requires Signal Integrity Toolbox** — `serdes.AMI` runner and the AMI Simulink block need both SerDes Toolbox and Signal Integrity Toolbox
- **AMI GetWave: call in a chunked loop** — `serdes.AMI` passes `BlockSize` (default 1024) to `AMI_GetWave`, so only `BlockSize` samples are processed per call. You **must** call the object in a `for` loop with `BlockSize`-length chunks. State is preserved between calls via the DLL memory handle
- **AMI GetWave: set `SkipFirstBlock = false`** when calling from MATLAB — the default (`true`) is for Simulink's internal signal buffering and causes the first block to pass through unprocessed
- **AMI Init: `RowSize` must match impulse length** — `serdes.AMI` crashes MATLAB (process termination, no error) if `RowSize` doesn't match `numel(impulse)`
- **AMI generation requires Simulink model** — use `IbisAmiManager` GUI or `serdes.AMIExport` with `export()` programmatically (see Programmatic AMI Generation)

## Workflow

### Design Exploration

Most projects start here. The goal is to find the right equalization architecture and settings for your channel.

1. **Design** — Create a `SerdesSystem` with Tx/Rx blocks and channel (loss model or S-parameters)
2. **Analyze** — Run `analysis` for statistical results, `plotStatEye` for eye diagrams, `analysisReport` for metrics
3. **Sweep** — Vary channel loss, FFE taps, CTLE gain, DFE taps, or jitter to map the design space
4. **Compare** — Evaluate architectures (FFE-only vs FFE+CTLE vs FFE+CTLE+DFE) using COM, eye height, eye width
5. **Select** — Choose the configuration that meets margin targets, then freeze equalization settings

Use `SerdesSystem` for programmatic exploration; `serdesDesigner` for interactive GUI work.

### Waveform Processing

When you have a captured or imported waveform (e.g., from an oscilloscope or simulation) and want to equalize and analyze it directly:

1. **Load** — Import the waveform and define timing (`SampleInterval`, `SymbolTime`)
2. **Equalize** — Stream through datapath blocks (FFE, CTLE, DFECDR) with `WaveType = "Sample"`
3. **Analyze** — Build an eye diagram with `eyeDiagramSI`, extract metrics (eye height, COM, VEC)
4. **Decompose jitter** — Run `jitter()` on the equalized waveform for TJ, RJ, DJ, DDJ, ISI breakdown

DFECDR and DFE require a sample-by-sample `for` loop in Sample mode; FFE and CTLE accept full vectors. See `reference/waveform-processing.md` for the Direct Equalization pattern.

### IBIS-AMI Model Delivery

When you need compiled models (.ami/.ibs/.dll/.so) for EDA tools or IP delivery:

1. **Export** — Call `exportToSimulink(sys)` to generate a Simulink model from the frozen design
2. **Configure** — Set AMI parameters, IBIS component/pin data, and model type via `IbisAmiManager` or `serdes.AMIExport`
3. **Generate** — Build `.ami`/`.ibs` and compile `.dll`/`.so` via `serdes.AMIExport` with `export()`
4. **Validate** — Load compiled DLL/SO with `serdes.AMI`, compare against behavioral reference (Init for impulse, GetWave for waveform)
5. **Cross-check** — The Simulink path (`sim` with Rx WaveOut) is the preferred time-domain reference. Compare against: statistical `analysis()`, system objects direct chain, and compiled AMI DLLs. See `reference/simulink-serdes-simulation.md`
6. **Iterate** — Fix discrepancies, re-export, re-validate until all paths agree

### AMI Model Types

Choose the model type based on which equalization blocks need to adapt at runtime:

| Type | Init_Returns_Impulse | GetWave_Exists | Use For |
|------|---------------------|----------------|---------|
| Init-Only | true | false | LTI equalization (fixed FFE, CTLE). Supports statistical analysis |
| GetWave-Only | false | true | Time-domain only. No statistical analysis |
| Dual | true | true | Adaptive equalization (DFE, CDR). All analysis types |

Every IBIS-AMI model implements `AMI_Init` (required), `AMI_GetWave` (optional), and `AMI_Close` (required) per the IBIS standard.

## Key Classes

| Class | Purpose |
|-------|---------|
| `SerdesSystem` | Top-level system. Methods: `analysis`, `plotStatEye`, `plotImpulse`, `plotPulse`, `plotAlignedPulse`, `plotWavePattern`, `analysisReport`, `exportToSimulink` |
| `Transmitter` | Tx container. Construct: `Transmitter('Blocks', {serdes.FFE(...)})` |
| `Receiver` | Rx container. Construct: `Receiver('Blocks', {serdes.CTLE(...), serdes.DFECDR(...)})` |
| `ChannelData` | Channel spec. Props: `ChannelLossdB`, `ChannelLossFreq` (**default 5 GHz — must override to Nyquist**), `ChannelDifferentialImpedance`, or `Impulse`/`dt` |
| `JitterAndNoise` | IBIS 7.0 jitter/noise. 4 groups: Tx jitter (Rj/Dj/DCD/Sj), Rx jitter, Rx clock recovery (5 params, active with `RxClockMode='clocked'`, `'convolved'`, or `'normal'`), Rx noise. Values in seconds (default) or UI. See `reference/serdes-api-reference.md` |
| `serdes.AMI` | Run compiled AMI DLLs/SOs. Call: `[waveOut, impulseOut] = ami(waveIn, impulseIn, clockIn)` |
| `serdes.AMIExport` | Programmatic AMI export (R2026a+). Methods: `export`, `getExportSettings`. Props: `ModelTypeTx`, `DLLFiles`, `LinuxCrossCompile` |
| `SParameterChannel` | S-parameter to impulse response. Handles `.s4p` through `.s16p` (multi-port returns Nx(K) matrix: col 1=thru, cols 2+=aggressors). Props: `FileName`, `SampleInterval`, `StopTime`, `PortOrder` |
| `eyeDiagramSI` | Waveform eye diagram (R2024a+). Step: `eyeObj(wave)` — no output. Metrics: `eyeHeight`, `eyeWidth`, `com`, `vec`, `margin` |
| `ctlefit` | CTLE pole/zero fitter. Import: `ctlefit.readcsv`. Output: `GPZ` matrix for `serdes.CTLE("Specification", "GPZ Matrix")` |

### Datapath Blocks

| Block | Role | Mode Values | Key Properties |
|-------|------|-------------|----------------|
| `serdes.FFE` | Feed-forward equalizer | 0, 1 | `TapWeights`, `TapSpacing`, `Normalize` |
| `serdes.CTLE` | Continuous-time linear EQ | 0, 1, 2 | `Specification`, `DCGain`, `ACGain`, `PeakingGain`, `GPZ` |
| `serdes.DFECDR` | DFE + clock recovery | 0, 1, 2 | `TapWeights`, `CDRMode`, `PhaseDetector`, `Count` |
| `serdes.DFE` | Standalone DFE | 0, 1, 2 | `TapWeights`, `EqualizationGain`, `EqualizationStep` |
| `serdes.CDR` | Standalone CDR | 0, 1 | `CDRMode`, `Count`, `Step`, `Sensitivity`. Mode is deprecated |
| `serdes.AGC` | Auto gain control | 0, 1 | `TargetRMSVoltage`, `MaxGain`, `AveragingLength` |
| `serdes.VGA` | Variable gain amplifier | 0, 1 | `Gain` |
| `serdes.SaturatingAmplifier` | Limiting amplifier | 0, 1 | `Limit`, `LinearGain`, `Specification` |
| `serdes.PassThrough` | No-op placeholder | — | — |

**Mode values:** 0 = Fixed (not exported), 1 = Fixed (exported as AMI parameter), 2 = Adaptive (GetWave). Only CTLE, DFECDR, and DFE support Mode=2.

Set CTLE `Specification` before setting gain properties — using `ACGain` with the default spec triggers a warning. **GPZ Matrix requires `Mode=1`** for `ConfigSelect` to switch rows. See `reference/equalization-tuning.md` for the 4 specification options.

## Patterns

Each reference file includes executable code patterns for its topic. Load the relevant reference before writing code — it contains correct calling conventions, constructor arguments, and property names. See the References table in Conventions below for the full routing map.

## Common Mistakes

See `reference/common-mistakes.md` for 37 documented anti-patterns with wrong/correct code pairs covering API misuse, wrong property names, silent failures, and performance pitfalls.

## Conventions

### Design

- Use `SerdesSystem` for programmatic design; `serdesDesigner` for interactive exploration. Always run `analysis`/`plotStatEye` before exporting
- **CRITICAL:** `ChannelLossFreq` defaults to 5 GHz — **always override** to Nyquist (`1/(2*SymbolTime)`). Without this, 15 dB at 5 GHz becomes 40+ dB at Nyquist and the eye appears closed. Use `SParameterChannel` for real channels
- `analysis()` does not auto-optimize FFE taps — use canonical de-emphasis with `sum(abs(taps)) ≈ 1.0`
- DFE taps initialized to zero are optimized by the statistical solver automatically
- Industry reference designs: `serdesDesigner` or `openExample('serdes/PCIe5TransmitterReceiverIBISAMIModelExample')`. See `reference/equalization-tuning.md` for starting-point configurations

### Visualization and Metrics

- All `SerdesSystem` plot methods (`plotStatEye`, `plotImpulse`, `plotPulse`, `plotAlignedPulse`, `plotWavePattern`) render into the current axes — use `tiledlayout`/`nexttile` or `subplot` for multi-panel layouts
- `eyeDiagramSI` (R2024a+) for waveform eye diagrams; `jitter` (R2024b+) for jitter decomposition
- DFECDR/DFE in `"Sample"` WaveType require scalar (sample-by-sample) input; FFE/CTLE accept full vectors
- When generating PRBS waveforms via `pulse2wave`, ask the user for PRBS order and symbol count — default PRBS-10 (1023 symbols) if unspecified
- Use `serdes.utilities.SignalIntegrityColorMap` (not `hot`/`parula`) for `pulse2stateye` plots. For compliance, use `margin(eyeObj, eyeMask)`
- See `reference/visualization-and-metrics.md` for all plot methods, metrics fields/units, eyeDiagramSI, and jitter

### AMI Export and Validation

- Use `serdes.AMIExport` with `export()` for programmatic AMI generation — not `slbuild` (legacy, R2025b and earlier only)
- Validate compiled DLLs/SOs with `serdes.AMI` before sending to EDA tools — both Init (impulse correlation) and GetWave (waveform chain)
- **Simulink is the preferred time-domain path** — `sim()` with Rx WaveOut is the ground truth for adaptive systems. Compare against system objects chain and compiled AMI DLLs as cross-checks. Use the same PRBS stimulus across all time-domain paths
- AMI export parameters on Simulink blocks use `*AMI` suffix (`'ModeAMI'`, `'TapWeightsAMI'`); model-level settings go through `IbisAmiManager` or `serdes.AMIExport`
- No compiled DLLs/SOs ship with the toolbox. Cross-compile for Linux `.so` via `serdes.utilities.createCrossCompiler`

### Script-First Workflow

For design, analysis, or sweep tasks — write code to `.m` files on disk, not inline MCP snippets. For quick one-off checks, inline `evaluate_matlab_code` is fine.

1. **Create** a `.m` file (e.g., `serdes_pam4_design.m`), **run** via `run_matlab_file`, **iterate** by editing and re-running
2. **Deliver** a polished script — `%% Parameters` block at top, `%% Section` headers, summary `fprintf` at end

### References

| Load when... | Reference |
|-------------|-----------|
| Building or modifying a `SerdesSystem` | `reference/serdes-api-reference.md` |
| Debugging wrong API names or silent failures | `reference/common-mistakes.md` |
| Working with S-parameter files or crosstalk | `reference/channel-modeling.md` |
| Tuning CTLE, FFE, DFE, or fitting transfer functions | `reference/equalization-tuning.md` |
| Sweeping parameters or running GA optimization | `reference/optimization.md` |
| Plotting eyes, reading metrics, or decomposing jitter | `reference/visualization-and-metrics.md` |
| Equalizing captured or imported waveforms directly | `reference/waveform-processing.md` |
| Exporting to Simulink, compiling AMI DLLs, or validating AMI models | `reference/programmatic-ami-generation.md` |
| Scripting Simulink simulations or `parsim` sweeps | `reference/simulink-serdes-simulation.md` |
| Building custom datapath blocks | `reference/custom-datapath-blocks.md` |
| Looking up utility functions (SNR, ICN, resample) | `reference/serdes-utilities.md` |

----

Copyright 2026 The MathWorks, Inc.
----