graph TD
A[Start with state-space model A,B,C,D] --> B{Primary decision?}
B -->|Reachability from inputs| C[Use CTRB]
B -->|State reconstruction from outputs| D[Use OBSV]
B -->|Energy/conditioning insight| E[Use GRAM]
B -->|Stability certificate| F{Time domain?}
B -->|Quadratic-optimal feedback| G{Time domain?}
F -->|Continuous| H[Use LYAP]
F -->|Discrete| I[Use DLYAP]
G -->|Continuous| J[Use CARE]
G -->|Discrete| K[Use DARE]
C --> L[If rank deficient, revise actuator design]
D --> M[If rank deficient, revise sensor design]
E --> N[Use c/o for full Gramian, cf/of for Cholesky factors]
Matrix Computations
Overview
Introduction Matrix computations in control systems are the numerical backbone for answering one practical question: “Can this dynamic system be analyzed, stabilized, and monitored reliably?” In state-space form, a linear time-invariant (LTI) model is written as \dot{x}=Ax+Bu, y=Cx+Du for continuous-time systems, or x_{k+1}=Ax_k+Bu_k, y_k=Cx_k+Du_k for discrete-time systems. Once a model is in this form, most design and diagnostics tasks reduce to structured matrix equations and matrix rank checks. This category collects those operations into focused tools so users can move from model definition to design decisions without hand-building fragile spreadsheets.
From a mathematical perspective, these computations sit at the intersection of linear algebra, systems theory, and optimization. The core objects include controllability and observability matrices, Gramians, and matrix equation solutions (Lyapunov and Riccati). Together, they allow engineers and analysts to evaluate whether a system is steerable, whether hidden states can be reconstructed from measurements, whether trajectories decay or diverge, and what feedback law minimizes a quadratic cost. These are foundational ideas in modern control, including LQR, Kalman filtering, model predictive control warm starts, and safety-critical stability assessments. For background, the state-space representation and Lyapunov equation references are good starting points.
In Boardflare, the matrix-computation tools are wrappers around the python-control ecosystem (with selective fallback to SciPy linear algebra in one case). The category includes CTRB, OBSV, GRAM, LYAP, DLYAP, CARE, and DARE. Each tool isolates one canonical computation and returns directly usable matrices for downstream analysis. This design is especially useful in business and engineering workflows where teams share models between Python, Excel, and web calculators, and need deterministic outputs for documentation, validation, and governance.
At a practical level, these calculators reduce three recurrent risks in control analytics: (1) manual formula errors when assembling block matrices, (2) inconsistent discretization assumptions across teams, and (3) hidden numerical instability when systems are near uncontrollable or marginally stable. By using common, tested implementations and explicit inputs (A, B, C, D, Q, R), teams can compare scenarios quickly, audit model choices, and embed control-theoretic checks in larger operational pipelines.
When to Use It Use this category when the job is not just “solve a matrix equation,” but “make a control decision with confidence.” Matrix computations are most valuable at milestones where design, verification, and deployment meet.
A first common scenario is actuator and sensor architecture validation before controller tuning. Suppose an automation team is redesigning a packaging line and can choose between several motor placements (affecting B) and sensor sets (affecting C). They can use CTRB to verify that candidate actuators can excite all critical modes, and OBSV to check that chosen sensors make those modes reconstructible. If either matrix is rank-deficient, the hardware layout is structurally limited regardless of how sophisticated the controller is. GRAM then adds nuance by quantifying “how hard” control or observation is, even when rank tests pass.
A second scenario is stability assurance and disturbance-energy analysis in process, energy, or robotics systems. After linearizing a plant around an operating point, teams use LYAP (continuous) or DLYAP (discrete) to solve Lyapunov equations and certify asymptotic behavior under nominal assumptions. In reliability terms, this answers whether perturbations decay and how rapidly state energy dissipates. For battery thermal loops, chemical dosing skids, or drone attitude hold, these calculations can be run across many operating points to identify regions that are stable, weakly damped, or unstable.
A third scenario is optimal regulator synthesis under explicit performance tradeoffs. If the objective is to penalize state deviation and control effort, then CARE and DARE provide the Riccati solutions behind continuous and discrete LQR-style policies. This is directly relevant for teams balancing product quality, energy cost, and actuator wear. For example, a smart HVAC platform may use DARE for sample-time control in embedded firmware, while a high-speed servo prototype may begin with CARE in continuous-time analysis before discretization.
These tools are also useful for model governance and migration projects. When legacy controllers are being ported from MATLAB or spreadsheet templates, analysts can replicate key matrices with LYAP, DLYAP, CARE, and DARE, then compare against historical baselines. Similarly, controllability/observability checks via CTRB and OBSV provide a quick sanity gate before expensive simulation or hardware-in-the-loop tests.
In short, use this category when a model-based decision depends on structural reachability, reconstructibility, stability certificates, or quadratic-optimal feedback design. If the system is represented in state-space and the decision has operational consequence, these matrix tools are usually the fastest route to a defensible answer.
How It Works The category combines three families of computations: structural tests, energy-based metrics, and matrix-equation solvers.
For structural tests, CTRB forms the controllability matrix
\mathcal{C} = \begin{bmatrix}B & AB & A^2B & \cdots & A^{n-1}B\end{bmatrix},
and OBSV forms the observability matrix
\mathcal{O} = \begin{bmatrix}C \\ CA \\ CA^2 \\ \vdots \\ CA^{n-1}\end{bmatrix}.
For an n-state system, full rank conditions \mathrm{rank}(\mathcal{C})=n and \mathrm{rank}(\mathcal{O})=n indicate controllability and observability, respectively. These are binary structural conditions: they answer whether control or estimation is theoretically possible, not whether it is numerically easy or robust in noisy practice.
For energy-based metrics, GRAM computes controllability or observability Gramians (and optionally their Cholesky factors). In continuous time, for a stable A, the controllability Gramian W_c and observability Gramian W_o satisfy
AW_c + W_cA^T + BB^T = 0,
A^TW_o + W_oA + C^TC = 0.
Intuitively, W_c encodes how much input energy is required to reach state directions, while W_o encodes how strongly state directions appear in outputs. Small eigenvalues often signal weakly controllable/observable modes. This is why a system can pass CTRB and OBSV rank checks but still be difficult to control or estimate robustly.
For stability and covariance-style equations, LYAP solves continuous Lyapunov forms and DLYAP solves discrete forms. A common discrete-time relation is
A^TXA - X + Q = 0,
while continuous variants use AX + XA^T + Q = 0 (or equivalent sign conventions depending on software API). Existence of a positive-definite solution under appropriate conditions is tied to stability properties of A and definiteness of Q. In practice, these tools support both classic stability certificates and steady-state covariance-like analyses.
For optimal control, CARE and DARE solve algebraic Riccati equations that define quadratic-optimal state feedback. The continuous-time CARE in one standard form is
A^TX + XA - XBR^{-1}B^TX + Q = 0,
and the discrete-time DARE is commonly written as
X = A^TXA - A^TXB\left(R + B^TXB\right)^{-1}B^TXA + Q.
Given X, a feedback gain can be recovered (outside this category) and used for LQR-like policies. The matrices Q \succeq 0 and R \succ 0 encode business/engineering priorities: larger state penalties improve regulation; larger input penalties reduce actuator effort and aggressiveness.
Under the hood, Boardflare relies on python-control function implementations: control.ctrb, control.obsv, control.gram, control.lyap, control.dlyap, control.care, and control.dare. For GRAM, there is also fallback use of SciPy routines such as SciPy linear algebra in edge cases.
Assumptions matter. These methods generally assume linear, time-invariant models around an operating regime. If a physical process is strongly nonlinear, time-varying, heavily constrained, or poorly identified, the resulting matrices can still be computed but may mislead decisions. A good workflow is to (1) validate model quality, (2) run structural checks, (3) run energy and stability checks, and only then (4) tune optimality weights. This sequence reduces the risk of tuning a controller around an unfit model.
Practical Example Consider a two-state thermal process with one heater input and one measured output. The team models it in continuous time as
\dot{x}=Ax+Bu,\quad y=Cx,
with
A=\begin{bmatrix}-0.8 & 0.2 \\ 0.1 & -0.5\end{bmatrix},\; B=\begin{bmatrix}1.0\\0.3\end{bmatrix},\; C=\begin{bmatrix}1 & 0\end{bmatrix},\; D=\begin{bmatrix}0\end{bmatrix}.
Step 1 is structural feasibility. The analyst runs CTRB with A,B and verifies full rank, confirming both thermal states are reachable by heater actuation. Then they run OBSV with A,C and verify that the chosen sensor can reconstruct both states through model dynamics. If either check fails, they revise actuator/sensor placement before any controller tuning.
Step 2 is energy insight. Using GRAM with gram_type="c", they compute the controllability Gramian and inspect eigenvalues. One much smaller eigenvalue indicates a “hard-to-move” temperature mode. They also evaluate gram_type="o" to see whether one state direction is weakly visible at the sensor. This informs instrumentation upgrades and expected estimator sensitivity before field deployment.
Step 3 is nominal stability margin. They solve LYAP for a chosen positive-definite Q to verify that the nominal linearized system has a Lyapunov certificate and to compare damping intensity across operating points (e.g., low-load and high-load regimes). If the process controller must run digitally at sampling time T_s, they discretize the model and repeat with DLYAP, since discrete-time stability can differ materially from continuous-time intuition when sampling is coarse.
Step 4 is optimal regulator design. They choose cost weights based on business priorities: production quality and safety correspond to stronger state penalties in Q, while actuator lifespan and energy tariffs are represented in R. For a continuous implementation benchmark, they solve CARE. For firmware deployment on a PLC or microcontroller, they solve DARE using the discrete model and selected sample period. The resulting Riccati solution matrix provides the basis for deriving consistent feedback gains across scenarios.
Step 5 is governance and communication. The team documents each matrix and result in Boardflare calculators so process engineers, controls engineers, and operations managers share one auditable record. This often replaces spreadsheet tabs with manually assembled block matrices, reducing review friction. A practical handoff artifact is a short table listing rank checks, Gramian condition indicators, Lyapunov pass/fail, and Riccati solution snapshots for each operating point.
The key advantage over ad hoc Excel modeling is repeatability at scale. Once a template is set, analysts can batch-run multiple plants, machine variants, or seasonal conditions using the same CTRB → OBSV → GRAM → LYAP/DLYAP → CARE/DARE sequence. That sequence maps directly to real decisions: architecture viability, instrumentation sufficiency, stability confidence, and control cost-performance tradeoffs.
How to Choose Choose tools by decision type rather than by equation name. If the question is “Is this possible?”, start with structural matrices. If the question is “How difficult or fragile is it?”, move to Gramians and Lyapunov. If the question is “What policy is optimal under weighted costs?”, use Riccati.
Function-by-function guidance:
- CTRB: Use for a fast controllability screen from A,B. Best for architecture checks and early feasibility. Pro: simple and interpretable rank test. Limitation: binary outcome can hide numerical weakness in near-singular cases.
- OBSV: Use for observability screening from A,C. Best when selecting sensors or validating estimator prerequisites. Pro: direct structural test. Limitation: like CTRB, it does not quantify measurement quality under noise.
- GRAM: Use after structural checks to quantify controllability/observability energy and mode conditioning. Pro: richer insight than rank alone; supports
c,o,cf,of. Limitation: interpretation depends on system stability assumptions and scaling choices. - LYAP: Use for continuous-time stability and energy-function analysis. Pro: central tool for continuous LTI certificates and covariance-style equations. Limitation: requires careful sign convention awareness and physically meaningful Q selection.
- DLYAP: Use when implementation is sampled-data, digital, or event-stepped. Pro: directly reflects discrete-time behavior. Limitation: results can be sensitive to sampling choice and model discretization quality.
- CARE: Use for continuous-time LQR-related Riccati solutions. Pro: mathematically grounded tradeoff between regulation and actuation effort. Limitation: assumes linear model and appropriate definiteness/regularity of weighting matrices.
- DARE: Use for discrete-time LQR and embedded control designs. Pro: deployment-aligned for digital controllers. Limitation: performance depends on sampling and discrete model fidelity.
A practical selection rule is:
- Run CTRB and OBSV first; if either fails rank expectations, redesign model architecture before tuning.
- Run GRAM second; if Gramian spectra are badly conditioned, expect fragile tuning and consider scaling, sensor upgrades, or actuator reallocation.
- Run LYAP or DLYAP third to certify stability in the actual implementation domain.
- Run CARE or DARE last to encode business priorities through Q,R and compute optimality-aligned solutions.
This progression keeps teams from overinvesting in controller tuning when structural prerequisites are not met. It also creates a transparent audit trail: structure, energy, stability, then optimality. In organizations that span data science, controls, and operations, that ordering improves cross-functional trust because each decision is tied to a specific, explainable matrix computation.
CARE
This function computes the stabilizing solution matrix X for the continuous-time algebraic Riccati equation used in linear quadratic regulator design and continuous-time state estimation.
A^T X + X A - X B R^{-1} B^T X + Q = 0
The matrix X balances state penalty terms from Q against control effort penalties from R. For stabilizable systems with appropriate weighting matrices, the stabilizing solution defines the optimal quadratic cost-to-go and is a standard building block for LQR feedback gains.
Excel Usage
=CARE(A, B, Q, R)
A(list[list], required): State dynamics matrix A.B(list[list], required): Input matrix B.Q(list[list], required): State weighting matrix Q.R(list[list], optional, default: null): Input weighting matrix R.
Returns (list[list]): The solution matrix X.
Example 1: Simple Riccati solution
Inputs:
| A | B | Q | R | ||
|---|---|---|---|---|---|
| 0 | 1 | 0 | 1 | 0 | 1 |
| 0 | 0 | 1 | 0 | 1 |
Excel formula:
=CARE({0,1;0,0}, {0;1}, {1,0;0,1}, {1})
Expected output:
| Result | |
|---|---|
| 1.73205 | 1 |
| 1 | 1.73205 |
Example 2: Scalar continuous Riccati equation
Inputs:
| A | B | Q | R |
|---|---|---|---|
| -1 | 1 | 2 | 1 |
Excel formula:
=CARE({-1}, {1}, {2}, {1})
Expected output:
0.732051
Example 3: Omitted R uses identity weighting
Inputs:
| A | B | Q | ||
|---|---|---|---|---|
| 0 | 1 | 0 | 2 | 0 |
| 0 | 0 | 1 | 0 | 1 |
Excel formula:
=CARE({0,1;0,0}, {0;1}, {2,0;0,1})
Expected output:
| Result | |
|---|---|
| 2.7671 | 1.41421 |
| 1.41421 | 1.95664 |
Example 4: Diagonal stable system with anisotropic state cost
Inputs:
| A | B | Q | R | ||||
|---|---|---|---|---|---|---|---|
| -1 | 0 | 1 | 0 | 3 | 0 | 2 | 0 |
| 0 | -2 | 0 | 1 | 0 | 1 | 0 | 4 |
Excel formula:
=CARE({-1,0;0,-2}, {1,0;0,1}, {3,0;0,1}, {2,0;0,4})
Expected output:
| Result | |
|---|---|
| 1.16228 | 0 |
| 0 | 0.246211 |
Python Code
Show Code
import control as ct
import numpy as np
def care(A, B, Q, R=None):
"""
Solve the continuous-time algebraic Riccati equation.
See: https://python-control.readthedocs.io/en/latest/generated/control.care.html
This example function is provided as-is without any representation of accuracy.
Args:
A (list[list]): State dynamics matrix A.
B (list[list]): Input matrix B.
Q (list[list]): State weighting matrix Q.
R (list[list], optional): Input weighting matrix R. Default is None.
Returns:
list[list]: The solution matrix X.
"""
try:
def to_np(x):
if x is None:
return None
if not isinstance(x, list):
return np.array([[float(x)]])
if x and not isinstance(x[0], list):
x = [x]
return np.array([[float(v) if v is not None and str(v) != "" else 0.0 for v in row] for row in x])
a_np = to_np(A)
b_np = to_np(B)
q_np = to_np(Q)
r_np = to_np(R)
X, L, G = ct.care(a_np, b_np, q_np, r_np)
return X.tolist()
except Exception as e:
return f"Error: {str(e)}"Online Calculator
CTRB
This function builds the controllability matrix for a linear state-space system with state matrix A and input matrix B.
\mathcal{C} = [B, AB, A^2 B, \dots, A^{n-1} B]
A system is controllable when this matrix has full rank, meaning every state can be reached from a suitable input over finite time. The result is commonly used as a prerequisite check before pole placement, LQR design, and related controller synthesis tasks.
Excel Usage
=CTRB(A, B)
A(list[list], required): State dynamics matrix A.B(list[list], required): Input matrix B.
Returns (list[list]): The controllability matrix.
Example 1: Controllability of a second order system
Inputs:
| A | B | |
|---|---|---|
| 0 | 1 | 0 |
| -2 | -3 | 1 |
Excel formula:
=CTRB({0,1;-2,-3}, {0;1})
Expected output:
| Result | |
|---|---|
| 0 | 1 |
| 1 | -3 |
Example 2: Single-state controllability matrix
Inputs:
| A | B |
|---|---|
| 2 | 3 |
Excel formula:
=CTRB({2}, {3})
Expected output:
3
Example 3: Two-state system with two control channels
Inputs:
| A | B | ||
|---|---|---|---|
| 1 | 0 | 1 | 0 |
| 0 | 2 | 0 | 1 |
Excel formula:
=CTRB({1,0;0,2}, {1,0;0,1})
Expected output:
| Result | |||
|---|---|---|---|
| 1 | 0 | 1 | 0 |
| 0 | 1 | 0 | 2 |
Example 4: Double integrator controllability matrix
Inputs:
| A | B | |
|---|---|---|
| 0 | 1 | 0 |
| 0 | 0 | 1 |
Excel formula:
=CTRB({0,1;0,0}, {0;1})
Expected output:
| Result | |
|---|---|
| 0 | 1 |
| 1 | 0 |
Python Code
Show Code
import control as ct
import numpy as np
def ctrb(A, B):
"""
Compute the controllability matrix.
See: https://python-control.readthedocs.io/en/latest/generated/control.ctrb.html
This example function is provided as-is without any representation of accuracy.
Args:
A (list[list]): State dynamics matrix A.
B (list[list]): Input matrix B.
Returns:
list[list]: The controllability matrix.
"""
try:
def to_np(x):
if x is None:
return None
if not isinstance(x, list):
return np.array([[float(x)]])
if x and not isinstance(x[0], list):
x = [x]
return np.array([[float(v) if v is not None and str(v) != "" else 0.0 for v in row] for row in x])
a_np = to_np(A)
b_np = to_np(B)
C = ct.ctrb(a_np, b_np)
return C.tolist()
except Exception as e:
return f"Error: {str(e)}"Online Calculator
DARE
This function computes the stabilizing solution matrix X for the discrete-time algebraic Riccati equation used in optimal control and discrete-time filtering problems.
A^T X A - X - A^T X B (B^T X B + R)^{-1} B^T X A + Q = 0
The solution defines the quadratic cost-to-go for a discrete-time regulator and is used to derive optimal state feedback gains. When R is omitted, the underlying library uses an identity input weighting matrix.
Excel Usage
=DARE(A, B, Q, R)
A(list[list], required): Discrete state dynamics matrix A.B(list[list], required): Discrete input matrix B.Q(list[list], required): State weighting matrix Q.R(list[list], optional, default: null): Input weighting matrix R. If omitted, the identity matrix is used.
Returns (list[list]): The solution matrix X.
Example 1: Discrete Riccati solution
Inputs:
| A | B | Q | R | ||
|---|---|---|---|---|---|
| 1 | 1 | 0.5 | 1 | 0 | 1 |
| 0 | 1 | 1 | 0 | 1 |
Excel formula:
=DARE({1,1;0,1}, {0.5;1}, {1,0;0,1}, {1})
Expected output:
| Result | |
|---|---|
| 2.3671 | 1.11803 |
| 1.11803 | 2.58748 |
Example 2: Scalar discrete Riccati equation
Inputs:
| A | B | Q | R |
|---|---|---|---|
| 0.8 | 1 | 1 | 1 |
Excel formula:
=DARE({0.8}, {1}, {1}, {1})
Expected output:
1.36995
Example 3: Omitted R uses identity weighting in discrete time
Inputs:
| A | B | Q |
|---|---|---|
| 0.9 | 1 | 2 |
Excel formula:
=DARE({0.9}, {1}, {2})
Expected output:
2.584
Example 4: Two-state discrete regulator design
Inputs:
| A | B | Q | R | ||
|---|---|---|---|---|---|
| 1 | 0.1 | 0 | 1 | 0 | 0.5 |
| 0 | 0.9 | 1 | 0 | 2 |
Excel formula:
=DARE({1,0.1;0,0.9}, {0;1}, {1,0;0,2}, {0.5})
Expected output:
| Result | |
|---|---|
| 15.8497 | 1.74312 |
| 1.74312 | 2.53848 |
Python Code
Show Code
import control as ct
import numpy as np
def dare(A, B, Q, R=None):
"""
Solve the discrete-time algebraic Riccati equation.
See: https://python-control.readthedocs.io/en/latest/generated/control.dare.html
This example function is provided as-is without any representation of accuracy.
Args:
A (list[list]): Discrete state dynamics matrix A.
B (list[list]): Discrete input matrix B.
Q (list[list]): State weighting matrix Q.
R (list[list], optional): Input weighting matrix R. If omitted, the identity matrix is used. Default is None.
Returns:
list[list]: The solution matrix X.
"""
try:
def to_np(x):
if x is None:
return None
if not isinstance(x, list):
return np.array([[float(x)]])
if x and not isinstance(x[0], list):
x = [x]
return np.array([[float(v) if v is not None and str(v) != "" else 0.0 for v in row] for row in x])
a_np = to_np(A)
b_np = to_np(B)
q_np = to_np(Q)
r_np = to_np(R)
X, L, G = ct.dare(a_np, b_np, q_np, r_np)
return X.tolist()
except Exception as e:
return f"Error: {str(e)}"Online Calculator
DLYAP
This function solves the discrete-time Lyapunov equation for a stable linear system and can also be used for the related discrete Sylvester equation.
A X A^T - X + Q = 0
The resulting matrix X is used in stability analysis, covariance propagation, and discrete-time energy calculations. When the optional matrix C is supplied, the computation switches to the discrete Sylvester form supported by the underlying library.
Excel Usage
=DLYAP(A, Q, C)
A(list[list], required): Square matrix A.Q(list[list], required): Square symmetric matrix Q.C(list[list], optional, default: null): Optional matrix C for solving the Sylvester equation.
Returns (list[list]): The solution matrix X.
Example 1: Discrete stable system Lyapunov solution
Inputs:
| A | Q | ||
|---|---|---|---|
| 0.5 | 0 | 1 | 0 |
| 0 | 0.3 | 0 | 1 |
Excel formula:
=DLYAP({0.5,0;0,0.3}, {1,0;0,1})
Expected output:
| Result | |
|---|---|
| 1.33333 | 0 |
| 0 | 1.0989 |
Example 2: Scalar discrete Lyapunov equation
Inputs:
| A | Q |
|---|---|
| 0.2 | 1 |
Excel formula:
=DLYAP({0.2}, {1})
Expected output:
1.04167
Example 3: Coupled stable discrete system
Inputs:
| A | Q | ||
|---|---|---|---|
| 0.4 | 0.1 | 1 | 0 |
| 0 | 0.3 | 0 | 1 |
Excel formula:
=DLYAP({0.4,0.1;0,0.3}, {1,0;0,1})
Expected output:
| Result | |
|---|---|
| 1.20713 | 0.0374625 |
| 0.0374625 | 1.0989 |
Example 4: Scalar discrete Sylvester equation
Inputs:
| A | Q | C |
|---|---|---|
| 0.5 | 0.4 | 1 |
Excel formula:
=DLYAP({0.5}, {0.4}, {1})
Expected output:
1.25
Python Code
Show Code
import control as ct
import numpy as np
def dlyap(A, Q, C=None):
"""
Solve the discrete-time Lyapunov equation.
See: https://python-control.readthedocs.io/en/latest/generated/control.dlyap.html
This example function is provided as-is without any representation of accuracy.
Args:
A (list[list]): Square matrix A.
Q (list[list]): Square symmetric matrix Q.
C (list[list], optional): Optional matrix C for solving the Sylvester equation. Default is None.
Returns:
list[list]: The solution matrix X.
"""
try:
def to_np(x):
if x is None:
return None
if not isinstance(x, list):
return np.array([[float(x)]])
if x and not isinstance(x[0], list):
x = [x]
return np.array([[float(v) if v is not None and str(v) != "" else 0.0 for v in row] for row in x])
a_np = to_np(A)
q_np = to_np(Q)
c_np = to_np(C)
try:
X = ct.dlyap(a_np, q_np, C=c_np)
except Exception:
if c_np is None:
raise
left = np.eye(a_np.shape[0] * q_np.shape[0]) - np.kron(q_np, a_np)
right = c_np.reshape(-1, order="F")
X = np.linalg.solve(left, right).reshape((a_np.shape[0], q_np.shape[0]), order="F")
x_array = np.asarray(X, dtype=float)
if x_array.ndim == 0:
return [[float(x_array)]]
return x_array.tolist()
except Exception as e:
return f"Error: {str(e)}"Online Calculator
GRAM
This function computes either the controllability Gramian, the observability Gramian, or a Cholesky factor of one of those matrices for a continuous-time state-space model.
A W_c + W_c A^T + B B^T = 0
A^T W_o + W_o A + C^T C = 0
The controllability Gramian measures the input energy needed to reach state directions, while the observability Gramian measures how strongly state directions appear in the outputs. These matrices are standard tools in balanced realization, model reduction, and control system diagnostics.
Excel Usage
=GRAM(A, B, C, D, gram_type)
A(list[list], required): State dynamics matrix A.B(list[list], required): Input matrix B.C(list[list], required): Output matrix C.D(list[list], required): Feedthrough matrix D.gram_type(str, required): Type of Gramian computation (‘c’, ‘o’, ‘cf’, or ‘of’).
Returns (list[list]): The requested Gramian matrix.
Example 1: Controllability Gramian
Inputs:
| A | B | C | D | gram_type | ||
|---|---|---|---|---|---|---|
| -1 | 0 | 1 | 1 | 1 | 0 | c |
| 0 | -2 | 1 |
Excel formula:
=GRAM({-1,0;0,-2}, {1;1}, {1,1}, {0}, "c")
Expected output:
| Result | |
|---|---|
| 0.5 | 0.333333 |
| 0.333333 | 0.25 |
Example 2: Observability Gramian for stable second-order system
Inputs:
| A | B | C | D | gram_type | ||
|---|---|---|---|---|---|---|
| -1 | 0 | 1 | 1 | 1 | 0 | o |
| 0 | -2 | 1 |
Excel formula:
=GRAM({-1,0;0,-2}, {1;1}, {1,1}, {0}, "o")
Expected output:
| Result | |
|---|---|
| 0.5 | 0.333333 |
| 0.333333 | 0.25 |
Example 3: Cholesky factor of controllability Gramian
Inputs:
| A | B | C | D | gram_type | ||
|---|---|---|---|---|---|---|
| -1 | 0 | 1 | 1 | 1 | 0 | cf |
| 0 | -2 | 1 |
Excel formula:
=GRAM({-1,0;0,-2}, {1;1}, {1,1}, {0}, "cf")
Expected output:
| Result | |
|---|---|
| 0.707107 | 0.471405 |
| 0 | 0.166667 |
Example 4: Cholesky factor of observability Gramian
Inputs:
| A | B | C | D | gram_type | ||
|---|---|---|---|---|---|---|
| -1 | 0 | 1 | 1 | 1 | 0 | of |
| 0 | -2 | 1 |
Excel formula:
=GRAM({-1,0;0,-2}, {1;1}, {1,1}, {0}, "of")
Expected output:
| Result | |
|---|---|
| 0.707107 | 0.471405 |
| 0 | 0.166667 |
Python Code
Show Code
import control as ct
import numpy as np
from scipy.linalg import cholesky, solve_continuous_lyapunov
def gram(A, B, C, D, gram_type):
"""
Compute the Gramian (controllability or observability).
See: https://python-control.readthedocs.io/en/latest/generated/control.gram.html
This example function is provided as-is without any representation of accuracy.
Args:
A (list[list]): State dynamics matrix A.
B (list[list]): Input matrix B.
C (list[list]): Output matrix C.
D (list[list]): Feedthrough matrix D.
gram_type (str): Type of Gramian computation ('c', 'o', 'cf', or 'of'). Valid options: Controllability, Observability, Controllability Cholesky, Observability Cholesky.
Returns:
list[list]: The requested Gramian matrix.
"""
try:
def to_np(x):
if x is None:
return None
if not isinstance(x, list):
return np.array([[float(x)]])
if x and not isinstance(x[0], list):
x = [x]
return np.array([[float(v) if v is not None and str(v) != "" else 0.0 for v in row] for row in x])
a_np = to_np(A)
b_np = to_np(B)
c_np = to_np(C)
d_np = to_np(D)
sys = ct.ss(a_np, b_np, c_np, d_np)
try:
W = ct.gram(sys, gram_type)
return W.tolist()
except Exception:
if gram_type == "c":
W = solve_continuous_lyapunov(a_np, -(b_np @ b_np.T))
return W.tolist()
if gram_type == "o":
W = solve_continuous_lyapunov(a_np.T, -(c_np.T @ c_np))
return W.tolist()
if gram_type == "cf":
Wc = solve_continuous_lyapunov(a_np, -(b_np @ b_np.T))
Rc = cholesky(Wc, lower=False)
return Rc.tolist()
if gram_type == "of":
Wo = solve_continuous_lyapunov(a_np.T, -(c_np.T @ c_np))
Ro = cholesky(Wo, lower=False)
return Ro.tolist()
return "Error: gram_type must be one of c, o, cf, of"
except Exception as e:
return f"Error: {str(e)}"Online Calculator
LYAP
This function solves the continuous-time Lyapunov equation for stable linear systems and also supports the related Sylvester equation form.
A X + X A^T + Q = 0
A X + X Q + C = 0
The solution matrix X appears in stability analysis, covariance calculations, and controllability or observability Gramian computations. Providing the optional matrix C switches the calculation to the Sylvester equation supported by the wrapped library routine.
Excel Usage
=LYAP(A, Q, C)
A(list[list], required): Square matrix A.Q(list[list], required): Square symmetric matrix Q (or Q for Sylvester equation).C(list[list], optional, default: null): Optional matrix C for solving the Sylvester equation.
Returns (list[list]): The solution matrix X.
Example 1: Stable system Lyapunov solution
Inputs:
| A | Q | ||
|---|---|---|---|
| -1 | 0 | 1 | 0 |
| 0 | -2 | 0 | 1 |
Excel formula:
=LYAP({-1,0;0,-2}, {1,0;0,1})
Expected output:
| Result | |
|---|---|
| 0.5 | 0 |
| 0 | 0.25 |
Example 2: Scalar continuous Lyapunov equation
Inputs:
| A | Q |
|---|---|
| -2 | 4 |
Excel formula:
=LYAP({-2}, {4})
Expected output:
1
Example 3: Coupled stable continuous system
Inputs:
| A | Q | ||
|---|---|---|---|
| -1 | 1 | 1 | 0 |
| 0 | -2 | 0 | 1 |
Excel formula:
=LYAP({-1,1;0,-2}, {1,0;0,1})
Expected output:
| Result | |
|---|---|
| 0.583333 | 0.0833333 |
| 0.0833333 | 0.25 |
Example 4: Scalar continuous Sylvester equation
Inputs:
| A | Q | C |
|---|---|---|
| -1 | -2 | 3 |
Excel formula:
=LYAP({-1}, {-2}, {3})
Expected output:
1
Python Code
Show Code
import control as ct
import numpy as np
def lyap(A, Q, C=None):
"""
Solve the continuous-time Lyapunov equation.
See: https://python-control.readthedocs.io/en/latest/generated/control.lyap.html
This example function is provided as-is without any representation of accuracy.
Args:
A (list[list]): Square matrix A.
Q (list[list]): Square symmetric matrix Q (or Q for Sylvester equation).
C (list[list], optional): Optional matrix C for solving the Sylvester equation. Default is None.
Returns:
list[list]: The solution matrix X.
"""
try:
def to_np(x):
if x is None:
return None
if not isinstance(x, list):
return np.array([[float(x)]])
if x and not isinstance(x[0], list):
x = [x]
return np.array([[float(v) if v is not None and str(v) != "" else 0.0 for v in row] for row in x])
a_np = to_np(A)
q_np = to_np(Q)
c_np = to_np(C)
X = ct.lyap(a_np, q_np, C=c_np)
return X.tolist()
except Exception as e:
return f"Error: {str(e)}"Online Calculator
OBSV
This function builds the observability matrix for a linear state-space system with state matrix A and output matrix C.
\mathcal{O} = \begin{bmatrix} C \\ C A \\ C A^2 \\ \vdots \\ C A^{n-1} \end{bmatrix}
A system is observable when this matrix has full rank, meaning the internal state can be reconstructed from output measurements over finite time. The matrix is commonly used when checking whether observer design or state estimation is feasible.
Excel Usage
=OBSV(A, C)
A(list[list], required): State dynamics matrix A.C(list[list], required): Output matrix C.
Returns (list[list]): The observability matrix.
Example 1: Observability of a second order system
Inputs:
| A | C | ||
|---|---|---|---|
| 0 | 1 | 1 | 0 |
| -2 | -3 |
Excel formula:
=OBSV({0,1;-2,-3}, {1,0})
Expected output:
| Result | |
|---|---|
| 1 | 0 |
| 0 | 1 |
Example 2: Single-state observability matrix
Inputs:
| A | C |
|---|---|
| 2 | 3 |
Excel formula:
=OBSV({2}, {3})
Expected output:
3
Example 3: Two-state system with two output channels
Inputs:
| A | C | ||
|---|---|---|---|
| 1 | 0 | 1 | 0 |
| 0 | 2 | 0 | 1 |
Excel formula:
=OBSV({1,0;0,2}, {1,0;0,1})
Expected output:
| Result | |
|---|---|
| 1 | 0 |
| 0 | 1 |
| 1 | 0 |
| 0 | 2 |
Example 4: Double integrator observability matrix
Inputs:
| A | C | ||
|---|---|---|---|
| 0 | 1 | 1 | 0 |
| 0 | 0 |
Excel formula:
=OBSV({0,1;0,0}, {1,0})
Expected output:
| Result | |
|---|---|
| 1 | 0 |
| 0 | 1 |
Python Code
Show Code
import control as ct
import numpy as np
def obsv(A, C):
"""
Compute the observability matrix.
See: https://python-control.readthedocs.io/en/latest/generated/control.obsv.html
This example function is provided as-is without any representation of accuracy.
Args:
A (list[list]): State dynamics matrix A.
C (list[list]): Output matrix C.
Returns:
list[list]: The observability matrix.
"""
try:
def to_np(x):
if x is None:
return None
if not isinstance(x, list):
return np.array([[float(x)]])
if x and not isinstance(x[0], list):
x = [x]
return np.array([[float(v) if v is not None and str(v) != "" else 0.0 for v in row] for row in x])
a_np = to_np(A)
c_np = to_np(C)
O = ct.obsv(a_np, c_np)
return O.tolist()
except Exception as e:
return f"Error: {str(e)}"Online Calculator