ctrb function returns NaN or inf when dealing with large systems

I’m currently working with continuous-time, large state-space systems — specifically, systems with a number of states on the order of 10^3, and numbers of inputs and outputs on the order of 10^2.
I’m trying to analyze the reachability and observability properties of these systems. To that end, I’ve been using MATLAB’s ctrb function, which, according to the documentation, returns the reachability matrix. However, I’ve encountered a major issue: the resulting matrix (Co) contains a significant number of NaN and Inf entries.
For reference, in one example the matrix Co has dimensions 1,624 x 311,808, resulting in a total of 506,376,192 elements. Of these:
  • 466,771,919 entries (92.18%) are NaN, counted with sum(isnan(Co), 'all')
  • 37,732 entries (0.0075%) are Inf or -Inf, counted with sum(isinf(Co), 'all')
Has anyone encountered a similar issue when working with large-scale systems?
How did you handle it or work around it?
Any suggestions, tips, or alternative methods would be highly appreciated!

9 Comments

Just a test. It seems that the number of states cannot exceed 348!
Case 1:
n = 348; % number of states
p = - ones(1, n); % 100% stable poles
G = zpk([], p, prod(p)); % transfer function
% sys = canon(G, 'companion') % The "canon" command failed because the controllability matrix is nearly singular.
sys = compreal(G); % convert ot state-space
rk = rank(ctrb(sys.A, sys.B))
rk = 348
Case 2:
n = 349; % number of states
p = - ones(1, n); % 100% stable poles
G = zpk([], p, prod(p)); % transfer function
sys = compreal(G); % convert ot state-space
Error using DynamicSystem/compreal (line 64)
State coordinate transformation T is singular to working precision.
rk = rank(ctrb(sys.A, sys.B))
Case 3: An unexplainable result?
n = 250; % number of states
sys = rss(n); % generate random continuous-time state-space
Tf = isstable(sys)
Tf = logical
1
rk = rank(ctrb(sys.A, sys.B))
Error using rank (line 17)
Input matrix must not contain NaN or Inf values.
Basing on the idea of @Sam Chak, I run the following script multiple time (also with different n). It seems like (but I am not sure at all) that it is correlated to the fact that the matrix A (and B if more than 1 input) is bad conditioned and for a certain degenerates to values close to infinity. I don't have any idea on how to treat that, a part from checking manually the presence of numerical schemes that leads to, at least, two rows linearly dependent and hence concluding the matrix Co can never be full rank. However this is unfeasible with problems like mine, where size(B) is ~10^3 x 10^2.
n = 250;
sys = rss(n);
Tf = isstable(sys)
Tf = logical
0
try
rk = rank(ctrb(sys.A, sys.B)) % Check reachability with Matlab function
catch ME
warning("ctrb gave the following error: \n\t %s \n", ME.message)
end
Warning: ctrb gave the following error:
Input matrix must not contain NaN or Inf values.
% Check reachability by hand
A = sys.A; B = sys.B; % Scomposing them for simplicity
Aprod = sys.A;
Co = [B, Aprod*B];
for ii = 2:n-1
fprintf("n = %d, cond(Aprod) = %.3e\n", ii-1, cond(Aprod));
Aprod = Aprod*A; % A^n = A^(n-1)*A
product = Aprod*B; % in C0 goes A^n*B
try
assert(sum(isnan(product), 'all')==0, 'Elements in product are NaN: #: %d, iteration: %d, rank(C0) = %d', ...
sum(isnan(product), 'all'), ii, rank(Co)); % Check if NaN
assert(sum(isinf(product), 'all')==0, 'Elements in product are Inf: #: %d, iteration: %d, rank(C0) = %d', ...
sum(isinf(product), 'all'), ii, rank(Co)); % Check if Inf
catch e
disp(product) % Show where the cycle broke
rethrow(e)
end
Co = [Co, product];
if rank(Co) == n, fprintf('Iterations: %d', ii); break; end
end
n = 1, cond(Aprod) = 2.515e+18 n = 2, cond(Aprod) = 5.345e+16 n = 3, cond(Aprod) = 4.921e+16 n = 4, cond(Aprod) = 4.740e+16 n = 5, cond(Aprod) = 7.858e+16 n = 6, cond(Aprod) = 3.381e+17 n = 7, cond(Aprod) = 6.471e+17 n = 8, cond(Aprod) = 1.481e+17 n = 9, cond(Aprod) = 1.330e+18 n = 10, cond(Aprod) = 5.945e+17 n = 11, cond(Aprod) = 3.363e+18 n = 12, cond(Aprod) = 9.282e+17 n = 13, cond(Aprod) = 8.455e+17 n = 14, cond(Aprod) = 6.964e+18 n = 15, cond(Aprod) = 2.229e+18 n = 16, cond(Aprod) = 3.311e+18 n = 17, cond(Aprod) = 5.009e+18 n = 18, cond(Aprod) = 6.142e+18 n = 19, cond(Aprod) = 3.317e+18 n = 20, cond(Aprod) = 9.548e+18 n = 21, cond(Aprod) = 2.108e+19 n = 22, cond(Aprod) = 1.435e+19 n = 23, cond(Aprod) = 3.289e+18 n = 24, cond(Aprod) = 3.192e+18 n = 25, cond(Aprod) = 4.275e+19 n = 26, cond(Aprod) = 8.927e+18 n = 27, cond(Aprod) = 5.331e+18 n = 28, cond(Aprod) = 7.505e+18 n = 29, cond(Aprod) = 3.137e+18 n = 30, cond(Aprod) = 1.183e+19 n = 31, cond(Aprod) = 1.016e+19 n = 32, cond(Aprod) = 3.917e+18 n = 33, cond(Aprod) = 1.258e+19 n = 34, cond(Aprod) = 2.716e+20 n = 35, cond(Aprod) = 1.048e+19 n = 36, cond(Aprod) = 1.236e+19 n = 37, cond(Aprod) = 2.806e+18 n = 38, cond(Aprod) = 4.793e+18 n = 39, cond(Aprod) = 5.919e+19 n = 40, cond(Aprod) = 1.646e+19 n = 41, cond(Aprod) = 7.777e+18 n = 42, cond(Aprod) = 5.021e+18 n = 43, cond(Aprod) = 4.684e+18 n = 44, cond(Aprod) = 4.719e+18 n = 45, cond(Aprod) = 2.933e+19 n = 46, cond(Aprod) = 6.558e+18 n = 47, cond(Aprod) = 5.299e+19 n = 48, cond(Aprod) = 2.916e+18 n = 49, cond(Aprod) = 4.114e+18 n = 50, cond(Aprod) = 1.549e+19 n = 51, cond(Aprod) = 2.761e+18 n = 52, cond(Aprod) = 2.026e+19 n = 53, cond(Aprod) = 3.382e+19 n = 54, cond(Aprod) = 6.800e+18 n = 55, cond(Aprod) = 5.610e+18 n = 56, cond(Aprod) = 1.598e+19 n = 57, cond(Aprod) = 1.334e+20 n = 58, cond(Aprod) = 7.487e+19 n = 59, cond(Aprod) = 3.862e+18 n = 60, cond(Aprod) = 1.339e+19 n = 61, cond(Aprod) = 3.762e+18 n = 62, cond(Aprod) = 1.613e+19 n = 63, cond(Aprod) = 8.166e+18 n = 64, cond(Aprod) = 1.376e+19 n = 65, cond(Aprod) = 2.074e+19 n = 66, cond(Aprod) = 1.874e+19 n = 67, cond(Aprod) = 5.831e+18 n = 68, cond(Aprod) = 7.854e+19 n = 69, cond(Aprod) = 7.724e+18 n = 70, cond(Aprod) = 4.501e+18 n = 71, cond(Aprod) = 9.466e+19 n = 72, cond(Aprod) = 6.273e+18 n = 73, cond(Aprod) = 5.975e+18 n = 74, cond(Aprod) = 9.613e+18 n = 75, cond(Aprod) = 5.170e+18 n = 76, cond(Aprod) = 7.725e+18 n = 77, cond(Aprod) = 4.896e+18 n = 78, cond(Aprod) = 4.887e+18 n = 79, cond(Aprod) = 6.545e+18 n = 80, cond(Aprod) = 2.638e+19 n = 81, cond(Aprod) = 3.499e+18 n = 82, cond(Aprod) = 3.507e+19 n = 83, cond(Aprod) = 7.958e+18 n = 84, cond(Aprod) = 3.324e+19 n = 85, cond(Aprod) = 3.042e+18 n = 86, cond(Aprod) = 1.166e+19 n = 87, cond(Aprod) = 1.229e+19 n = 88, cond(Aprod) = 1.655e+19 n = 89, cond(Aprod) = 1.187e+19 n = 90, cond(Aprod) = 1.261e+19 n = 91, cond(Aprod) = 6.138e+18 n = 92, cond(Aprod) = 1.160e+19 n = 93, cond(Aprod) = 2.119e+19 n = 94, cond(Aprod) = 7.115e+18 n = 95, cond(Aprod) = 6.350e+19 n = 96, cond(Aprod) = 2.077e+19 n = 97, cond(Aprod) = 2.869e+19 n = 98, cond(Aprod) = 1.023e+19 n = 99, cond(Aprod) = 4.673e+18 n = 100, cond(Aprod) = 5.034e+19 n = 101, cond(Aprod) = 1.138e+19 n = 102, cond(Aprod) = 9.108e+18 n = 103, cond(Aprod) = 1.023e+19 n = 104, cond(Aprod) = 1.203e+19 n = 105, cond(Aprod) = 1.053e+19 n = 106, cond(Aprod) = 1.086e+19 n = 107, cond(Aprod) = 2.101e+19 n = 108, cond(Aprod) = 1.408e+19 n = 109, cond(Aprod) = 5.525e+18 n = 110, cond(Aprod) = 7.675e+18 n = 111, cond(Aprod) = 3.772e+19 n = 112, cond(Aprod) = 1.886e+19 n = 113, cond(Aprod) = 9.469e+18 n = 114, cond(Aprod) = 1.426e+19 n = 115, cond(Aprod) = 4.684e+19 n = 116, cond(Aprod) = 6.502e+19 n = 117, cond(Aprod) = 1.091e+19 n = 118, cond(Aprod) = 6.874e+18 n = 119, cond(Aprod) = 1.224e+19 n = 120, cond(Aprod) = 1.756e+19 n = 121, cond(Aprod) = 2.361e+19 n = 122, cond(Aprod) = 5.952e+18 n = 123, cond(Aprod) = 6.125e+18 n = 124, cond(Aprod) = 1.496e+19 n = 125, cond(Aprod) = 1.972e+19 n = 126, cond(Aprod) = 9.634e+18 n = 127, cond(Aprod) = 1.010e+19 n = 128, cond(Aprod) = 1.407e+19 n = 129, cond(Aprod) = 1.153e+19 n = 130, cond(Aprod) = 2.021e+19 n = 131, cond(Aprod) = 1.989e+21 n = 132, cond(Aprod) = 6.898e+18 n = 133, cond(Aprod) = 4.705e+18 n = 134, cond(Aprod) = 7.044e+18 n = 135, cond(Aprod) = 6.665e+18 n = 136, cond(Aprod) = 2.300e+19 n = 137, cond(Aprod) = 1.115e+19 n = 138, cond(Aprod) = 5.518e+18 n = 139, cond(Aprod) = 1.444e+19 n = 140, cond(Aprod) = 8.089e+18 n = 141, cond(Aprod) = 6.725e+19 n = 142, cond(Aprod) = 2.282e+20 n = 143, cond(Aprod) = 7.383e+18 n = 144, cond(Aprod) = 8.294e+18 n = 145, cond(Aprod) = 3.144e+19 n = 146, cond(Aprod) = 5.939e+19 n = 147, cond(Aprod) = 1.483e+19 n = 148, cond(Aprod) = 1.020e+20 n = 149, cond(Aprod) = 6.676e+19 n = 150, cond(Aprod) = 2.194e+19 n = 151, cond(Aprod) = 6.514e+18 n = 152, cond(Aprod) = 1.050e+19 n = 153, cond(Aprod) = 1.924e+19 n = 154, cond(Aprod) = 1.134e+19 n = 155, cond(Aprod) = 6.756e+18 n = 156, cond(Aprod) = 1.011e+19 n = 157, cond(Aprod) = 5.306e+18 n = 158, cond(Aprod) = 8.498e+18 n = 159, cond(Aprod) = 1.464e+19 n = 160, cond(Aprod) = 6.854e+19 n = 161, cond(Aprod) = 1.753e+19 n = 162, cond(Aprod) = 4.260e+19 n = 163, cond(Aprod) = 8.502e+20 n = 164, cond(Aprod) = 8.105e+18 n = 165, cond(Aprod) = 4.874e+18 n = 166, cond(Aprod) = 4.972e+18 n = 167, cond(Aprod) = 8.550e+18 n = 168, cond(Aprod) = 1.792e+19 n = 169, cond(Aprod) = 3.858e+19 n = 170, cond(Aprod) = 6.387e+18 n = 171, cond(Aprod) = 1.031e+20 n = 172, cond(Aprod) = 3.930e+19 n = 173, cond(Aprod) = 4.934e+18 n = 174, cond(Aprod) = 8.472e+18 n = 175, cond(Aprod) = 1.441e+19 n = 176, cond(Aprod) = 1.347e+19 n = 177, cond(Aprod) = 7.289e+18 n = 178, cond(Aprod) = 2.121e+19 n = 179, cond(Aprod) = 8.325e+18 n = 180, cond(Aprod) = 4.816e+18 n = 181, cond(Aprod) = 1.275e+19 n = 182, cond(Aprod) = 5.212e+18 n = 183, cond(Aprod) = 1.521e+19 n = 184, cond(Aprod) = 9.254e+19 n = 185, cond(Aprod) = 2.526e+19 n = 186, cond(Aprod) = 4.199e+18 n = 187, cond(Aprod) = 3.888e+20 n = 188, cond(Aprod) = 7.487e+18 n = 189, cond(Aprod) = 1.982e+19 n = 190, cond(Aprod) = 8.343e+18 n = 191, cond(Aprod) = 1.441e+19 n = 192, cond(Aprod) = 8.856e+19 n = 193, cond(Aprod) = 1.266e+19 n = 194, cond(Aprod) = 1.570e+19 n = 195, cond(Aprod) = 7.845e+18 n = 196, cond(Aprod) = 2.584e+19 n = 197, cond(Aprod) = 7.343e+18 n = 198, cond(Aprod) = 1.440e+19 n = 199, cond(Aprod) = 7.202e+18 n = 200, cond(Aprod) = 9.070e+18 n = 201, cond(Aprod) = 1.605e+20 n = 202, cond(Aprod) = 5.150e+18 n = 203, cond(Aprod) = 6.125e+18 n = 204, cond(Aprod) = 2.140e+19 n = 205, cond(Aprod) = 9.008e+18 n = 206, cond(Aprod) = 8.905e+18 n = 207, cond(Aprod) = 3.955e+20 n = 208, cond(Aprod) = 1.166e+19 n = 209, cond(Aprod) = 5.470e+18 n = 210, cond(Aprod) = 1.740e+19 n = 211, cond(Aprod) = 4.651e+18 n = 212, cond(Aprod) = 9.072e+18 n = 213, cond(Aprod) = 1.758e+19 n = 214, cond(Aprod) = 1.153e+19 n = 215, cond(Aprod) = 2.662e+19 n = 216, cond(Aprod) = 3.961e+19 n = 217, cond(Aprod) = 2.981e+19 n = 218, cond(Aprod) = 3.718e+18 n = 219, cond(Aprod) = 3.358e+19 n = 220, cond(Aprod) = 1.084e+19 n = 221, cond(Aprod) = 5.854e+18 n = 222, cond(Aprod) = 1.372e+19 n = 223, cond(Aprod) = 1.806e+19 n = 224, cond(Aprod) = 8.535e+18 n = 225, cond(Aprod) = 1.493e+19 n = 226, cond(Aprod) = 8.751e+18 n = 227, cond(Aprod) = 4.063e+18 n = 228, cond(Aprod) = 7.622e+18 n = 229, cond(Aprod) = 1.049e+19 n = 230, cond(Aprod) = 3.874e+19 n = 231, cond(Aprod) = 4.137e+18 n = 232, cond(Aprod) = 1.804e+19 n = 233, cond(Aprod) = 2.602e+20 n = 234, cond(Aprod) = 1.163e+19 n = 235, cond(Aprod) = 3.133e+20 n = 236, cond(Aprod) = 1.132e+19 n = 237, cond(Aprod) = 9.293e+18 n = 238, cond(Aprod) = 2.417e+19 n = 239, cond(Aprod) = 9.998e+18 n = 240, cond(Aprod) = 1.803e+19 n = 241, cond(Aprod) = 4.032e+18 n = 242, cond(Aprod) = 9.789e+18 n = 243, cond(Aprod) = 1.761e+19
1.0e+307 * -1.9483 NaN NaN NaN NaN NaN NaN NaN NaN 0.9973 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 0.8600 NaN NaN NaN -2.5083 NaN NaN 1.3415 -1.7728 0.0180 NaN NaN NaN NaN NaN 0.3482 NaN NaN 2.1591 NaN NaN NaN -1.4826 NaN 2.2424 NaN -0.9892 NaN NaN NaN NaN NaN NaN 0.3367 NaN NaN -0.9895 NaN NaN 1.7588 NaN 1.6317 0.5369 -0.0271 NaN 2.3999 2.1880 -1.6192 1.3580 NaN 1.7181 -1.2600 NaN NaN NaN NaN NaN NaN -0.0814 -0.5130 NaN NaN NaN -0.9718 NaN NaN NaN 2.3310 NaN 1.8353 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -0.5419 NaN 1.6304 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -0.7340 NaN NaN NaN -2.2289 NaN NaN -1.5566 NaN NaN NaN NaN NaN NaN -1.2478 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -2.2617 NaN NaN NaN NaN NaN NaN NaN -0.3120 NaN NaN NaN NaN NaN NaN NaN NaN NaN -0.1847 -1.9592 NaN NaN NaN 0.0630 NaN NaN NaN NaN 1.4949 NaN NaN 1.2203 NaN NaN NaN NaN NaN 1.9728 NaN NaN NaN NaN NaN 0.0233 -1.4690 NaN 0.1451 NaN 0.5902 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 0.8356 -0.6941 NaN -1.3033 NaN -0.5142 NaN NaN NaN -0.0953 -1.6254 NaN NaN NaN NaN 0.3875 NaN 0.1160 NaN 0.7635 NaN -1.6012 NaN -0.1475 NaN -1.4020 NaN NaN NaN 0.9109 NaN 0.8559 NaN NaN NaN NaN NaN NaN NaN NaN -2.1431 NaN 1.2509 NaN NaN -1.4559 NaN
Error using assert
Elements in product are NaN: #: 186, iteration: 244, rank(C0) = 2
rk = rank(Co)
@Mathieu NOE I have considered this idea. However, to the best of my knowledge, this approach allows proving the reachability (or, by duality, observability) only for the reduced system. I believe the result cannot be extended to the full system.
If this is not the case, could you please provide a reference where I can find a proof or discussion showing that results obtained for the reduced system can be extended to the full system? Thank you in advance.
Sure , a reduced order system cannot be compared or taken as 100% "equivalent" to the full system. Now the engineer must ask himself what does it mean to remove the poorly reachable / observable states ? Is it still physically meaningfull ?
Case 5: The ctrb() function can handle systems with a number of states greater than 1,000.
n = 2000; % number of states
A0 = zeros(n, 1);
A1 = eye(n);
A1(:,n) = [];
A = [A0, A1]; % State matrix
B = zeros(sqrt(numel(A)), 1);
B(end) = 1; % Input matrix
Co = ctrb(A, B); % Controllability matrix
rk = rank(Co) % expect to return rk = n
rk = 2000
Hi Corby,
I think the fundamental problem that forming the controllability matrix necessarily means raising the system matrix to a large power, which at some point will overflow if the spectral radius is greater than unity and n is large enough. I think you touched on this issue in this comment, though I don't think that necessarily means the system matrix is poorly conditioned.
For example
rng(100);
n = 250;
sys = rss(n,1,5);
size(sys)
State-space model with 1 outputs, 5 inputs, and 250 states.
rss should generate a stable system
Tf = isstable(sys)
Tf = logical
0
but it doesn't because
max(real(eig(sys.a)))
ans = 7.6458e-14
So shift the A matrix to ensure stability (do you know your system is stable?)
sys.a = sys.a - eye(n);
max(real(eig(sys.a)))
ans = -1.0000
We see that raising the system matrix to the i'th power breaks down at i = 195
for ii = 1:n
if any(isnan(sys.A^ii),'all') || any(isinf(sys.A^ii),'all')
break
end
end
ii
ii = 195
At i = 194, elements are getting close to realmax
[max(sys.A^(ii-1),[],'all') , min(sys.A^(ii-1),[],'all'), realmax]
ans = 1×3
1.0e+308 * 0.1267 -0.1341 1.7977
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
The spectral radius of the system matrix is
r = max(abs(eig(sys.A)))
r = 38.4665
The spectral radius of A^n is r^n, so we might estimate the maximum achievable n as
nlimit = log(realmax)/log(r)
nlimit = 194.4723
which at least tracks nicely with the result above, though I don't really know how rigorous that really is.
Anyway, that leaves us searching for other ways to test for controllability.
One option is to compute the controllability Gramian
Wc = gram(sys,'c');
which at least is returning a finite result
all(isfinite(Wc),'all')
ans = logical
1
By definiton the Gramian is symmetric
issymmetric(Wc)
ans = logical
1
It it positive definite if (A,B) are a controllable pair.
The simple test would be
e = eig(Wc);
all(imag(e)==0)
ans = logical
1
min(e)
ans = -6.4753e-13
Taken literally, that means the systme is not controllable (would that be miraculous for a randomly generated system?).
Or we can use chol to test, and it too fails.
try
C = chol(Wc)
catch ME
ME.message
end
ans = 'Matrix must be positive definite.'
Does that mean they system isn't controllable? Or does that mean we are suffering from numerical issues in one of the steps along the way?
Another option might be to tranform the system to modal form. I think a sufficient condition for controllability is that every row of the transformed B matrix has at least one non-zero entry (check that)
sysm = modalreal(sys);
all(any(sysm.b,2))
ans = logical
1
Of course, here we could have the problem where a value is very close to zero. Here that's not the case.
min(min(abs(sysm.b),[],2))
ans = 0.0122
Or try a balanced realization (balreal)
In any case, there might be options besides checking the controllability matrix. Also, consider looking into other numerical conditioning schemes.
Seems like a hard problem in general.
If you don't mind, what kind of system is being modeled?
More importantly, why is it important to know if the system is controllable? What would that information be used for if it could be accurately ascertained?
Dear @Paul, Thank you for your kind answer. The Gramian seems like a very clever way to assess controllability.
The system in question models the eddy current response of a 3D structure to external magnetic field variations.
Controllability is of interest because, if confirmed, it would imply that a desired eddy current pattern can be achieved by controlling a finite set of currents.

