User manual › Control systems in the command window
kind: manual#console#control-systems#transfer-function#state-space#lti#manual

Control systems in the command window#

Every name on this page is typed at the command window (or passed to ICoreBlocks --console "<line>") and answers what MATLAB's Control System Toolbox answers for the same arguments. A model is a VALUE here — it goes into a variable, it does arithmetic, it prints the way MATLAB prints it — so analysis and design code written for MATLAB should paste in and run.

>>> G = tf([1], [1, 2, 5])
G = 
        1
  -------------
  s^2 + 2 s + 5
Continuous-time transfer function.  # Transfer Function

Three model kinds cross: tf and zpk are SISO, ss may be MIMO. A discrete model carries its own sample time and every verb that has a time base reads it from the model rather than from an argument.

The families, and what to reach for#

You want toUse
Build a modeltf(num, den[, Ts]), tf('s'), tf('z', Ts), ss(A, B, C, D[, Ts]), zpk(z, p, k[, Ts]), and each of them on another model to convert
Read a model back outtfdata(sys, "v"), zpkdata(sys, "v"), ssdata(sys), G.num, G.den, G.Ts, sys.A … sys.D
Combine models*, +, -, /, inv, ', ^, and series, parallel, feedback(G, H[, sign]), append, connect
Ask what a model ISpole, zero, damp, dcgain, isstable, order, isct, isdt, isproper, issiso, size
Simplify or re-coordinateminreal, canon, ss2ss, balreal, modred
Change time basec2d(sys, Ts[, method]), d2c, d2d
Simulatestep, impulse, lsim(sys, u, t[, x0]), initial(sys, x0), gensig
Measure a responsestepinfo, covar(sys, W) for the stationary covariance under white noise
Look at frequencybode, bodemag, nyquist, nichols, sigma, freqresp, evalfr, margin, bandwidth, getPeakGain, norm
Look at the rootspzmap, rlocus(sys, k), sgrid, zgrid
Design a controllerplace, acker, lqr, dlqr, lqi, lqry, pid, pidstd, pidtune, pidtuneOptions("PhaseMargin", d)
Design an estimatorkalman, lqe, estim, reg
Solve the matrix equationslyap, dlyap, care, dare, icare, idare, gram, ctrb, obsv, ctrbf, obsvf
Handle a delaypade(tau, n), sys.InputDelay, sys.OutputDelay, totaldelay, absorbDelay

A worked line or two#

A second-order plant, its factored form, and its poles with damping:

>>> G = tf(1, [1 2 5]); zpk(G)
        1
  --------------
  (s^2 + 2s + 5)
Continuous-time zero/pole/gain model.  # Zero Pole Gain

>>> G = tf(1, [1 2 5]); [wn, zeta, p] = damp(G)
wn = [[2.23607], [2.23607]]  # Matrix of Double
zeta = [[0.447214], [0.447214]]  # Matrix of Double
p = [-1 + 2i; -1 - 2i]  # Matrix of Complex

Its step response on a grid you choose, and the response measured:

>>> G = tf(1, [1 2 5]); [y, t] = step(G, 0:0.5:3); y'
[[0, 0.0834202, 0.197167, 0.241031, 0.227934, 0.203214, 0.19183]]  # Matrix of Double

>>> G = tf(1, [1 2 5]); s = stepinfo(G); [s.RiseTime, s.SettlingTime, s.Overshoot]
[[0.690343, 3.73522, 20.7866]]  # Matrix of Double

Feedback, discretization, and the stability margins of a loop:

>>> G = tf(1,[1 2 5]); feedback(G, 1)
        1
  -------------
  s^2 + 2 s + 6
Continuous-time transfer function.  # Transfer Function

>>> G = tf(1, [1 2 5]); c2d(G, 0.1, "tustin")
  0.002247 z^2 + 0.004494 z + 0.002247
  ------------------------------------
         z^2 - 1.775 z + 0.8202
Sample time: 0.1 seconds
Discrete-time transfer function.  # Transfer Function

>>> L = tf(1, [1 2 5 0]); [Gm, Pm, Wcg, Wcp] = margin(L)
Gm = 10  # Double
Pm = 85.3667  # Double
Wcg = 2.23607  # Double
Wcp = 0.20097  # Double

State feedback, two ways:

>>> A = [0 1; -5 -2]; B = [0; 1]; K = place(A, B, [-3, -4])
K = [[7, 5]]  # Matrix of Double

>>> lqr([0 1; -5 -2], [0; 1], eye(2), 1)
[[0.0990195, 0.279921]]  # Matrix of Double

Every transcript on this page is real output, captured with ICoreBlocks --console "<line>" on 2026-09-05 at commit bd974745.

