Skip to content

Commit e10b798

Browse files
author
Henrik Sandberg
committed
* In sysnorm: Warnings now of type UserWarning
* In sysnorm_test: Use pytest.warns context manager
1 parent a95daaf commit e10b798

File tree

2 files changed

+41
-30
lines changed

2 files changed

+41
-30
lines changed

control/sysnorm.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def _h2norm_slycot(sys, print_warning=True):
5555
if dico == 'C':
5656
if any(D.flat != 0):
5757
if print_warning:
58-
warnings.warn("System has a direct feedthrough term!")
58+
warnings.warn("System has a direct feedthrough term!", UserWarning)
5959
return float("inf")
6060
else:
6161
return 0.0
@@ -67,15 +67,15 @@ def _h2norm_slycot(sys, print_warning=True):
6767
except SlycotArithmeticError as e:
6868
if e.info == 3:
6969
if print_warning:
70-
warnings.warn("System has pole(s) on the stability boundary!")
70+
warnings.warn("System has pole(s) on the stability boundary!", UserWarning)
7171
return float("inf")
7272
elif e.info == 5:
7373
if print_warning:
74-
warnings.warn("System has a direct feedthrough term!")
74+
warnings.warn("System has a direct feedthrough term!", UserWarning)
7575
return float("inf")
7676
elif e.info == 6:
7777
if print_warning:
78-
warnings.warn("System is unstable!")
78+
warnings.warn("System is unstable!", UserWarning)
7979
return float("inf")
8080
else:
8181
raise e
@@ -91,7 +91,7 @@ def norm(system, p=2, tol=1e-10, print_warning=True, method=None):
9191
system : LTI (:class:`StateSpace` or :class:`TransferFunction`)
9292
System in continuous or discrete time for which the norm should be computed.
9393
p : int or str
94-
Type of norm to be computed. p=2 gives the H2 norm, and p='inf' gives the L-infinity norm.
94+
Type of norm to be computed. ``p=2`` gives the H2 norm, and ``p='inf'`` gives the L-infinity norm.
9595
tol : float
9696
Relative tolerance for accuracy of L-infinity norm computation. Ignored
9797
unless p='inf'.
@@ -145,15 +145,15 @@ def norm(system, p=2, tol=1e-10, print_warning=True, method=None):
145145
poles_real_part = G.poles().real
146146
if any(np.isclose(poles_real_part, 0.0)): # Poles on imaginary axis
147147
if print_warning:
148-
warnings.warn("Poles close to, or on, the imaginary axis. Norm value may be uncertain.")
148+
warnings.warn("Poles close to, or on, the imaginary axis. Norm value may be uncertain.", UserWarning)
149149
return float('inf')
150150
elif any(poles_real_part > 0.0): # System unstable
151151
if print_warning:
152-
warnings.warn("System is unstable!")
152+
warnings.warn("System is unstable!", UserWarning)
153153
return float('inf')
154154
elif any(D.flat != 0): # System has direct feedthrough
155155
if print_warning:
156-
warnings.warn("System has a direct feedthrough term!")
156+
warnings.warn("System has a direct feedthrough term!", UserWarning)
157157
return float('inf')
158158

159159
else:
@@ -169,7 +169,7 @@ def norm(system, p=2, tol=1e-10, print_warning=True, method=None):
169169
# Test next is a precaution in case the Lyapunov equation is ill conditioned.
170170
if any(la.eigvals(P).real < 0.0):
171171
if print_warning:
172-
warnings.warn("There appears to be poles close to the imaginary axis. Norm value may be uncertain.")
172+
warnings.warn("There appears to be poles close to the imaginary axis. Norm value may be uncertain.", UserWarning)
173173
return float('inf')
174174
else:
175175
norm_value = np.sqrt(np.trace(C@P@C.T)) # Argument in sqrt should be non-negative
@@ -187,11 +187,11 @@ def norm(system, p=2, tol=1e-10, print_warning=True, method=None):
187187
poles_abs = abs(G.poles())
188188
if any(np.isclose(poles_abs, 1.0)): # Poles on imaginary axis
189189
if print_warning:
190-
warnings.warn("Poles close to, or on, the complex unit circle. Norm value may be uncertain.")
190+
warnings.warn("Poles close to, or on, the complex unit circle. Norm value may be uncertain.", UserWarning)
191191
return float('inf')
192192
elif any(poles_abs > 1.0): # System unstable
193193
if print_warning:
194-
warnings.warn("System is unstable!")
194+
warnings.warn("System is unstable!", UserWarning)
195195
return float('inf')
196196

