nk 1.0.0
C++ Numerical Computing Runtime
Loading...
Searching...
No Matches
Control System Toolbox (control)

Linear time-invariant (LTI) system representation (tf, ss, zpk), frequency response (Bode, Nyquist), time response (step, impulse), and stability. More...

Files

file  analyze.hpp
file  connect.hpp
file  conversion.hpp
file  discretize.hpp
file  freq.hpp
file  numerics.hpp
file  lti.hpp
file  lyapunov.hpp
file  props.hpp
 LTI-system predicates and analytic properties.
file  response.hpp
file  riccati.hpp
file  place.hpp
file  state.hpp

Classes

struct  nk::control::MarginResult
 Result of margin(sys) — gain / phase margin pair plus the frequencies at which they occur. More...
struct  nk::control::Tf2ZpResult
 Result of tf2zp — zeros, poles, and gain from tf coefficients. More...
struct  nk::control::StateSpace
 State-space realisation (A, B, C, D), the result of tf2ss. More...
struct  nk::control::BodeResult
 Result of bode(sys, w). More...
struct  nk::control::NyquistResult
 Result of nyquist(sys, w). More...
struct  nk::control::DampResult
 Result of damp. More...
struct  nk::control::RiccatiResult
 Result of an algebraic Riccati solve, matching MATLAB's [X, L, G] output order for care / dare. More...
struct  nk::control::CovarResult
 Output and state covariance of an LTI system driven by white noise. More...

Typedefs

using nk::control::internal::Mat = std::vector<double>
using nk::control::internal::Vec = std::vector<double>

Functions

