it.grypho.scala.leonardo.control
Members list
Type members
Classlikes
Continuous-to-discrete conversion.
Continuous-to-discrete conversion.
The method is always a visible argument, never a hidden default. The same plant discretised by zero-order hold and by Tustin has different discrete poles, so a silent choice would make two correct-looking answers disagree with no way to see why.
Attributes
- Supertypes
-
trait Enumtrait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Closed loop with negative feedback: feedback(G, H, v) = G/(1 + G*H).
Closed loop with negative feedback: feedback(G, H, v) = G/(1 + G*H).
Attributes
- Supertypes
-
trait Serializabletrait Producttrait Equalstrait _Expressionclass Objecttrait Matchableclass AnyShow all
Impulse response: impulse(G, s, t) = L^-1{G(s)}.
Impulse response: impulse(G, s, t) = L^-1{G(s)}.
Attributes
- Supertypes
-
trait Serializabletrait Producttrait Equalstrait _Expressionclass Objecttrait Matchableclass AnyShow all
Parallel connection: parallel(G, H, v).
Parallel connection: parallel(G, H, v).
Attributes
- Supertypes
-
trait Serializabletrait Producttrait Equalstrait _Expressionclass Objecttrait Matchableclass AnyShow all
Series connection: series(G, H, v).
Series connection: series(G, H, v).
Attributes
- Supertypes
-
trait Serializabletrait Producttrait Equalstrait _Expressionclass Objecttrait Matchableclass AnyShow all
Unit-step response: step(G, s, t) = L^-1{G(s)/s}.
Unit-step response: step(G, s, t) = L^-1{G(s)/s}.
Attributes
- Supertypes
-
trait Serializabletrait Producttrait Equalstrait _Expressionclass Objecttrait Matchableclass AnyShow all
Value members
Concrete methods
Frequency response of G at angular frequency w: substitute v -> i*w.
Frequency response of G at angular frequency w: substitute v -> i*w.
Rides the existing _Complex closure — no new arithmetic — which is why the whole of Bode and Nyquist is one substitution.
Value parameters
- g
-
the transfer function
- v
-
the frequency variable
- w
-
the angular frequency, in radians per unit time
Attributes
- Returns
-
(magnitude, phase-in-radians), orNonewhere the response is not finite (evaluating an integrator atw = 0, say) — never a fabricated infinity
Discretises a continuous transfer function over sample period ts.
Discretises a continuous transfer function over sample period ts.
Tustin is a substitution: replace s by (2/Ts)*(z-1)/(z+1) and renormalise. Zero- order hold is a hold equivalence, G_d(z) = (1 - z^-1) * Z{L^-1[G(s)/s]}, assembled from the inverse Laplace transform and the z-transform — which is the reason the z-transform had to exist first.
Value parameters
- g
-
the continuous transfer function
- method
-
Zoh or Tustin
- s
-
the continuous frequency variable
- ts
-
the sample period; must be positive
- z
-
the discrete variable to express the result in
Attributes
- Returns
-
the discrete transfer function, or
Nonewhen the conversion does not close
Exact state-space discretisation over one sample period: A_d = e^(A*Ts).
Exact state-space discretisation over one sample period: A_d = e^(A*Ts).
Uses the block-matrix form, not B_d = A⁻¹(A_d − I)B, and that is a correctness matter rather than tidiness. Exponentiating [[A, B], [0, 0]]*Ts yields [[A_d, B_d], [0, I]] in one step, and it is defined for a singular A — where the inverse form is not, even though B_d exists. A singular A is entirely ordinary: any system with an integrator has one, so the naive form would fail on a common case rather than an exotic one.
This is what the matrix exponential exists to supply, and what a Kalman filter needs.
Value parameters
- a
-
the continuous state matrix
- b
-
the continuous input matrix
- ts
-
the sample period
Attributes
- Returns
-
(A_d, B_d), orNonewhen the operands are not conforming dense matrices
Is the pair (A, B) controllable — can the input steer every state?
Is the pair (A, B) controllable — can the input steer every state?
Value parameters
- a
-
the state matrix
- b
-
the input matrix
Attributes
- Returns
-
Some(true)/Some(false), orNonewhen either operand is not a dense matrix
Inverse of c2d: recovers a continuous transfer function from a discrete one.
Inverse of c2d: recovers a continuous transfer function from a discrete one.
Only Tustin is invertible in closed form — the substitution z = (2 + Ts*s)/(2 - Ts*s) is its exact inverse, which is what makes d2c(c2d(G)) return to G. A zero-order-hold inverse would need a matrix logarithm and is declined rather than approximated.
Value parameters
- g
-
the discrete transfer function
- method
-
must be Tustin
- s
-
the continuous variable to express the result in
- ts
-
the sample period
- z
-
the discrete variable
Attributes
- Returns
-
the continuous transfer function, or
None
Steady-state gain: G evaluated at v = 0.
Steady-state gain: G evaluated at v = 0.
Value parameters
- g
-
the transfer function
- v
-
the frequency variable
Attributes
- Returns
-
G(0), orNonewhen it is not finite (a pole at the origin) or not rational
Closed loop with negative feedback: G / (1 + G*H).
Closed loop with negative feedback: G / (1 + G*H).
The sign convention is stated because it cannot be inferred. Negative feedback is the control convention and what a unity-feedback loop means by default; a substantial part of the literature writes the positive form G/(1 - G*H), and choosing silently would make every closed-loop result wrong for half its readers — the reasoning that also fixes the spherical polar-angle convention in the vector package. For positive feedback, negate h.
Value parameters
- g
-
the forward path
- h
-
the feedback path (use
_Number(1)for unity feedback) - v
-
the frequency variable
Attributes
- Returns
-
the closed-loop transfer function, normalised to a single rational
The Bode sweep: magnitude in decibels and unwrapped phase in degrees, over a logarithmically spaced grid (issue F_0004).
The Bode sweep: magnitude in decibels and unwrapped phase in degrees, over a logarithmically spaced grid (issue F_0004).
Unwrapping is the substance here, not the grid. bode's phase comes from atan2, whose principal value is (-pi, pi], so a swept curve jumps by a full turn wherever it crosses the branch cut — 1/(s+1)^3 tends to -270 degrees but a raw sweep reports +90. That jump is an artefact of the arctangent and not of the plant, and every reader who plots a raw sweep inherits it. This accumulates a turn whenever consecutive samples differ by more than half a turn, which restores the continuous curve.
dB and degrees rather than the raw pair, because that is what a Bode plot is; the raw magnitude and radian phase stay available from bode itself, so nothing is lost.
The one assumption worth stating: unwrapping cannot distinguish a genuine half-turn step from a grid too coarse to resolve a fast one, so a sparse sweep across a lightly damped resonance can unwrap the wrong way. That is inherent to unwrapping rather than particular to this implementation, and the remedy is points, not cleverness.
A frequency where the response is not finite — a pole on the imaginary axis — is dropped, mirroring scalar.sample; the unwrapping state carries across the gap, so the curve resumes rather than restarting.
Value parameters
- env
-
bindings for any parameter the plant carries
- g
-
the transfer function
- points
-
how many samples, at least 2
- v
-
the frequency variable
- wMax
-
the highest angular frequency
- wMin
-
the lowest angular frequency, strictly positive
Attributes
- Returns
-
(omega, magnitude-in-dB, unwrapped-phase-in-degrees), ascending in omega
Impulse response L^-1{G(s)}. Declines for an improper G, as stepResponse does.
Impulse response L^-1{G(s)}. Declines for an improper G, as stepResponse does.
Value parameters
- g
-
the transfer function
- s
-
the frequency variable
- t
-
the time variable, free in the result
Attributes
- Returns
-
the response, or _ImpulseResponse unchanged when no rule applies
Continuous-time stability: every pole strictly in the left half-plane.
Continuous-time stability: every pole strictly in the left half-plane.
Decided from the poles rather than from a Routh table, a deliberate departure from the original plan. Routh's advantage is symbolic coefficients, but it carries well-known degenerate cases — a zero in the first column, or an identically zero row — each needing its own repair, and a mis-handled one yields a confident wrong verdict rather than a refusal. Root location has neither failure mode. Symbolic coefficients are refused here instead, which is the same answer Routh would have to give once scalar.sign could not decide, and routhTable remains available for the table itself.
Strict, so marginal stability is not stability: poles on the imaginary axis give false. An oscillator that never decays is not a stable system, and reporting it as one would be the confident wrong answer.
Value parameters
- g
-
the transfer function
- v
-
the frequency variable
Attributes
- Returns
-
Some(true)/Some(false), orNonewhen the poles cannot be determined
Discrete-time stability: every pole strictly inside the unit circle.
Discrete-time stability: every pole strictly inside the unit circle.
The continuous test does not transfer. z = 0.5 is a stable discrete pole while the same value read as a continuous one is unstable, so applying the left-half-plane rule to a z-domain transfer function inverts the answer rather than degrading it.
Value parameters
- g
-
the discrete transfer function
- v
-
the z-domain variable
Attributes
- Returns
-
Some(true)/Some(false), orNonewhen the poles cannot be determined
Nyquist point: the real and imaginary parts of G(i*w).
Nyquist point: the real and imaginary parts of G(i*w).
The same substitution as bode, reported in rectangular rather than polar form — the two are one computation presented two ways, not two computations.
Value parameters
- g
-
the transfer function
- v
-
the frequency variable
- w
-
the angular frequency
Attributes
- Returns
-
(real, imaginary), orNonewhere the response is not finite
The Nyquist sweep: the same grid as frequencyResponse, in rectangular coordinates.
The Nyquist sweep: the same grid as frequencyResponse, in rectangular coordinates.
One sweep presented two ways — the relationship bode and nyquist already have, and the reason both read the same logGrid rather than each building one. Unwrapping does not arise here: a point in the plane is unchanged by adding a turn to its argument.
Value parameters
- env
-
bindings for any parameter the plant carries
- g
-
the transfer function
- points
-
how many samples, at least 2
- v
-
the frequency variable
- wMax
-
the highest angular frequency
- wMin
-
the lowest angular frequency, strictly positive
Attributes
- Returns
-
(real, imaginary)for each grid frequency, non-finite points dropped
Is the pair (A, C) observable — can the output distinguish every state?
Is the pair (A, C) observable — can the output distinguish every state?
Observability of (A, C) is controllability of (Aᵀ, Cᵀ) — the duality, used here rather than restated, so the two can never disagree.
Value parameters
- a
-
the state matrix
- c
-
the output matrix
Attributes
- Returns
-
Some(true)/Some(false), orNonewhen either operand is not a dense matrix
Parallel connection: G + H.
Parallel connection: G + H.
Value parameters
- g
-
first block
- h
-
second block
- v
-
the frequency variable
Attributes
- Returns
-
the combined transfer function, normalised to a single rational
Poles of G: the roots of its denominator.
Poles of G: the roots of its denominator.
Returns _Values rather than Doubles because a complex pole is the interesting case, not an error — an oscillatory mode is a conjugate pair, and reducing the result to reals would silently drop exactly the systems a control engineer cares about.
Value parameters
- g
-
the transfer function
- v
-
the frequency variable
Attributes
- Returns
-
the poles, or
NonewhenGis not rational invor the roots do not resolve
The Routh array of G's denominator, for inspecting a stability margin by hand.
The Routh array of G's denominator, for inspecting a stability margin by hand.
Numeric coefficients only. isStable does not consult it — see the note there.
Value parameters
- g
-
the transfer function
- v
-
the frequency variable
Attributes
- Returns
-
the array, row by row from the highest power down, or
None
Series (cascade) connection: G * H.
Series (cascade) connection: G * H.
Value parameters
- g
-
first block
- h
-
second block
- v
-
the frequency variable
Attributes
- Returns
-
the combined transfer function, normalised to a single rational
Bundles (A, B, C, D) into the 1x4 row that represents a state-space model.
Bundles (A, B, C, D) into the 1x4 row that represents a state-space model.
Value parameters
- a
-
state matrix
- b
-
input matrix
- c
-
output matrix
- d
-
feedthrough matrix
Attributes
- Returns
-
the model as a
_Matrixnode
Unit-step response L^-1{G(s)/s} — almost entirely a re-spelling of the inverse Laplace transform's repeated-pole machinery.
Unit-step response L^-1{G(s)/s} — almost entirely a re-spelling of the inverse Laplace transform's repeated-pole machinery.
Declines for an improper G (numerator degree above denominator degree). Such a response contains an impulsive term at t = 0 that the inverse-transform tier does not represent, so returning only the smooth part would be a confidently incomplete answer rather than a refusal.
Value parameters
- g
-
the transfer function
- s
-
the frequency variable
- t
-
the time variable, free in the result
Attributes
- Returns
-
the response, or _StepResponse unchanged when no rule applies