Nine things that surprise people#

  1. tfdata's numerator is LEFT-PADDED to the denominator's length. tfdata(tf([1 3],[1 2 5]), "v") is [0 1 3], not [1 3] — so numel(num) == numel(den) always, and indexing from the front lands on a zero. And its third output Ts is 0 for a continuous model, which is MATLAB's convention.

    `` >>> tfdata(tf([1 3],[1 2 5]), "v") [[0, 1, 3]] # Matrix of Double ``

  2. A zpk's zeros and poles are the numbers you PUT IN, not the roots of the polynomial they multiply out to. That is what makes a zpk survive being stored and multiplied. Arithmetic on a zpk answers a zpk — H*2, H+1, inv(H), H^2 and H*tf(1,[1 1]) in either order — exactly as MATLAB's does; tf(H) and ss(H) convert.
  3. The bare step(sys) picks its own horizon, and MATLAB's is longer. The step SIZE is the same on both sides; the final TIME comes from a settling detection that ships compiled in MATLAB, so MATLAB simply runs further. step(sys, Tfinal) and step(sys, t) — where you name the horizon — agree digit for digit. If you are comparing against MATLAB, name the grid.
  4. A DISCRETE impulse has height 1/Ts, not 1. A unit sample scaled so the area is one, on both sides. A continuous impulse is impulse-invariant (the free evolution from x(0+) = B), not the zero-order hold that step and lsim use.
  5. lsim PICKS the hold from your input, and it is a hard switch. An input whose largest step is at most 0.75 of its own range is called smooth and gets a first-order hold; anything jumpier gets a zero-order hold. Both sides decide it the same way, so a sine and a square wave both cross to the digit — but the same u at a different amplitude can change the rule's verdict.
  6. initial's time grid is not step's, even for the same model: the grid is built from x0 rather than from the input matrix, and on one measured model came out at exactly half step's spacing. And a transfer function is refused on both sides — initial conditions need a state-space model.
  7. A PID's filter pole belongs to the DERIVATIVE term. pid(2, 3, 0, 0.5) has Kd = 0, so the filter has nothing to filter and the answer is a first-order PI controller, not a second-order model:

    ``` >>> pid(2, 3, 0, 0.5) 1 Kp + Ki * --- s

    with Kp = 2, Ki = 3 Continuous-time PI controller in parallel form. # Transfer Function ```

    And a discrete PID is not the continuous one with s replaced: with a filter the derivative term is Kd/(Tf + Ts/(z-1)), which is not Kd*(z-1)/Ts over anything.

  8. pidtune's gains are NOT MATLAB's, and this is the one row on the page where that is true by design. MATLAB's loop shaping ships unpublished, so this console runs a documented rule of its own: put the crossover where the structure's phase range is widest, then meet |L| = 1 and the target margin there exactly. What agrees is the PROPERTY pidtune itself promises — a phase margin at or above the target. Measured on MATLAB, pidtune(tf(1,[1 3 3 1]), "pi") gives margin 60 exactly and "pid" gives 64.7 — at or above 60, not equal to it. A named crossover overrides the margin on both sides.
  9. stepinfo's TransientTime and SettlingTime are different numbers. The first settles against threshold * max|y - yfinal|, the second against threshold * |yfinal - yinit|. They coincide only when the largest error in the record is the initial one — which is the usual case, and is why the difference surprises people when it appears.

What is not here#

Refused, with the reason in the message:

  • allmargin — it answers a struct of seven fields, and this console holds a record of numbers only. margin(sys) answers the crossing nearest instability, which is what the list is usually read for.
  • lqg and reg — the assembled LQG regulator.
  • hinfnorm — use norm(sys, Inf).
  • c2d(..., "matched" | "least-squares" | "damped") — the four that cross are "zoh", "foh", "tustin" and "impulse". "matched" is refused because the routine behind it is measurably the zoh routine, not because the word is unknown: accepting it would compare a zero-order hold against a matched pole-zero and call the difference a tolerance.
  • rlocus(sys) without gains, and zpk('z') without a sample time.
  • MIMO tf and zpk (the cell form). SISO tf/zpk and MIMO ss are the three kinds; append of two transfer functions therefore answers the state-space model where MATLAB answers a MIMO tf — the same system, a different kind.

Not known to the console at all — typing one of these answers unknown function '<name>':

If you reach forUse
controlSystemDesigner, sisotool, pidTunerpidtune, place, lqr and margin typed directly; there is no interactive tool here
linearSystemAnalyzer, ltiviewstep, bode, nyquist, stepinfo
rlocfindrlocus(sys, k) and read the roots
frd, genss, ussnothing — this console has three model kinds and no object types

Four console-only spellings sit beside these names and are marked as the console's own in Command glossary — console commands, verbs, functions. Each keeps its own signature, and the MATLAB call it corresponds to is not always the one the name suggests:

Console's ownMATLABWhat differs beyond the name
rootlocus(G, gains)rlocus(sys, k)nothing but the spelling — both take the gain vector, and both leave the pole order within a gain step to the implementation
polezero(G)pzmap(sys)polezero only ever draws; pzmap also answers, as [p, z] = pzmap(sys)
bode(G, w0, w1, n)bode(sys, {wmin, wmax})the four-argument sweep answers an N x 3 matrix of [omega, magnitude in dB, phase in radians]; MATLAB's answers the magnitude as an absolute ratio and the phase in unwrapped degrees
ramp(G)—MATLAB has no ramp; write it as lsim(G, t, t), the ramp as its own input over its own time vector

New work should use MATLAB's names where the table gives one.

Where to look next#