197197
else:
@@ -207,7 +207,7 @@ def norm(system, p=2, tol=1e-10, print_warning=True, method=None):
207207
# Test next is a precaution in case the Lyapunov equation is ill conditioned.
208208
if any(la.eigvals(P).real < 0.0):
209209
if print_warning:
210-
warnings.warn("Warning: There appears to be poles close to the complex unit circle. Norm value may be uncertain.")
210+
warnings.warn("Warning: There appears to be poles close to the complex unit circle. Norm value may be uncertain.", UserWarning)
211211
return float('inf')
212212
else:
213213
norm_value = np.sqrt(np.trace(C@P@C.T + D@D.T)) # Argument in sqrt should be non-negative
@@ -226,12 +226,12 @@ def norm(system, p=2, tol=1e-10, print_warning=True, method=None):
226226
if G.isdtime(): # Discrete time
227227
if any(np.isclose(abs(poles), 1.0)): # Poles on unit circle
228228
if print_warning:
229-
warnings.warn("Poles close to, or on, the complex unit circle. Norm value may be uncertain.")
229+
warnings.warn("Poles close to, or on, the complex unit circle. Norm value may be uncertain.", UserWarning)
230230
return float('inf')
231231
else: # Continuous time
232232
if any(np.isclose(poles.real, 0.0)): # Poles on imaginary axis
233233
if print_warning:
234-
warnings.warn("Poles close to, or on, the imaginary axis. Norm value may be uncertain.")
234+
warnings.warn("Poles close to, or on, the imaginary axis. Norm value may be uncertain.", UserWarning)
235235
return float('inf')
236236

237237
# Use slycot, if available, to compute (finite) norm

control/tests/sysnorm_test.py

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,51 @@
88

99
import control as ct
1010
import numpy as np
11+
import pytest
12+
1113

1214
def test_norm_1st_order_stable_system():
1315
"""First-order stable continuous-time system"""
1416
s = ct.tf('s')
17+
1518
G1 = 1/(s+1)
16-
assert np.allclose(ct.norm(G1, p='inf', tol=1e-9, print_warning=False), 1.0) # Comparison to norm computed in MATLAB
17-
assert np.allclose(ct.norm(G1, p=2, print_warning=False), 0.707106781186547) # Comparison to norm computed in MATLAB
19+
assert np.allclose(ct.norm(G1, p='inf', tol=1e-9 ), 1.0) # Comparison to norm computed in MATLAB
20+
assert np.allclose(ct.norm(G1, p=2), 0.707106781186547) # Comparison to norm computed in MATLAB
1821

1922
Gd1 = ct.sample_system(G1, 0.1)
20-
assert np.allclose(ct.norm(Gd1, p='inf', tol=1e-9, print_warning=False), 1.0) # Comparison to norm computed in MATLAB
21-
assert np.allclose(ct.norm(Gd1, p=2, print_warning=False), 0.223513699524858) # Comparison to norm computed in MATLAB
23+
assert np.allclose(ct.norm(Gd1, p='inf', tol=1e-9), 1.0) # Comparison to norm computed in MATLAB
24+
assert np.allclose(ct.norm(Gd1, p=2), 0.223513699524858) # Comparison to norm computed in MATLAB
2225

2326

2427
def test_norm_1st_order_unstable_system():
2528
"""First-order unstable continuous-time system"""
2629
s = ct.tf('s')
30+
2731
G2 = 1/(1-s)
28-
assert np.allclose(ct.norm(G2, p='inf', tol=1e-9, print_warning=False), 1.0) # Comparison to norm computed in MATLAB
29-
assert ct.norm(G2, p=2, print_warning=False) == float('inf') # Comparison to norm computed in MATLAB
32+
assert np.allclose(ct.norm(G2, p='inf', tol=1e-9), 1.0) # Comparison to norm computed in MATLAB
33+
with pytest.warns(UserWarning, match="System is unstable!"):
34+
assert ct.norm(G2, p=2) == float('inf') # Comparison to norm computed in MATLAB
3035

