Run high-accuracy time-domain simulation on an RF signal chain using the rfsystem System Object. Under the hood, rfsystem auto-generates and manages a Simulink/RF Blockset model -- the user works entirely in MATLAB with the standard System Object step/reset/release interface.
When to Use
- Running circuit envelope or idealized baseband time-domain simulation on an rfbudget chain
- Streaming time-domain data through an RF system for EVM, power, or spectral analysis
- Modeling MISO receivers or SIMO transmitters
- Inspecting auto-generated RF Blockset Simulink models
- Comparing Friis/HarmonicBalance budget results against full time-domain simulation
When NOT to Use
- Cascade budget analysis (gain, NF, IP3) without time-domain -- use
matlab-analyze-rf-budget - Standalone baseband signal processing without Simulink -- use
matlab-process-rf-baseband - Frequency-domain S-parameter analysis -- use
matlab-manage-sparameters - Building circuit topologies from R/L/C elements -- use
matlab-compose-rf-circuit
Workflow
- Build rfbudget -- Define the RF chain (see
matlab-analyze-rf-budgetandmatlab-create-rfbudget-elementsskills) - Create rfsystem -- Pass the rfbudget to
rfsystemwith desired library and options - Stream data -- Call
rfs(in)repeatedly with frame-sized input vectors - Analyze output -- Measure power, EVM, spectrum, etc. on the time-domain output
- Clean up --
release(rfs)thenclose_system(rfs, 0)
Creating an rfsystem
% Build an rfbudget first
lna = amplifier('Gain', 15, 'NF', 2, 'OIP3', 35, 'Name', 'LNA');
mix = modulator('Gain', -6, 'NF', 10, 'OIP3', 20, ...
'LO', 2.1e9, 'ConverterType', 'Down', 'Name', 'Mixer');
ifAmp = amplifier('Gain', 20, 'NF', 4, 'OIP3', 30, 'Name', 'IFAmp');
b = rfbudget([lna mix ifAmp], 2.4e9, -30, 10e6);
% Create rfsystem (default: CircuitEnvelope)
rfs = rfsystem(b);
% With options
rfs = rfsystem(b, ...
ModelName='MyReceiver', ...
Library='CircuitEnvelope', ...
SampleTime=1e-8);
Constructor: rfsystem(rfbudget, Name=Value)
Properties
| Property | Default | Description |
|---|---|---|
ModelName |
'untitled' |
Name of auto-generated Simulink model |
SampleTime |
1/(bw*8) |
Time step for simulation (seconds) |
InputFrequency |
from budget | Row vector of input carrier frequencies (Hz) |
OutputFrequency |
from budget | Row vector of output carrier frequencies (Hz) |
RFInputs |
from budget | Number of RF inputs (read-only) |
RFOutputs |
from budget | Number of RF outputs (read-only) |
Library |
'CircuitEnvelope' |
'CircuitEnvelope' or 'IdealizedBaseband' |
Rx |
1 | Number of input chains (MISO receiver) |
Tx |
1 | Number of output chains (SIMO transmitter) |
SLInputs |
0 | Number of extra Simulink input ports |
SLOutputs |
0 | Number of extra Simulink output ports |
Mismatch |
false | Model impedance mismatch loss (IdealizedBaseband only) |
Library Modes
rfsystem supports two modes. RF Blockset itself supports a third (Equivalent Baseband) that is accessible only from the Simulink model generated by exportRFBlockset(b). Both IdealizedBaseband and Equivalent Baseband process complex baseband signals and model nonlinear compression; CircuitEnvelope additionally resolves multi-carrier and mismatch effects. The legacy rfckt analysis workflow (analyze) is equivalent baseband under the hood.
CircuitEnvelope (Default)
Full RF Blockset circuit envelope simulation. Supports all rfbudget element types and provides the highest accuracy -- accounts for nonlinear compression, intermodulation, impedance mismatch, and multi-carrier effects.
rfs = rfsystem(b, Library='CircuitEnvelope');
Supported elements: amplifier, modulator, rffilter, nport, rfelement, attenuator, phaseshift, seriesRLC, shuntRLC, lcladder, mixerIMT.
IdealizedBaseband
Faster simulation using idealized complex baseband models. More restrictive on element types but significantly faster for large signal chains.
rfs = rfsystem(b, Library='IdealizedBaseband');
Supported elements: amplifier, modulator, rffilter, nport only.
Gotcha: IdealizedBaseband rejects rfelement, attenuator, phaseshift, seriesRLC, shuntRLC, lcladder, mixerIMT, and rfantenna with "Expected elements in rfobj to be one of these types: amplifier, modulator, rffilter, nport." Replace unsupported elements or use CircuitEnvelope.
Mismatch Loss
rfs = rfsystem(b, Library='IdealizedBaseband', Mismatch=true);
Gotcha: Mismatch=true only works with IdealizedBaseband. Using it with CircuitEnvelope errors.
Running Simulation (step)
The rfsystem object follows the standard System Object streaming pattern: call rfs(in) repeatedly with frame-sized input vectors.
rfs = rfsystem(b);
Ts = rfs.SampleTime;
% Input: complex baseband envelope at InputFrequency
% Power scaling: Vin = sqrt(2 * Z0 * Pin_W) for a 50-ohm system
Pin_dBm = -30;
Pin_W = 10^((Pin_dBm - 30) / 10);
Vin = sqrt(2 * 50 * Pin_W);
% Single frame
nSamples = 100;
inSig = Vin * ones(nSamples, 1); % CW tone
out = rfs(inSig);
% Measure output power
Pout_dBm = 10*log10(mean(abs(out).^2 / (2*50))) + 30;
fprintf('Output: %.2f dBm\n', Pout_dBm);
Multi-Frame Streaming
Call step repeatedly -- the system accumulates state across frames:
nFrames = 10;
frameLen = 256;
allOut = zeros(frameLen * nFrames, 1);
for k = 1:nFrames
inFrame = Vin * randn(frameLen, 1) + 1j * Vin * randn(frameLen, 1);
outFrame = rfs(inFrame);
allOut((k-1)*frameLen + (1:frameLen)) = outFrame;
end
Modulated Signal Example
% QPSK signal through receiver chain
rng(42);
nSym = 1000;
symbols = (2*randi([0 1], nSym, 1) - 1) + 1j*(2*randi([0 1], nSym, 1) - 1);
inMod = Vin * symbols / sqrt(2);
outMod = rfs(inMod);
Pout = 10*log10(mean(abs(outMod).^2 / (2*50))) + 30;
fprintf('Modulated output: %.2f dBm\n', Pout);
Zero-IF (Direct Conversion)
When the rfbudget output frequency is 0 Hz (fRF = fLO), the output splits into separate I and Q components. The RFOutputs property becomes 2.
% Direct-conversion receiver: fRF = fLO
lna = amplifier('Gain', 15, 'NF', 2, 'OIP3', 35, 'Name', 'LNA');
mix = modulator('Gain', -6, 'NF', 10, 'OIP3', 20, ...
'LO', 2.4e9, 'ConverterType', 'Down', 'Name', 'Mixer');
ifAmp = amplifier('Gain', 20, 'NF', 4, 'OIP3', 30, 'Name', 'IFAmp');
b = rfbudget([lna mix ifAmp], 2.4e9, -30, 10e6);
rfs = rfsystem(b);
fprintf('RFOutputs: %d\n', rfs.RFOutputs); % 2 (I and Q)
% Step returns separate I and Q
[outI, outQ] = rfs(inSig);
outComplex = outI + 1j * outQ; % Reconstruct complex baseband
Gotcha: When OutputFrequency is 0, RFOutputs becomes 2 and the step method returns two output arguments (I and Q). Using a single output out = rfs(in) gives only the I component.
MISO Receiver and SIMO Transmitter
MISO Receiver (Multiple Inputs, Single Output)
rfs = rfsystem(b, Rx=2);
fprintf('RFInputs: %d\n', rfs.RFInputs); % 2
% Two RF inputs combined into one output
out = rfs(in1, in2);
SIMO Transmitter (Single Input, Multiple Outputs)
% Up-conversion transmitter chain
upMix = modulator('Gain', -6, 'NF', 10, 'OIP3', 20, ...
'LO', 2.1e9, 'ConverterType', 'Up', 'Name', 'UpMixer');
pa = amplifier('Gain', 25, 'NF', 5, 'OIP3', 40, 'Name', 'PA');
bTx = rfbudget([upMix pa], 0.3e9, -10, 10e6);
rfsTx = rfsystem(bTx, Tx=2);
fprintf('RFOutputs: %d\n', rfsTx.RFOutputs); % 2
[out1, out2] = rfsTx(inSig);
Simulink I/O Ports (SLInputs / SLOutputs)
Add extra Simulink ports for control signals or monitoring:
rfs = rfsystem(b, SLInputs=1, SLOutputs=1);
% Step with RF input and Simulink control input
[outRF, outSL] = rfs(inRF, inSL);
System Object Lifecycle
reset -- Clear Internal State
Restarts simulation clock to t=0 (clears operating point). Can call step again immediately without unlocking properties:
reset(rfs);
out = rfs(newInput); % Fresh simulation from t=0
release -- Allow Property Changes
Unlocks properties for modification. After release, SampleTime, InputFrequency, etc. can be changed:
release(rfs);
rfs.SampleTime = 5e-9; % Change sample time
out = rfs(newInput); % Re-runs setup on next step
Summary: reset = restart clock, release = unlock properties.
Gotcha: Properties are locked while the system is in use (between first step and release). Attempting to set a property without calling release first errors.
Model Management
The auto-generated Simulink model can be inspected, modified, and saved:
rfs = rfsystem(b, ModelName='MyReceiver');
load_system(rfs); % Load model into memory (no GUI)
open_system(rfs); % Open model in Simulink editor
hide_system(rfs); % Hide model window
save_system(rfs); % Save model to disk
save_system(rfs, 'NewName');% Save with new name
close_system(rfs, 0); % Close without saving (0 = discard changes)
close_system(rfs, 1); % Close and save
Gotcha: close_system(rfs) with no second argument errors if the model has unsaved changes: "Unable to close the model because it has been changed." Always use close_system(rfs, 0) to discard or close_system(rfs, 1) to save.
Inspecting the Model
load_system(rfs);
blocks = find_system(rfs.ModelName, 'Type', 'Block');
for k = 1:numel(blocks)
fprintf('%s\n', blocks{k});
end
The model contains RF Blockset blocks corresponding to each rfbudget element, plus Inport/Outport blocks for the RF and Simulink I/O.
rfBudgetAnalyzer
Open the RF Budget Analyzer app pre-loaded with the rfsystem's budget:
rfBudgetAnalyzer(rfs);
SampleTime Selection
Default: 1 / (rfbudget.SignalBandwidth * 8) -- 8 samples per signal bandwidth period. Decrease for higher time resolution; increase for faster simulation.
rfs = rfsystem(b, SampleTime=1e-9); % 1 ns time step
Element Compatibility Summary
| Element | CircuitEnvelope | IdealizedBaseband |
|---|---|---|
| amplifier | Yes | Yes |
| modulator | Yes | Yes |
| rffilter | Yes | Yes |
| nport | Yes | Yes |
| rfelement | Yes | No |
| attenuator | Yes | No |
| phaseshift | Yes | No |
| seriesRLC | Yes | No |
| shuntRLC | Yes | No |
| lcladder | Yes | No |
| mixerIMT | Yes | No |
| rfantenna | No | No |
Gotchas
- Requires rfbudget --
rfsystemtakes anrfbudgetobject, not raw elements or a circuit. Build the budget first. - close_system needs save flag --
close_system(rfs)errors on unsaved models. Useclose_system(rfs, 0)to discard changes. - IdealizedBaseband element restrictions -- Only amplifier, modulator, rffilter, nport. Other types error at construction.
- Mismatch only with IdealizedBaseband --
Mismatch=trueerrors with CircuitEnvelope. - Zero-IF splits I/Q -- When OutputFrequency=0,
RFOutputsbecomes 2 and step returns[I, Q]not a single complex output. - rfantenna not supported -- Neither library mode supports rfantenna in the chain.
- Properties locked during use -- Cannot change SampleTime, InputFrequency, etc. between step calls. Call
release(rfs)first. - SampleTime default is bandwidth-derived --
1/(SignalBandwidth*8). For wideband signals, this can produce very small time steps and slow simulation. - Simulink license required -- rfsystem requires a Simulink license even though the user never sees Simulink directly.
- ModelName must be valid -- Must be a valid Simulink model name (valid MATLAB identifier, no spaces).
- Element Name must be a valid variable name --
'IF Filter'errors with "not valid variable names." Use'IFFilter'or'IF_Filter'(no spaces, no special characters). This applies to all rfbudget elementNameproperties. - Clone elements before reusing in a second rfbudget -- An element object can only belong to one
rfbudgetat a time. Reusing it errors with "Element is already in another rfbudget." Useclone(element)to create an independent copy for each budget.
Conventions
- Use
tiledlayout/nexttilefor multi-panel time-domain and spectral plots - Always label axes with units (dBm, ns, MHz) and include figure titles
- Call
close_system(rfs, 0)in cleanup to avoid orphaned Simulink models - Compare rfsystem output against rfbudget Friis results to quantify nonlinear effects -- deltas of 0.5-2 dB are normal at backed-off power levels due to compression; larger deltas indicate operation near saturation
Copyright 2026 The MathWorks, Inc.