Sign in to comment.

 Accepted Answer

Thank you and Paul for explaining why the ctrb() function fails for very high-order LTI systems when the spectral radius of the state matrix exceeds the realmax value. The Controllability Gramian is also an effective approach to assess the system's controllability through the Lyapunov equation.
However, when dealing with very high-order LTI systems, we can use the Hautus Lemma, commonly known as the Popov-Belevitch-Hautus test, not only to determine the controllability of the system but also to identify the minimum number of control inputs required to render the LTI system controllable. I highly recommend watching Prof. Steve Brunton's video.
Simple code for the Popov-Belevitch-Hautus (PBH) test:
%% State-space system
n = 500; % number of system states
sys = rss(n); % random state-space
%% Setting for PBH Test
tol = 1e-16; % tolerance to use in the rank computation
%% Call isctrb() to determine controllability
TF = isctrb(sys, tol)
The system is controllable.
TF = 1
%% Code for Popov-Belevitch-Hautus (PBH) test
function TF = isctrb(sys, tol)
% Extract state and input matrices from the system
A = sys.A; % state matrix from sys
B = sys.B; % input matrix from sys
% Find eigenvalues of the system
p = eig(A); % eigenvalues (poles)
ns = sqrt(numel(A)); % number of states
I = eye(ns); % identity matrix
% Initialize rank vector
rk = zeros(ns, 1);
% Perform PBH test
for i = 1:ns
rk(i) = rank([A-p(i)*I, B], tol);
% can break here; not need to loop all
if rk(i) ~= ns
break
end
end
% Display result
if any(rk ~= ns, 'all')
TF = 0;
disp('The system is not controllable.');
else
TF = 1;
disp('The system is controllable.');
end
end

2 Comments

Good idea to investigate the PBH test.
Would there be any concerns with determining rank of the test matrix, which involves a tolerance? Because we don't need to know the exact rank, only whether or not it's full rank, perhaps it would be better to just look at its minimum singular value (svd), but that will still involve a judgement against a tolerance. I have no idea what to expect for accuracy of svd for matrices of this scale, especially for the minimum singular value.
Hi @Paul, thank you for your advice. The code was written hastily yesterday. I have tested it, and the rank computation indeed has issues for systems with ill-conditioned state matrices (after being transformed from equivalent well-conditioned matrices). Allowing users to specify the tolerance helps to alleviate this issue.
Hi @Corby, I have updated the code for the PBH test. Please take a look if you are interested.
Both of you are welcome to improve the code as needed.

Sign in to comment.

More Answers (0)

Categories

Products

Release

R2024b

Asked:

on 7 Apr 2025

Commented:

on 9 Apr 2025

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!