3136
Gd2 = ct.sample_system(G2, 0.1)
32-
assert np.allclose(ct.norm(Gd2, p='inf', tol=1e-9, print_warning=False), 1.0) # Comparison to norm computed in MATLAB
33-
assert ct.norm(Gd2, p=2, print_warning=False) == float('inf') # Comparison to norm computed in MATLAB
37+
assert np.allclose(ct.norm(Gd2, p='inf', tol=1e-9), 1.0) # Comparison to norm computed in MATLAB
38+
with pytest.warns(UserWarning, match="System is unstable!"):
39+
assert ct.norm(Gd2, p=2) == float('inf') # Comparison to norm computed in MATLAB
3440

3541
def test_norm_2nd_order_system_imag_poles():
3642
"""Second-order continuous-time system with poles on imaginary axis"""
3743
s = ct.tf('s')
44+
3845
G3 = 1/(s**2+1)
39-
assert ct.norm(G3, p='inf', print_warning=False) == float('inf') # Comparison to norm computed in MATLAB
40-
assert ct.norm(G3, p=2, print_warning=False) == float('inf') # Comparison to norm computed in MATLAB
46+
with pytest.warns(UserWarning, match="Poles close to, or on, the imaginary axis."):
47+
assert ct.norm(G3, p='inf') == float('inf') # Comparison to norm computed in MATLAB
48+
with pytest.warns(UserWarning, match="Poles close to, or on, the imaginary axis."):
49+
assert ct.norm(G3, p=2) == float('inf') # Comparison to norm computed in MATLAB
4150

4251
Gd3 = ct.sample_system(G3, 0.1)
43-
assert ct.norm(Gd3, p='inf', print_warning=False) == float('inf') # Comparison to norm computed in MATLAB
44-
assert ct.norm(Gd3, p=2, print_warning=False) == float('inf') # Comparison to norm computed in MATLAB
52+
with pytest.warns(UserWarning, match="Poles close to, or on, the complex unit circle."):
53+
assert ct.norm(Gd3, p='inf') == float('inf') # Comparison to norm computed in MATLAB
54+
with pytest.warns(UserWarning, match="Poles close to, or on, the complex unit circle."):
55+
assert ct.norm(Gd3, p=2) == float('inf') # Comparison to norm computed in MATLAB
4556

4657
def test_norm_3rd_order_mimo_system():
4758
"""Third-order stable MIMO continuous-time system"""
@@ -55,9 +66,9 @@ def test_norm_3rd_order_mimo_system():
5566
[-0.863652821988714, -1.214117043615409, -0.006849328103348]])
5667
D = np.zeros((2,2))
5768
G4 = ct.ss(A,B,C,D) # Random system generated in MATLAB
58-
assert np.allclose(ct.norm(G4, p='inf', tol=1e-9, print_warning=False), 4.276759162964244) # Comparison to norm computed in MATLAB
59-
assert np.allclose(ct.norm(G4, p=2, print_warning=False), 2.237461821810309) # Comparison to norm computed in MATLAB
69+
assert np.allclose(ct.norm(G4, p='inf', tol=1e-9), 4.276759162964244) # Comparison to norm computed in MATLAB
70+
assert np.allclose(ct.norm(G4, p=2), 2.237461821810309) # Comparison to norm computed in MATLAB
6071

6172
Gd4 = ct.sample_system(G4, 0.1)
62-
assert np.allclose(ct.norm(Gd4, p='inf', tol=1e-9, print_warning=False), 4.276759162964228) # Comparison to norm computed in MATLAB
63-
assert np.allclose(ct.norm(Gd4, p=2, print_warning=False), 0.707434962289554) # Comparison to norm computed in MATLAB
73+
assert np.allclose(ct.norm(Gd4, p='inf', tol=1e-9), 4.276759162964228) # Comparison to norm computed in MATLAB
74+
assert np.allclose(ct.norm(Gd4, p=2), 0.707434962289554) # Comparison to norm computed in MATLAB

0 commit comments

Comments
 (0)