Value nk::control::dcgain (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 DC (steady-state) gain of an LTI system.
MarginResult nk::control::margin (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Gain and phase margins ([Gm, Pm, Wcg, Wcp] = margin(sys)).
Value nk::control::stepinfo (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Step-response quality metrics (S = stepinfo(sys)).
Value nk::control::allmargin (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 All stability margins as a struct (S = allmargin(sys)).
Value nk::control::hinfnorm (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 H-infinity norm of a continuous-time LTI system (g = hinfnorm(sys)).
Value nk::control::series (const Value &sys1, const Value &sys2, std::pmr::memory_resource *mr=nullptr)
 Cascade two LTI blocks (series(sys1, sys2)).
Value nk::control::parallel (const Value &sys1, const Value &sys2, std::pmr::memory_resource *mr=nullptr)
 Parallel connection of two LTI blocks (parallel(sys1, sys2)).
Value nk::control::feedback (const Value &G, const Value &H, int sign, std::pmr::memory_resource *mr=nullptr)
 Closed-loop transfer function under feedback (feedback(G, H, sign)).
Tf2ZpResult nk::control::tf2zp (const Value &num, const Value &den, std::pmr::memory_resource *mr=nullptr)
 Convert tf coefficients to zero-pole-gain form.
std::pair< Value, Value > nk::control::zp2tf (const Value &z, const Value &p, const Value &k, std::pmr::memory_resource *mr=nullptr)
 Convert zero-pole-gain form to tf coefficients.
StateSpace nk::control::tf2ss (const Value &num, const Value &den, std::pmr::memory_resource *mr=nullptr)
 Convert tf coefficients to controllable canonical state-space.
std::pair< Value, Value > nk::control::ss2tf (const Value &A, const Value &B, const Value &C, const Value &D, int iu, std::pmr::memory_resource *mr=nullptr)
 Convert state-space to tf coefficients.
Value nk::control::minreal (const Value &sys, double tol=0.0, std::pmr::memory_resource *mr=nullptr)
 Minimal realization — cancel pole/zero pairs (sysr = minreal(sys, tol)).
Value nk::control::c2d (const Value &sys, double Ts, const std::string &method, std::pmr::memory_resource *mr=nullptr)
 Continuous-to-discrete conversion (c2d(sys, Ts, method)).
Value nk::control::d2c (const Value &sys, const std::string &method, std::pmr::memory_resource *mr=nullptr)
 Discrete-to-continuous conversion (d2c(sys, method)).
Value nk::control::evalfr (const Value &sys, double f, std::pmr::memory_resource *mr=nullptr)
 Single-point frequency response (H = evalfr(sys, f)).
Value nk::control::freqresp (const Value &sys, const Value &w, std::pmr::memory_resource *mr=nullptr)
 Frequency response on a user-supplied grid (H = freqresp(sys, w)).
BodeResult nk::control::bode (const Value &sys, const Value &wArg, std::pmr::memory_resource *mr=nullptr)
 Bode magnitude and phase response ([mag, phase, w] = bode(sys, w)).
NyquistResult nk::control::nyquist (const Value &sys, const Value &wArg, std::pmr::memory_resource *mr=nullptr)
 Nyquist plot data ([re, im, w] = nyquist(sys, w)).
std::pair< Value, Value > nk::control::rlocus (const Value &sys, const Value &kVec, std::pmr::memory_resource *mr=nullptr)
 Root locus ([r, k] = rlocus(sys, k)).
bool nk::control::internal::solveInPlace (Mat &A, Mat &B, std::size_t n, std::size_t nrhs)
 In-place partial-pivot LU decomposition + back-substitution.
Mat nk::control::internal::expm (const Mat &A, std::size_t n)
 Matrix exponential via the canonical [6/6] Padé approximant with scaling and squaring.
Vec nk::control::internal::charPoly (const Mat &A, std::size_t n)
 Faddeev–LeVerrier characteristic polynomial of an n×n column-major matrix.
Mat nk::control::internal::matmulSq (const Mat &A, const Mat &B, std::size_t n)
 Square matrix multiply C = A·B (all n×n column-major).
Value nk::control::tf (const Value &num, const Value &den, double Ts, std::pmr::memory_resource *mr=nullptr)
 Transfer-function LTI constructor (tf(num, den, Ts)).
Value nk::control::zpk (const Value &z, const Value &p, double k, double Ts, std::pmr::memory_resource *mr=nullptr)
 Zero-pole-gain LTI constructor (zpk(z, p, k, Ts)).
Value nk::control::ss (const Value &A, const Value &B, const Value &C, const Value &D, double Ts, std::pmr::memory_resource *mr=nullptr)
 State-space LTI constructor (ss(A, B, C, D, Ts)).
Value nk::control::filt (const Value &num, const Value &den, double Ts, std::pmr::memory_resource *mr=nullptr)
 Discrete tf with z^-1 variable convention (filt(num, den, Ts)).
Value nk::control::frd (const Value &response, const Value &frequency, double Ts, std::pmr::memory_resource *mr=nullptr)
 Frequency-response data model (frd(response, frequency, Ts)).
std::tuple< Value, Value > nk::control::frdata (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Extract (resp, freq) from an frd model.
std::tuple< Value, Value > nk::control::tfdata (const Value &sys, bool asVector, std::pmr::memory_resource *mr=nullptr)
 Extract numerator / denominator from any LTI form (tfdata).
std::tuple< Value, Value, Value > nk::control::zpkdata (const Value &sys, bool asVector, std::pmr::memory_resource *mr=nullptr)
 Extract zeros, poles, and gain (zpkdata).
std::tuple< Value, Value, Value, Value > nk::control::ssdata (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Extract A, B, C, D from any LTI form (ssdata).
Value nk::control::ss2ss (const Value &sys, const Value &T, std::pmr::memory_resource *mr=nullptr)
 Similarity transform of a state-space model (ss2ss(sys, T)).
Value nk::control::lyap (const Value &A, const Value &Q, std::pmr::memory_resource *mr=nullptr)
 Continuous-time Lyapunov equation solver (X = lyap(A, Q)).
Value nk::control::dlyap (const Value &A, const Value &Q, std::pmr::memory_resource *mr=nullptr)
 Discrete-time Lyapunov (Stein) equation solver (X = dlyap(A, Q)).
Value nk::control::isct (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Continuous-time predicate (isct(sys)).
Value nk::control::isdt (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Discrete-time predicate (isdt(sys)).
Value nk::control::issiso (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 SISO predicate (issiso(sys)).
Value nk::control::isproper (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Proper rational predicate (isproper(sys)).
Value nk::control::isstable (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Stability predicate (isstable(sys)).
Value nk::control::order (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 System order (order(sys)).
Value nk::control::pole (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Poles of the system (pole(sys)).
Value nk::control::zero (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 (Transmission) zeros of the system (zero(sys)).
DampResult nk::control::damp (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Natural frequencies and damping ratios ([wn, zeta, p] = damp(sys)).
std::pair< Value, Value > nk::control::pzmap (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Pole / zero map ([p, z] = pzmap(sys)).
Value nk::control::isstatic (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Static-system predicate (isstatic(sys)).
Value nk::control::tzero (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Transmission zeros (tzero(sys)).
std::pair< Value, Value > nk::control::step_response (const Value &sys, const Value &tArg, std::pmr::memory_resource *mr=nullptr, Value *xOut=nullptr)
 Unit-step response ([y, t] = step(sys, tFinal_or_t)).
std::pair< Value, Value > nk::control::impulse_response (const Value &sys, const Value &tArg, std::pmr::memory_resource *mr=nullptr, Value *xOut=nullptr)
 Unit-impulse response ([y, t] = impulse(sys, tFinal_or_t)).
Value nk::control::lsim (const Value &sys, const Value &u, const Value &t, const Value &x0, std::pmr::memory_resource *mr=nullptr, Value *xOut=nullptr)
 Linear simulation with arbitrary input (y = lsim(sys, u, t, x0)).
std::pair< Value, Value > nk::control::initial_response (const Value &sys, const Value &x0, const Value &tArg, std::pmr::memory_resource *mr=nullptr, Value *xOut=nullptr)
 Initial-condition response ([y, t] = initial(sys, x0, tArg)).
RiccatiResult nk::control::care (const Value &A, const Value &B, const Value &Q, const Value &R, std::pmr::memory_resource *mr=nullptr)
 Continuous-time algebraic Riccati equation ([X, L, G] = care(A, B, Q, R)).
RiccatiResult nk::control::dare (const Value &A, const Value &B, const Value &Q, const Value &R, std::pmr::memory_resource *mr=nullptr)
 Discrete-time algebraic Riccati equation ([X, L, G] = dare(A, B, Q, R)).
Value nk::control::acker (const Value &A, const Value &B, const Value &p, std::pmr::memory_resource *mr=nullptr)
 Ackermann's pole placement (K = acker(A, B, p)).
Value nk::control::place (const Value &A, const Value &B, const Value &p, std::pmr::memory_resource *mr=nullptr)
 SISO alias for acker — K = place(A, B, p).
Value nk::control::ctrb_AB (const Value &A, const Value &B, std::pmr::memory_resource *mr=nullptr)
 Controllability matrix from raw (A, B) (Co = ctrb(A, B)).
Value nk::control::ctrb_sys (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Controllability matrix from a system struct (Co = ctrb(sys)).
Value nk::control::obsv_AC (const Value &A, const Value &C, std::pmr::memory_resource *mr=nullptr)
 Observability matrix from raw (A, C) (O = obsv(A, C)).
Value nk::control::obsv_sys (const Value &sys, std::pmr::memory_resource *mr=nullptr)
 Observability matrix from a system struct (O = obsv(sys)).
Value nk::control::gram (const Value &sys, const std::string &type, std::pmr::memory_resource *mr=nullptr)
 Controllability / observability gramian (W = gram(sys, type)).
CovarResult nk::control::covar (const Value &sys, const Value &W, std::pmr::memory_resource *mr=nullptr)
 Steady-state covariance under white-noise excitation ([P, Q] = covar(sys, W)).

Detailed Description

Linear time-invariant (LTI) system representation (tf, ss, zpk), frequency response (Bode, Nyquist), time response (step, impulse), and stability.

Typedef Documentation

◆ Mat

using nk::control::internal::Mat = std::vector<double>

Definition at line 25 of file numerics.hpp.

◆ Vec

using nk::control::internal::Vec = std::vector<double>

Definition at line 26 of file numerics.hpp.

Function Documentation

◆ acker()

Value nk::control::acker ( const Value & A,
const Value & B,
const Value & p,
std::pmr::memory_resource * mr = nullptr )

Ackermann's pole placement (K = acker(A, B, p)).

Computes the SISO state-feedback gain row K such that eig(A − B·K) = p. Implements:

\[ K = [0\ 0\ \cdots\ 0\ 1]\ \mathcal{C}(A,B)^{-1}\ \phi(A) \]

where \( \mathcal{C} \) is the controllability matrix and \( \phi(s) = \prod_i (s - p_i) \) is the desired characteristic polynomial.

Single-input only. For multi-input systems use a Riccati-based design (lqr) or split into multiple SISO loops.

Parameters
An×n state matrix.
Bn×1 input column.
pn-element vector of desired closed-loop poles.
mrMemory resource (nullptr → process default).
Returns
1×n state-feedback gain row K.
Exceptions
Errorif B has more than one column, dimensions disagree, or (A, B) is uncontrollable.
auto K = acker(A, B, Value{-2, -3, -4});
// eig(A - B*K) ≈ [-2; -3; -4]
Core MATLAB-compatible multidimensional array and scalar value type.
Definition value.hpp:61
Value acker(const Value &A, const Value &B, const Value &p, std::pmr::memory_resource *mr=nullptr)
Ackermann's pole placement (K = acker(A, B, p)).
See also
place

◆ allmargin()

Value nk::control::allmargin ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

All stability margins as a struct (S = allmargin(sys)).

Scans the open-loop frequency response for every gain crossover (|G|=1 → phase margins) and every phase crossover (∠G = −180°+360°k → gain margins), and returns a struct with the seven MATLAB fields: GainMargin, GMFrequency, PhaseMargin, PMFrequency, DelayMargin, DMFrequency (row vectors), and Stable (logical — closed-loop unity- feedback stability from the roots of den+num). The single-crossover values coincide with margin; DelayMargin = PM(rad)/ω_gc.

Parameters
sysLTI struct (tf / zpk / ss).
mrMemory resource (nullptr → process default).
Returns
Struct Value with the 7 fields above.
See also
margin, hinfnorm

◆ bode()

BodeResult nk::control::bode ( const Value & sys,
const Value & wArg,
std::pmr::memory_resource * mr = nullptr )

Bode magnitude and phase response ([mag, phase, w] = bode(sys, w)).

Evaluates the response on wArg (or a default logarithmic grid covering the dominant pole/zero magnitudes if wArg is empty). Phase is unwrapped sample-by-sample so it doesn't jump by 360°.

Parameters
sysLTI struct.
wArgFrequency vector (rad/s) or empty to auto-pick.
mrMemory resource (nullptr → process default).
Returns
BodeResult; bind via auto b = bode(sys, w);.
auto b = bode(plant, Value::Empty);
// b.mag, b.phase, b.w are column vectors of equal length.
static const Value Empty
MATLAB-style empty matrix sentinel — a 0×0 DOUBLE value.
Definition value.hpp:136
BodeResult bode(const Value &sys, const Value &wArg, std::pmr::memory_resource *mr=nullptr)
Bode magnitude and phase response ([mag, phase, w] = bode(sys, w)).
See also
margin, nyquist, freqresp

◆ c2d()

Value nk::control::c2d ( const Value & sys,
double Ts,
const std::string & method,
std::pmr::memory_resource * mr = nullptr )

Continuous-to-discrete conversion (c2d(sys, Ts, method)).

Discretises a continuous-time LTI model at sample time Ts. The output struct's kind matches the input (tf → tf, zpk → zpk, ss → ss); the conversion is always done through an internal ss form, then converted back if needed.

Supported methods:

  • "zoh" (default): zero-order hold via Van Loan matrix exponential of \( \exp\!\left(\begin{smallmatrix}A & B \\ 0 & 0\end{smallmatrix}\right) T_s \).
  • "tustin": bilinear (Tustin), \( z = (1 + sT_s/2)/(1 - sT_s/2) \).
Parameters
sysContinuous LTI struct (Ts == 0).
TsSample time in seconds (positive).
method"zoh" or "tustin" (case-sensitive).
mrMemory resource (nullptr → process default).
Returns
Discrete LTI struct with Ts set.
Exceptions
Erroron unknown method, non-continuous input, or singularity in the Tustin matrix I − A·Ts/2.
auto sysC = tf({1}, {1, 2, 1}); // continuous plant
auto sysD = c2d(sysC, 0.1, "zoh"); // discrete @ 0.1 s
Value tf(const Value &num, const Value &den, double Ts, std::pmr::memory_resource *mr=nullptr)
Transfer-function LTI constructor (tf(num, den, Ts)).
Value c2d(const Value &sys, double Ts, const std::string &method, std::pmr::memory_resource *mr=nullptr)
Continuous-to-discrete conversion (c2d(sys, Ts, method)).
See also
d2c

◆ care()

RiccatiResult nk::control::care ( const Value & A,
const Value & B,
const Value & Q,
const Value & R,
std::pmr::memory_resource * mr = nullptr )

Continuous-time algebraic Riccati equation ([X, L, G] = care(A, B, Q, R)).

Solves \( A^{T}X + XA - XBR^{-1}B^{T}X + Q = 0 \) for the unique stabilizing \( X = X^{T} \succeq 0 \) via the matrix sign function of the Hamiltonian \( H = \begin{bmatrix} A & -BR^{-1}B^{T} \\ -Q & -A^{T}\end{bmatrix} \). The gain is \( G = R^{-1}B^{T}X \) and the closed-loop poles are \( \mathrm{eig}(A - BG) \).

Parameters
An×n state matrix.
Bn×m input matrix.
Qn×n state-weight (symmetric PSD).
Rm×m input-weight (symmetric positive-definite).
mrMemory resource (nullptr → process default).
Returns
{X, L, G} (see RiccatiResult).
Exceptions
Erroron shape mismatch or a singular Hamiltonian embedding.
See also
dare, lyap

◆ charPoly()

Vec nk::control::internal::charPoly ( const Mat & A,
std::size_t n )

Faddeev–LeVerrier characteristic polynomial of an n×n column-major matrix.

Returns coefficients [1, c1, c2, …, cn] in standard order (descending powers, leading 1): det(sI − A) = sⁿ + c1·sⁿ⁻¹ + … + cn. O(n⁴) work — fine for the n ≲ 32 typical of textbook problems.

Parameters
AColumn-major n×n input.
nMatrix dimension.
Returns
Coefficient vector of length n+1.
See also
expm

◆ covar()

CovarResult nk::control::covar ( const Value & sys,
const Value & W,
std::pmr::memory_resource * mr = nullptr )

Steady-state covariance under white-noise excitation ([P, Q] = covar(sys, W)).

For an LTI system driven by white noise of intensity W, solves the gramian Lyapunov equation for the state covariance Q and projects it to the output covariance P:

  • continuous: A Q + Q Aᵀ + B W Bᵀ = 0 (via lyap), P = C Q Cᵀ (infinite if D ≠ 0 — white noise through a direct feedthrough).
  • discrete: A Q Aᵀ − Q + B W Bᵀ = 0 (via dlyap), P = C Q Cᵀ + D W Dᵀ.
Parameters
sysLTI struct (ss / tf / zpk — converted to state space).
WNoise intensity (scalar → W·I, or an m×m matrix).
mrMemory resource (nullptr → process default).
Returns
{P, Q} (see CovarResult).
Exceptions
Erroron a non-LTI input or a shape mismatch.
See also
gram, lyap, dlyap

◆ ctrb_AB()

Value nk::control::ctrb_AB ( const Value & A,
const Value & B,
std::pmr::memory_resource * mr = nullptr )

Controllability matrix from raw (A, B) (Co = ctrb(A, B)).

Builds \( \mathcal{C} = [B,\ AB,\ A^2 B,\ \ldots,\ A^{n-1} B] \) — shape n × (n·m) where n = rows(A) and m = cols(B).

The system is controllable iff this matrix has full row rank (rank(Co) == n). NK doesn't run the rank check here — that's left to whatever rank tool the caller prefers.

Parameters
An×n state matrix.
Bn×m input matrix.
mrMemory resource (nullptr → process default).
Returns
n × (n·m) controllability matrix.
See also
ctrb_sys, obsv_AC

◆ ctrb_sys()

Value nk::control::ctrb_sys ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Controllability matrix from a system struct (Co = ctrb(sys)).

Convenience wrapper: pulls (A, B) from the LTI struct (converting tf / zpk inputs through tf2ss internally) and delegates to ctrb_AB.

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
Controllability matrix.
See also
ctrb_AB

◆ d2c()

Value nk::control::d2c ( const Value & sys,
const std::string & method,
std::pmr::memory_resource * mr = nullptr )

Discrete-to-continuous conversion (d2c(sys, method)).

Inverse of c2d. The default method is "tustin"; ZOH inverse is not implemented (would require a numerically robust matrix logarithm).

Parameters
sysDiscrete LTI struct (Ts > 0).
method"tustin" (default). "zoh" is rejected.
mrMemory resource (nullptr → process default).
Returns
Continuous LTI struct (Ts == 0).
Exceptions
Erroron unknown method or non-discrete input.
See also
c2d

◆ damp()

DampResult nk::control::damp ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Natural frequencies and damping ratios ([wn, zeta, p] = damp(sys)).

For each pole \( s_i \): \( \omega_{n,i} = |s_i|,\ \zeta_i = -\text{Re}(s_i)/\omega_{n,i} \). Discrete-time poles are first converted to the s-plane via \( s = \log(z) / T_s \).

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
DampResult; bind via auto d = damp(sys);.
See also
pole

◆ dare()

RiccatiResult nk::control::dare ( const Value & A,
const Value & B,
const Value & Q,
const Value & R,
std::pmr::memory_resource * mr = nullptr )

Discrete-time algebraic Riccati equation ([X, L, G] = dare(A, B, Q, R)).

Solves \( A^{T}XA - X - A^{T}XB(R + B^{T}XB)^{-1}B^{T}XA + Q = 0 \) for the stabilizing \( X \). Builds the symplectic matrix and applies a Cayley transform (unit disk → left half-plane) so the same sign-function machinery as care selects the stable subspace. The gain is \( G = (R + B^{T}XB)^{-1}B^{T}XA \), closed-loop poles \( \mathrm{eig}(A - BG) \) (inside the unit circle).

Parameters
An×n state matrix (must be nonsingular).
Bn×m input matrix.
Qn×n state-weight (symmetric PSD).
Rm×m input-weight (symmetric positive-definite).
mrMemory resource (nullptr → process default).
Returns
{X, L, G} (see RiccatiResult).
Exceptions
Erroron shape mismatch, singular A, or a singular embedding.
See also
care, dlyap

◆ dcgain()

Value nk::control::dcgain ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

DC (steady-state) gain of an LTI system.

Evaluates the transfer function at the steady-state frequency:

  • continuous (Ts == 0): \( H(0) \)
  • discrete (Ts > 0): \( H(1) \) (i.e. tf evaluated at z = 1)
Parameters
sysLTI struct (tf / zpk / ss as built by toolboxes/control/lti).
mrMemory resource (nullptr → process default).
Returns
Real scalar Value (or complex if the model is complex).
Value sys = tf({1}, {1, 2, 1}); // 1 / (s² + 2s + 1)
Value g = dcgain(sys); // → 1.0
Value dcgain(const Value &sys, std::pmr::memory_resource *mr=nullptr)
DC (steady-state) gain of an LTI system.
See also
margin, stepinfo, evalfr

◆ dlyap()

Value nk::control::dlyap ( const Value & A,
const Value & Q,
std::pmr::memory_resource * mr = nullptr )

Discrete-time Lyapunov (Stein) equation solver (X = dlyap(A, Q)).

Solves \( A X A^{T} - X + Q = 0 \) via the same Kronecker approach as lyap.

Parameters
An×n state matrix (typically Schur-stable, |λ_i| < 1).
Qn×n right-hand side.
mrMemory resource (nullptr → process default).
Returns
n×n solution X.
Exceptions
Errorif dimensions disagree or the Kronecker system is singular (A has eigenvalues λ_i, λ_j with λ_i·λ_j = 1).
See also
lyap

◆ evalfr()

Value nk::control::evalfr ( const Value & sys,
double f,
std::pmr::memory_resource * mr = nullptr )

Single-point frequency response (H = evalfr(sys, f)).

Returns the complex value of the transfer function at a single frequency f (rad/s):

  • continuous: \( H(j f) \).
  • discrete: \( H\!\left(e^{j f T_s}\right) \).
Parameters
sysLTI struct (tf / zpk / ss).
fFrequency in rad/s.
mrMemory resource (nullptr → process default).
Returns
1×1 complex Value.
See also
freqresp, bode

◆ expm()

Mat nk::control::internal::expm ( const Mat & A,
std::size_t n )

Matrix exponential via the canonical [6/6] Padé approximant with scaling and squaring.

Coefficient set: c_k = (12 − k)! · 6! / (12! · k! · (6 − k)!). Falls back to a 30-term truncated power series if the Padé denominator is numerically singular. O(n³) per matrix multiply.

Parameters
AColumn-major n×n input.
nMatrix dimension.
Returns
Column-major n×n matrix exponential.
See also
solveInPlace, matmulSq

◆ feedback()

Value nk::control::feedback ( const Value & G,
const Value & H,
int sign,
std::pmr::memory_resource * mr = nullptr )

Closed-loop transfer function under feedback (feedback(G, H, sign)).

Computes:

  • sign = −1 (default, negative feedback): \( T = G / (1 + G\,H) \)
  • sign = +1 (positive feedback): \( T = G / (1 - G\,H) \)

H defaults to unity feedback at the call site (pass tf({1},{1})).

Parameters
GForward path block.
HFeedback path block.
sign−1 (negative feedback) or +1 (positive feedback).
mrMemory resource (nullptr → process default).
Returns
tf struct for the closed-loop system.
auto P = tf({1}, {1, 2, 1}); // plant
auto C = tf({10, 1}, {1, 0}); // PI controller
auto T = feedback(series(C, P), tf({1},{1}), -1); // unity-feedback CL
Value series(const Value &sys1, const Value &sys2, std::pmr::memory_resource *mr=nullptr)
Cascade two LTI blocks (series(sys1, sys2)).
Value feedback(const Value &G, const Value &H, int sign, std::pmr::memory_resource *mr=nullptr)
Closed-loop transfer function under feedback (feedback(G, H, sign)).
See also
series, parallel

◆ filt()

Value nk::control::filt ( const Value & num,
const Value & den,
double Ts,
std::pmr::memory_resource * mr = nullptr )

Discrete tf with z^-1 variable convention (filt(num, den, Ts)).

Equivalent to tf except:

  • default Ts is −1 ("unspecified discrete"),
  • variable field is set to "z^-1",
  • coefficient order is that of filt: num/den as in Y(z)/U(z) = (b0 + b1 z^-1 + …) / (a0 + a1 z^-1 + …).
Parameters
numNumerator coefficients (z^-1 ascending powers).
denDenominator coefficients.
TsSample time (−1 = unspecified, > 0 = explicit).
mrMemory resource (nullptr → process default).
Returns
Struct Value tagged kind="tf" with variable = "z^-1".
See also
tf

◆ frd()

Value nk::control::frd ( const Value & response,
const Value & frequency,
double Ts,
std::pmr::memory_resource * mr = nullptr )

Frequency-response data model (frd(response, frequency, Ts)).

Builds a struct {kind="frd", resp, freq, Ts}. response may be complex; frequency is a real vector (rad/s). Both are stored as column vectors.

Parameters
responseComplex response samples.
frequencyReal frequency grid (rad/s).
TsSample time (0 = continuous).
mrMemory resource (nullptr → process default).
Returns
Struct Value tagged kind="frd".
See also
frdata

◆ frdata()

std::tuple< Value, Value > nk::control::frdata ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Extract (resp, freq) from an frd model.

Parameters
sysfrd struct.
mrMemory resource (nullptr → process default).
Returns
(resp, freq); bind via auto [r, f] = frdata(sys);.
Exceptions
Errorif kind != "frd".
See also
frd

◆ freqresp()

Value nk::control::freqresp ( const Value & sys,
const Value & w,
std::pmr::memory_resource * mr = nullptr )

Frequency response on a user-supplied grid (H = freqresp(sys, w)).

Parameters
sysLTI struct (tf / zpk / ss).
wColumn or row vector of frequencies (rad/s).
mrMemory resource (nullptr → process default).
Returns
Column vector of complex H values, one per element of w.
See also
evalfr, bode, nyquist

◆ gram()

Value nk::control::gram ( const Value & sys,
const std::string & type,
std::pmr::memory_resource * mr = nullptr )

Controllability / observability gramian (W = gram(sys, type)).

Solves the appropriate Lyapunov equation for the LTI system sys:

  • type = "c": controllability gramian, \( A W_c + W_c A^{T} + B B^{T} = 0 \) (discrete: Stein equation via dlyap).
  • type = "o": observability gramian, \( A^{T} W_o + W_o A + C^{T} C = 0 \).

Continuous vs discrete is taken from the system's sample time (Ts).

Parameters
sysLTI struct (ss / tf / zpk — converted to state space).
type"c" (controllability) or "o" (observability).
mrMemory resource (nullptr → process default).
Returns
n×n gramian (symmetric positive-semidefinite for a stable sys).
Exceptions
Erroron a non-LTI input or an unknown type.
See also
lyap, dlyap, ctrb_sys, obsv_sys

◆ hinfnorm()

Value nk::control::hinfnorm ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

H-infinity norm of a continuous-time LTI system (g = hinfnorm(sys)).

Returns \( \|G\|_\infty = \sup_\omega \sigma_{\max}(G(j\omega)) \) via the Bruinsma–Steinbuch Hamiltonian test with bisection on \( \gamma \) ( \( \gamma \) is an upper bound iff the Hamiltonian \( M(\gamma) \) has no purely imaginary eigenvalue). Returns Inf for an unstable or marginally stable system (a pole on/right of the jω axis).

Parameters
sysContinuous-time LTI struct (ss / tf / zpk).
mrMemory resource (nullptr → process default).
Returns
Scalar ‖G‖∞ (or Inf).
Exceptions
Erroron a non-LTI input or a discrete-time system (discrete H∞ is not yet supported).
See also
margin, sigma, dcgain

◆ impulse_response()

std::pair< Value, Value > nk::control::impulse_response ( const Value & sys,
const Value & tArg,
std::pmr::memory_resource * mr = nullptr,
Value * xOut = nullptr )

Unit-impulse response ([y, t] = impulse(sys, tFinal_or_t)).

Continuous: simulates with u ≡ 0 and initial condition x(0+) = B (the differentiation-through-delta trick). Discrete: applies u[0] = 1, u[k>0] = 0.

Time argument semantics match step_response.

Parameters
sysLTI struct.
tArgTime argument.
mrMemory resource (nullptr → process default).
Returns
(y, t).
See also
step_response, lsim

◆ initial_response()

std::pair< Value, Value > nk::control::initial_response ( const Value & sys,
const Value & x0,
const Value & tArg,
std::pmr::memory_resource * mr = nullptr,
Value * xOut = nullptr )

Initial-condition response ([y, t] = initial(sys, x0, tArg)).

Time response of sys to the initial state x0 with zero input — the same integrator as step_response / impulse_response run with u ≡ 0 and x(0) = x0, output y = C·x. The time argument tArg follows the same semantics as step_response (Value::Empty → auto grid from the system poles; scalar → final time; vector → explicit grid). The optional state trajectory is returned via xOut.

Parameters
sysLTI struct (tf / zpk / ss).
x0Initial state (length = number of states).
tArgTime argument (Empty / scalar tFinal / explicit grid).
mrMemory resource (nullptr → process default).
xOutOptional state-trajectory output (one row per sample).
Returns
(y, t); bind via auto [y, t] = initial_response(sys, x0, tArg);.
See also
step_response, impulse_response, lsim

◆ isct()

Value nk::control::isct ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Continuous-time predicate (isct(sys)).

True when Ts == 0.

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
LOGICAL scalar.
See also
isdt

◆ isdt()

Value nk::control::isdt ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Discrete-time predicate (isdt(sys)).

True when Ts > 0 (explicit sample time) or Ts == -1 ("unspecified discrete").

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
LOGICAL scalar.
See also
isct

◆ isproper()

Value nk::control::isproper ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Proper rational predicate (isproper(sys)).

  • tf: length(num) <= length(den)
  • zpk: numel(z) <= numel(p)
  • ss: always true
Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
LOGICAL scalar.

◆ issiso()

Value nk::control::issiso ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

SISO predicate (issiso(sys)).

True for tf / zpk (always SISO in this build) and for ss when B has a single column and C has a single row.

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
LOGICAL scalar.

◆ isstable()

Value nk::control::isstable ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Stability predicate (isstable(sys)).

  • continuous: every pole satisfies real(p) < 0.
  • discrete: every pole satisfies |p| < 1.
Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
LOGICAL scalar.
See also
pole, isstatic

◆ isstatic()

Value nk::control::isstatic ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Static-system predicate (isstatic(sys)).

True when order returns 0 — i.e. the system is a pure gain with no dynamics.

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
LOGICAL scalar.
See also
order

◆ lsim()

Value nk::control::lsim ( const Value & sys,
const Value & u,
const Value & t,
const Value & x0,
std::pmr::memory_resource * mr = nullptr,
Value * xOut = nullptr )

Linear simulation with arbitrary input (y = lsim(sys, u, t, x0)).

Simulates \( \dot x = Ax + Bu,\ y = Cx + Du \) (or its discrete analogue) along the explicit time grid t. u must have length(t) rows (one row per sample). x0 is the initial state (length n); pass Value::Empty to default to zero.

Parameters
sysLTI struct.
uInput samples, one row per time step.
tTime grid (at least 2 samples).
x0Initial state (or empty for zero IC).
mrMemory resource (nullptr → process default).
Returns
Column vector of y(t) of length length(t).
Exceptions
Errorif length(u) != length(t) or length(t) < 2.
See also
step_response, impulse_response

◆ lyap()

Value nk::control::lyap ( const Value & A,
const Value & Q,
std::pmr::memory_resource * mr = nullptr )

Continuous-time Lyapunov equation solver (X = lyap(A, Q)).

Solves \( A X + X A^{T} + Q = 0 \) by vectorising the equation (Kronecker form) into a dense n²×n² linear system and applying Gaussian elimination. Practical for n up to ~32; for larger problems a Bartels–Stewart implementation would be wanted.

Parameters
An×n state matrix.
Qn×n right-hand side (typically symmetric PSD).
mrMemory resource (nullptr → process default).
Returns
n×n solution X.
Exceptions
Errorif dimensions disagree or the Kronecker system is singular (A has an eigenvalue λ with λ + λ* = 0).
auto X = lyap(A, Q);
// For stable A and Q = Qᵀ > 0, X is symmetric positive definite.
Value lyap(const Value &A, const Value &Q, std::pmr::memory_resource *mr=nullptr)
Continuous-time Lyapunov equation solver (X = lyap(A, Q)).
See also
dlyap

◆ margin()

MarginResult nk::control::margin ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Gain and phase margins ([Gm, Pm, Wcg, Wcp] = margin(sys)).

Builds a dense Bode grid via bode(sys) and scans for the first crossings of phase = −180° (gain margin) and |H| = 1 (phase margin) from low to high frequency. If a crossing isn't found the corresponding margin is +Inf.

Parameters
sysLTI struct (tf / zpk / ss).
mrMemory resource (nullptr → process default).
Returns
MarginResult — bind via auto m = margin(sys);.
auto m = margin(plant);
fprintf("GM = %.2f at ω = %.2f, PM = %.2f at ω = %.2f\n",
m.Gm.toScalar(), m.Wcg.toScalar(),
m.Pm.toScalar(), m.Wcp.toScalar());
MarginResult margin(const Value &sys, std::pmr::memory_resource *mr=nullptr)
Gain and phase margins ([Gm, Pm, Wcg, Wcp] = margin(sys)).
See also
bode, dcgain, stepinfo

◆ matmulSq()

Mat nk::control::internal::matmulSq ( const Mat & A,
const Mat & B,
std::size_t n )

Square matrix multiply C = A·B (all n×n column-major).

Parameters
AColumn-major n×n left operand.
BColumn-major n×n right operand.
nMatrix dimension.
Returns
Column-major n×n product.

◆ minreal()

Value nk::control::minreal ( const Value & sys,
double tol = 0.0,
std::pmr::memory_resource * mr = nullptr )

Minimal realization — cancel pole/zero pairs (sysr = minreal(sys, tol)).

Removes common factors of a model to produce a minimal (controllable + observable) realization:

  • tf / zpk: cancel each pole against a zero within relative tolerance tol (default sqrt(eps)), rebuilt from the surviving roots — returns a tf.
  • ss (SISO): the same cancellation on ss2tf(sys), re-realized via tf2ss — returns an ss of the reduced order. The realization is not unique, so it matches MATLAB on order + transfer function, not the exact A,B,C,D.
Parameters
sysLTI struct (tf / zpk / ss).
tolRelative pole/zero cancellation tolerance (≤0 → sqrt(eps)).
mrMemory resource (nullptr → process default).
Returns
Reduced LTI struct (tf for tf/zpk input, ss for ss input).
Exceptions
Erroron a non-LTI input or a MIMO state-space.
See also
tf2ss, ss2tf, tf2zp

◆ nyquist()

NyquistResult nk::control::nyquist ( const Value & sys,
const Value & wArg,
std::pmr::memory_resource * mr = nullptr )

Nyquist plot data ([re, im, w] = nyquist(sys, w)).

Same grid logic as bode but returns the Cartesian components of H instead of magnitude / phase.

Parameters
sysLTI struct.
wArgFrequency vector (rad/s) or empty to auto-pick.
mrMemory resource (nullptr → process default).
Returns
NyquistResult.
See also
bode, freqresp

◆ obsv_AC()

Value nk::control::obsv_AC ( const Value & A,
const Value & C,
std::pmr::memory_resource * mr = nullptr )

Observability matrix from raw (A, C) (O = obsv(A, C)).

Builds \( \mathcal{O} = [C;\ CA;\ CA^2;\ \ldots;\ CA^{n-1}] \) — shape (n·p) × n where n = rows(A) and p = rows(C).

The system is observable iff this matrix has full column rank.

Parameters
An×n state matrix.
Cp×n output matrix.
mrMemory resource (nullptr → process default).
Returns
(n·p) × n observability matrix.
See also
obsv_sys, ctrb_AB

◆ obsv_sys()

Value nk::control::obsv_sys ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Observability matrix from a system struct (O = obsv(sys)).

Convenience wrapper analogous to ctrb_sys.

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
Observability matrix.
See also
obsv_AC

◆ order()

Value nk::control::order ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

System order (order(sys)).

  • tf: max(deg(num), deg(den)) = max(numel - 1)
  • zpk: max(numel(z), numel(p))
  • ss: state dimension rows(A)
Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
DOUBLE scalar.
See also
isstatic

◆ parallel()

Value nk::control::parallel ( const Value & sys1,
const Value & sys2,
std::pmr::memory_resource * mr = nullptr )

Parallel connection of two LTI blocks (parallel(sys1, sys2)).

Both blocks see the same input; their outputs are summed: \( H(s) = H_1(s) + H_2(s) \). In coefficient form, H = (n1·d2 + n2·d1) / (d1·d2) with leading-coefficient normalisation on the denominator.

Parameters
sys1First block.
sys2Second block.
mrMemory resource (nullptr → process default).
Returns
tf struct for the parallel combination.
See also
series, feedback

◆ place()

Value nk::control::place ( const Value & A,
const Value & B,
const Value & p,
std::pmr::memory_resource * mr = nullptr )

SISO alias for acker — K = place(A, B, p).

The robust multi-input variant (Kautsky–Nichols eigenvector assignment) is intentionally not re-implemented here; calling place on a multi-input system therefore behaves identically to the SISO Ackermann path and will throw on B with more than one column.

Parameters
An×n state matrix.
Bn×1 input column.
pn-element vector of desired closed-loop poles.
mrMemory resource (nullptr → process default).
Returns
1×n state-feedback gain row K.
Exceptions
Errorif B has more than one column, dimensions disagree, or (A, B) is uncontrollable.
See also
acker

◆ pole()

Value nk::control::pole ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Poles of the system (pole(sys)).

Column vector. For ss inputs, computed via the characteristic polynomial of A (Faddeev-LeVerrier + roots).

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
Column vector of poles (possibly COMPLEX).
See also
zero, pzmap, damp

◆ pzmap()

std::pair< Value, Value > nk::control::pzmap ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Pole / zero map ([p, z] = pzmap(sys)).

Equivalent to {pole(sys), zero(sys)} — convenient when both quantities are needed.

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
(poles, zeros) pair; bind via auto [p, z] = pzmap(sys);.
See also
pole, zero

◆ rlocus()

std::pair< Value, Value > nk::control::rlocus ( const Value & sys,
const Value & kVec,
std::pmr::memory_resource * mr = nullptr )

Root locus ([r, k] = rlocus(sys, k)).

For each gain \( k \) in kVec, compute the n closed-loop poles of the negative-feedback system \( T = G / (1 + k\,G) \), i.e. roots of den(s) + k · num(s) = 0.

If kVec is empty, a default sweep is built: 0 plus 100 log-spaced points from 1e-2 to 1e3 (101 gains total).

Parameters
sysLTI struct.
kVecGain vector or empty for the default sweep.
mrMemory resource (nullptr → process default).
Returns
(r, k) where
  • r : length(k) × n complex matrix of closed-loop poles.
  • k : the gain vector actually used. Bind via auto [r, k] = rlocus(sys, kVec);.
See also
margin, bode

◆ series()

Value nk::control::series ( const Value & sys1,
const Value & sys2,
std::pmr::memory_resource * mr = nullptr )

Cascade two LTI blocks (series(sys1, sys2)).

Implements the topology u → sys1 → sys2 → y, equivalent to sys2 * sys1 in transfer-function math ( \( H(s) = H_2(s)\,H_1(s) \)).

Either input may be in any of the three LTI forms (tf / zpk / ss); they are reduced to (num, den) coefficient pairs internally and the polynomial product is taken. The result is always a tf struct, even if both inputs were zpk or ss.

Parameters
sys1First block (input side).
sys2Second block (output side).
mrMemory resource (nullptr → process default).
Returns
tf struct for the cascaded system.
auto C = tf({1, 1}, {1}); // PI controller numerator only
auto P = tf({1}, {1, 2, 1}); // 2nd-order plant
auto L = series(C, P); // loop gain L = P·C
See also
parallel, feedback

◆ solveInPlace()

bool nk::control::internal::solveInPlace ( Mat & A,
Mat & B,
std::size_t n,
std::size_t nrhs )

In-place partial-pivot LU decomposition + back-substitution.

Operates on a column-major n×n matrix A, with nrhs right-hand-side columns held column-major in B.

Parameters
AColumn-major n×n matrix; overwritten with LU.
BColumn-major n×nrhs RHS; overwritten with solution.
nMatrix dimension.
nrhsNumber of RHS columns.
Returns
false if numerically singular (any pivot < 1e-14); the contents of A and B are unspecified in that case. true on success.
See also
expm, charPoly

◆ ss()

Value nk::control::ss ( const Value & A,
const Value & B,
const Value & C,
const Value & D,
double Ts,
std::pmr::memory_resource * mr = nullptr )

State-space LTI constructor (ss(A, B, C, D, Ts)).

Builds an ss-tagged struct value with fields {kind="ss", A, B, C, D, Ts}. Dimensions:

  • A is n×n,
  • B is n×nin,
  • C is nout×n,
  • D is nout×nin (a scalar 0 is broadcast when D is empty).
Parameters
AState matrix (n×n).
BInput matrix (n×nin).
COutput matrix (nout×n).
DFeedthrough matrix (nout×nin); empty → broadcast 0.
TsSample time (0 for continuous).
mrMemory resource (nullptr → process default).
Returns
Struct Value tagged kind="ss".
See also
tf, zpk

◆ ss2ss()

Value nk::control::ss2ss ( const Value & sys,
const Value & T,
std::pmr::memory_resource * mr = nullptr )

Similarity transform of a state-space model (ss2ss(sys, T)).

Applies the change of basis x' = T · x: \( A' = T A T^{-1},\ B' = T B,\ C' = C T^{-1},\ D' = D \). Returns a fresh ss struct; the original is untouched.

Parameters
sysInput ss struct.
Tn×n invertible similarity matrix.
mrMemory resource (nullptr → process default).
Returns
New ss-tagged struct with transformed (A,B,C,D).
Exceptions
Errorif T is singular.

◆ ss2tf()

std::pair< Value, Value > nk::control::ss2tf ( const Value & A,
const Value & B,
const Value & C,
const Value & D,
int iu,
std::pmr::memory_resource * mr = nullptr )

Convert state-space to tf coefficients.

Uses the Faddeev–LeVerrier expansion to build \( H(s) = C\,(sI - A)^{-1}\,B + D \) without ever forming the matrix inverse. The output denominator is the characteristic polynomial \( \det(sI - A) \).

iu selects the input column when B has multiple inputs (1-based). Only single-output systems (C with 1 row) are supported; MIMO would need a generalized eigenproblem and is not yet exposed.

Parameters
An×n state matrix.
Bn×nin input matrix.
C1×n output row.
D1×nin feedthrough.
iuInput column to use (1-based; default 1).
mrMemory resource (nullptr → process default).
Returns
(num, den); bind via auto [num, den] = ss2tf(...);.
Exceptions
Errorif A is non-square, iu is out of range, or C has more than 1 row (MIMO not supported).
See also
tf2ss, tf2zp

◆ ssdata()

std::tuple< Value, Value, Value, Value > nk::control::ssdata ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Extract A, B, C, D from any LTI form (ssdata).

tf / zpk inputs are first converted via tf2ss / zp2tf+ tf2ss.

Parameters
sysLTI struct (tf / zpk / ss).
mrMemory resource (nullptr → process default).
Returns
(A, B, C, D).
See also
tfdata, zpkdata

◆ step_response()

std::pair< Value, Value > nk::control::step_response ( const Value & sys,
const Value & tArg,
std::pmr::memory_resource * mr = nullptr,
Value * xOut = nullptr )

Unit-step response ([y, t] = step(sys, tFinal_or_t)).

Simulates the response of sys to a unit step input. The time argument is overloaded:

  • scalar Tfinal → simulate from 0 to Tfinal with auto-picked dt (slowest stable pole sets Tfinal, fastest pole sets dt);
  • vector → use as the explicit time grid (uniform stride expected for continuous models — mean dt is taken);
  • empty / missing → auto-pick Tfinal ≈ 8 / |Re λ_min|.

Continuous models are discretised via ZOH using a Van Loan matrix-exponential expansion; discrete models iterate the recurrence directly.

Parameters
sysLTI struct (tf / zpk / ss).
tArgTime argument (scalar / vector / empty).
mrMemory resource (nullptr → process default).
Returns
(y, t); bind via auto [y, t] = step_response(sys, tArg);.
auto [y, t] = step_response(plant, Value::Empty); // auto grid
std::pair< Value, Value > step_response(const Value &sys, const Value &tArg, std::pmr::memory_resource *mr=nullptr, Value *xOut=nullptr)
Unit-step response ([y, t] = step(sys, tFinal_or_t)).
See also
impulse_response, lsim

◆ stepinfo()

Value nk::control::stepinfo ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Step-response quality metrics (S = stepinfo(sys)).

Runs the system through step_response with a 2× extended horizon and returns a struct with the fields:

  • RiseTime — 10 % → 90 % rise interval (s).
  • SettlingTime— last time |y − yfinal| exceeds the 2 % band (s).
  • SettlingMin — minimum of y inside the settling band.
  • SettlingMax — maximum of y inside the settling band.
  • Overshoot — peak overshoot as a percentage of yfinal.
  • Undershoot — peak undershoot as a percentage of yfinal.
  • Peak — absolute peak value.
  • PeakTime — time at which the peak occurs (s).

All times are in seconds. Defaults: 10–90 % rise band, 2 % settling band.

Parameters
sysLTI struct (tf / zpk / ss).
mrMemory resource (nullptr → process default).
Returns
Struct Value with the 8 fields above.
See also
margin, dcgain, step_response

◆ tf()

Value nk::control::tf ( const Value & num,
const Value & den,
double Ts,
std::pmr::memory_resource * mr = nullptr )

Transfer-function LTI constructor (tf(num, den, Ts)).

Builds a tf-tagged struct value with fields {kind="tf", num, den, Ts, variable}. The numerator and denominator are row coefficient vectors with the leading coefficient first. Ts selects the time domain:

  • Ts == 0 → continuous, variable = "s".
  • Ts > 0 → discrete with that sample time, variable = "z".
  • Ts == -1→ discrete "unspecified".
Parameters
numNumerator coefficients.
denDenominator coefficients (leading coefficient nonzero).
TsSample time in seconds; 0 for continuous.
mrMemory resource (nullptr → process default).
Returns
Struct Value tagged kind="tf".
auto sys = tf({1, 2}, {1, 3, 2}, 0); // (s + 2) / (s² + 3s + 2)
See also
zpk, ss, filt, frd

◆ tf2ss()

StateSpace nk::control::tf2ss ( const Value & num,
const Value & den,
std::pmr::memory_resource * mr = nullptr )

Convert tf coefficients to controllable canonical state-space.

Produces the controllable canonical realisation (companion-matrix form):

\[ A = \begin{pmatrix} 0 & 1 & 0 & \cdots & 0 \\ \vdots & & & & \\ 0 & 0 & \cdots & 0 & 1 \\ -a_n & -a_{n-1} & \cdots & & -a_1 \end{pmatrix},\quad B = \begin{pmatrix}0 \\ \vdots \\ 0 \\ 1\end{pmatrix} \]

with C[k] = b[n − k] − b[0]·a[n − k] and D = b[0]. The numerator must be no longer than the denominator (proper rational).

Parameters
numNumerator (length ≤ length(den)).
denDenominator (leading coefficient nonzero).
mrMemory resource (nullptr → process default).
Returns
StateSpace {A, B, C, D}.
Exceptions
Errorif length(num) > length(den) (improper).
See also
ss2tf, tf2zp

◆ tf2zp()

Tf2ZpResult nk::control::tf2zp ( const Value & num,
const Value & den,
std::pmr::memory_resource * mr = nullptr )

Convert tf coefficients to zero-pole-gain form.

Roots are computed via nk::builtin::roots; complex conjugate pairs and trailing-zero roots are fully handled.

Parameters
numNumerator polynomial (row, descending powers).
denDenominator polynomial (leading coefficient must be nonzero).
mrMemory resource (nullptr → process default).
Returns
Tf2ZpResult with z, p, k.
Exceptions
Errorif the denominator's leading coefficient is zero.
auto r = tf2zp({2, -16, 30}, {1, -1}); // (2s² − 16s + 30) / (s − 1)
// r.z = [3; 5], r.p = [1], r.k = 2.
Tf2ZpResult tf2zp(const Value &num, const Value &den, std::pmr::memory_resource *mr=nullptr)
Convert tf coefficients to zero-pole-gain form.
See also
zp2tf, tf2ss

◆ tfdata()

std::tuple< Value, Value > nk::control::tfdata ( const Value & sys,
bool asVector,
std::pmr::memory_resource * mr = nullptr )

Extract numerator / denominator from any LTI form (tfdata).

With asVector = true returns row vectors padded so num and den have equal length (leading zeros on num). With asVector = false wraps each row vector in a 1×1 cell (the default).

Accepts tf inputs directly; zpk and ss inputs are converted via zp2tf and ss2tf.

Parameters
sysLTI struct (tf / zpk / ss).
asVectortrue for raw row vectors, false for 1×1 cells.
mrMemory resource (nullptr → process default).
Returns
(num, den).
Exceptions
Erroron unrecognised kind.
See also
zpkdata, ssdata

◆ tzero()

Value nk::control::tzero ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

Transmission zeros (tzero(sys)).

For SISO inputs equivalent to zero. For MIMO ss inputs a generalised eigenproblem would be required; that path throws.

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
Column vector of transmission zeros.
Exceptions
ErrorMIMO ss input.
See also
zero

◆ zero()

Value nk::control::zero ( const Value & sys,
std::pmr::memory_resource * mr = nullptr )

(Transmission) zeros of the system (zero(sys)).

For tf this is roots(num); for zpk it is the z field directly; for SISO ss it goes through ss2tf and roots. MIMO ss would require a generalised eigenproblem (QZ) and is not yet supported.

Parameters
sysLTI struct.
mrMemory resource (nullptr → process default).
Returns
Column vector of zeros.
Exceptions
ErrorMIMO ss input.
See also
pole, tzero

◆ zp2tf()

std::pair< Value, Value > nk::control::zp2tf ( const Value & z,
const Value & p,
const Value & k,
std::pmr::memory_resource * mr = nullptr )

Convert zero-pole-gain form to tf coefficients.

Expands num = k · ∏(s − z_i) and den = ∏(s − p_i) via nk::builtin::poly. The result preserves complex coefficients if the inputs are complex.

Parameters
zZeros (column or row vector).
pPoles (column or row vector).
kGain (scalar).
mrMemory resource (nullptr → process default).
Returns
(num, den); bind via auto [num, den] = zp2tf(z, p, k);.
See also
tf2zp, tf2ss

◆ zpk()

Value nk::control::zpk ( const Value & z,
const Value & p,
double k,
double Ts,
std::pmr::memory_resource * mr = nullptr )

Zero-pole-gain LTI constructor (zpk(z, p, k, Ts)).

Builds a zpk-tagged struct value with fields {kind="zpk", z, p, k, Ts}. z and p are vectors of zeros and poles (real or complex); k is a real scalar gain.

Parameters
zZero list.
pPole list.
kGain scalar.
TsSample time (0 for continuous).
mrMemory resource (nullptr → process default).
Returns
Struct Value tagged kind="zpk".
See also
tf, ss

◆ zpkdata()

std::tuple< Value, Value, Value > nk::control::zpkdata ( const Value & sys,
bool asVector,
std::pmr::memory_resource * mr = nullptr )

Extract zeros, poles, and gain (zpkdata).

z and p are column vectors (or 1×1 cells without asVector). k is always a numeric scalar.

Parameters
sysLTI struct (tf / zpk / ss).
asVectortrue for raw vectors, false for cell-wrapped.
mrMemory resource (nullptr → process default).
Returns
(z, p, k).
See also
tfdata, ssdata