Skip to content

Commit abeb0e4

Browse files
authored
Merge pull request #1164 from murrayrm/release_10_2_fixes-04Jul2025
OS/BLAS update for Windows + small fixes for 0.10.2 release
2 parents 03ae372 + 3993c79 commit abeb0e4

File tree

16 files changed

+81
-47
lines changed

16 files changed

+81
-47
lines changed

.github/scripts/set-conda-test-matrix.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,19 @@
2727
'blas_lib': cbl}
2828
conda_jobs.append(cjob)
2929

30+
# Make sure Windows jobs are included even if we didn't build any
31+
windows_pythons = ['3.11'] # Whatever you want to test
32+
33+
for py in windows_pythons:
34+
for blas in combinations['windows']:
35+
cjob = {
36+
'packagekey': f'windows-{py}',
37+
'os': 'windows',
38+
'python': py,
39+
'blas_lib': blas,
40+
'package_source': 'conda-forge'
41+
}
42+
conda_jobs.append(cjob)
43+
3044
matrix = { 'include': conda_jobs }
3145
print(json.dumps(matrix))

.github/workflows/os-blas-test-matrix.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ jobs:
107107
os:
108108
- 'ubuntu'
109109
- 'macos'
110-
- 'windows'
111110
python:
112111
# build on one, expand matrix in conda-build from the Sylcot/conda-recipe/conda_build_config.yaml
113112
- '3.11'
@@ -332,7 +331,13 @@ jobs:
332331
echo "libblas * *mkl" >> $CONDA_PREFIX/conda-meta/pinned
333332
;;
334333
esac
335-
conda install -c ./slycot-conda-pkgs slycot
334+
if [ "${{ matrix.os }}" = "windows" ]; then
335+
echo "Installing slycot from conda-forge on Windows"
336+
conda install slycot
337+
else
338+
echo "Installing built conda package from local channel"
339+
conda install -c ./slycot-conda-pkgs slycot
340+
fi
336341
conda list
337342
- name: Test with pytest
338343
run: JOBNAME="$JOBNAME" pytest control/tests

control/config.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ def use_legacy_defaults(version):
297297
Parameters
298298
----------
299299
version : string
300-
Version number of the defaults desired. Ranges from '0.1' to '0.10.1'.
300+
Version number of `python-control` to use for setting defaults.
301301
302302
Examples
303303
--------
@@ -342,6 +342,14 @@ def use_legacy_defaults(version):
342342
#
343343
reset_defaults() # start from a clean slate
344344

345+
# Version 0.10.2:
346+
if major == 0 and minor < 10 or (minor == 10 and patch < 2):
347+
from math import inf
348+
349+
# Reset Nyquist defaults
350+
set_defaults('nyquist', arrows=2, max_curve_magnitude=20,
351+
blend_fraction=0, indent_points=50)
352+
345353
# Version 0.9.2:
346354
if major == 0 and minor < 9 or (minor == 9 and patch < 2):
347355
from math import inf

control/freqplot.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,7 +1659,7 @@ def nyquist_plot(
16591659
portions of the contour are plotted using a different line style.
16601660
label : str or array_like of str, optional
16611661
If present, replace automatically generated label(s) with the given
1662-
label(s). If sysdata is a list, strings should be specified for each
1662+
label(s). If `data` is a list, strings should be specified for each
16631663
system.
16641664
label_freq : int, optional
16651665
Label every nth frequency on the plot. If not specified, no labels
@@ -1690,8 +1690,8 @@ def nyquist_plot(
16901690
elements is equivalent to providing `omega_limits`.
16911691
omega_num : int, optional
16921692
Number of samples to use for the frequency range. Defaults to
1693-
`config.defaults['freqplot.number_of_samples']`. Ignored if data is
1694-
not a list of systems.
1693+
`config.defaults['freqplot.number_of_samples']`. Ignored if `data`
1694+
is not a system or list of systems.
16951695
plot : bool, optional
16961696
(legacy) If given, `nyquist_plot` returns the legacy return values
16971697
of (counts, contours). If False, return the values with no plot.

control/margins.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -536,10 +536,12 @@ def disk_margins(L, omega, skew=0.0, returnall=False):
536536
1D array of (non-negative) frequencies (rad/s) at which
537537
to evaluate the disk-based stability margins.
538538
skew : float or array_like, optional
539-
skew parameter(s) for disk margin (default = 0.0).
540-
skew = 0.0 "balanced" sensitivity function 0.5*(S - T).
541-
skew = 1.0 sensitivity function S.
542-
skew = -1.0 complementary sensitivity function T.
539+
Skew parameter(s) for disk margin (default = 0.0):
540+
541+
* skew = 0.0 "balanced" sensitivity function 0.5*(S - T)
542+
* skew = 1.0 sensitivity function S
543+
* skew = -1.0 complementary sensitivity function T
544+
543545
returnall : bool, optional
544546
If True, return frequency-dependent margins.
545547
If False (default), return worst-case (minimum) margins.
@@ -553,7 +555,7 @@ def disk_margins(L, omega, skew=0.0, returnall=False):
553555
DPM : float or array_like
554556
Disk-based phase margin.
555557
556-
Example
558+
Examples
557559
--------
558560
>> omega = np.logspace(-1, 3, 1001)
559561
>> P = control.ss([[0, 10], [-10, 0]], np.eye(2), [[1, 10],

control/matlab/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
This subpackage contains a number of functions that emulate some of
88
the functionality of MATLAB. The intent of these functions is to
9-
provide a simple interface to the python control systems library
9+
provide a simple interface to the Python Control Systems Library
1010
(python-control) for people who are familiar with the MATLAB Control
1111
Systems Toolbox (tm).
1212

control/pzmap.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def replot(self, cplt: ControlPlot):
129129
130130
Parameters
131131
----------
132-
cplt: ControlPlot
132+
cplt : `ControlPlot`
133133
Graphics handles of the existing plot.
134134
"""
135135
pole_zero_replot(self, cplt)

control/tests/discrete_test.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ class Tsys:
2626
sys = rss(3, 1, 1)
2727
T.siso_ss1 = StateSpace(sys.A, sys.B, sys.C, sys.D, None)
2828
T.siso_ss1c = StateSpace(sys.A, sys.B, sys.C, sys.D, 0.0)
29-
T.siso_ss1d = StateSpace(sys.A, sys.B, sys.C, sys.D, 0.1)
30-
T.siso_ss2d = StateSpace(sys.A, sys.B, sys.C, sys.D, 0.2)
31-
T.siso_ss3d = StateSpace(sys.A, sys.B, sys.C, sys.D, True)
29+
30+
dsys = ct.sample_system(sys, 1)
31+
T.siso_ss1d = StateSpace(dsys.A, dsys.B, dsys.C, dsys.D, 0.1)
32+
T.siso_ss2d = StateSpace(dsys.A, dsys.B, dsys.C, dsys.D, 0.2)
33+
T.siso_ss3d = StateSpace(dsys.A, dsys.B, dsys.C, dsys.D, True)
3234

3335
# Two input, two output continuous-time system
3436
A = [[-3., 4., 2.], [-1., -3., 0.], [2., 5., 3.]]
@@ -39,17 +41,18 @@ class Tsys:
3941
T.mimo_ss1c = StateSpace(A, B, C, D, 0)
4042

4143
# Two input, two output discrete-time system
42-
T.mimo_ss1d = StateSpace(A, B, C, D, 0.1)
44+
T.mimo_ss1d = ct.sample_system(T.mimo_ss1c, 0.1)
4345

4446
# Same system, but with a different sampling time
45-
T.mimo_ss2d = StateSpace(A, B, C, D, 0.2)
47+
T.mimo_ss2d = StateSpace(
48+
T.mimo_ss1d.A, T.mimo_ss1d.B, T.mimo_ss1d.C, T.mimo_ss1d.D, 0.2)
4649

4750
# Single input, single output continuus and discrete transfer function
4851
T.siso_tf1 = TransferFunction([1, 1], [1, 2, 1], None)
49-
T.siso_tf1c = TransferFunction([1, 1], [1, 2, 1], 0)
50-
T.siso_tf1d = TransferFunction([1, 1], [1, 2, 1], 0.1)
51-
T.siso_tf2d = TransferFunction([1, 1], [1, 2, 1], 0.2)
52-
T.siso_tf3d = TransferFunction([1, 1], [1, 2, 1], True)
52+
T.siso_tf1c = TransferFunction([1, 1], [1, 0.2, 1], 0)
53+
T.siso_tf1d = TransferFunction([1, 1], [1, 0.2, 0.1], 0.1)
54+
T.siso_tf2d = TransferFunction([1, 1], [1, 0.2, 0.1], 0.2)
55+
T.siso_tf3d = TransferFunction([1, 1], [1, 0.2, 0.1], True)
5356

5457
return T
5558

control/tests/margin_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ def test_siso_disk_margin():
384384
# Balanced (S - T) disk-based stability margins
385385
DM, DGM, DPM = disk_margins(L, omega, skew=0.0)
386386
assert_allclose([DM], [0.46], atol=0.1) # disk margin of 0.46
387-
assert_allclose([DGM], [4.05], atol=0.1) # disk-based gain margin of 4.05 dB
387+
assert_allclose([DGM], [4.05], atol=0.1) # disk-based gain margin of 4.05 dB
388388
assert_allclose([DPM], [25.8], atol=0.1) # disk-based phase margin of 25.8 deg
389389

390390
# For SISO systems, the S-based (S) disk margin should match the third output
@@ -408,13 +408,13 @@ def test_mimo_disk_margin():
408408
# Balanced (S - T) disk-based stability margins at plant output
409409
DMo, DGMo, DPMo = disk_margins(Lo, omega, skew=0.0)
410410
assert_allclose([DMo], [0.3754], atol=0.1) # disk margin of 0.3754
411-
assert_allclose([DGMo], [3.3], atol=0.1) # disk-based gain margin of 3.3 dB
411+
assert_allclose([DGMo], [3.3], atol=0.1) # disk-based gain margin of 3.3 dB
412412
assert_allclose([DPMo], [21.26], atol=0.1) # disk-based phase margin of 21.26 deg
413413

414414
# Balanced (S - T) disk-based stability margins at plant input
415415
DMi, DGMi, DPMi = disk_margins(Li, omega, skew=0.0)
416416
assert_allclose([DMi], [0.3754], atol=0.1) # disk margin of 0.3754
417-
assert_allclose([DGMi], [3.3], atol=0.1) # disk-based gain margin of 3.3 dB
417+
assert_allclose([DGMi], [3.3], atol=0.1) # disk-based gain margin of 3.3 dB
418418
assert_allclose([DPMi], [21.26], atol=0.1) # disk-based phase margin of 21.26 deg
419419
else:
420420
# Slycot not installed. Should throw exception.
@@ -435,7 +435,7 @@ def test_siso_disk_margin_return_all():
435435
atol=0.01) # sensitivity peak at 1.94 rad/s
436436
assert_allclose([min(DM)], [0.46], atol=0.1) # disk margin of 0.46
437437
assert_allclose([DGM[np.argmin(DM)]], [4.05],\
438-
atol=0.1) # disk-based gain margin of 4.05 dB
438+
atol=0.1) # disk-based gain margin of 4.05 dB
439439
assert_allclose([DPM[np.argmin(DM)]], [25.8],\
440440
atol=0.1) # disk-based phase margin of 25.8 deg
441441

@@ -457,7 +457,7 @@ def test_mimo_disk_margin_return_all():
457457
atol=0.01) # sensitivity peak at 0 rad/s (or smallest provided)
458458
assert_allclose([min(DMo)], [0.3754], atol=0.1) # disk margin of 0.3754
459459
assert_allclose([DGMo[np.argmin(DMo)]], [3.3],\
460-
atol=0.1) # disk-based gain margin of 3.3 dB
460+
atol=0.1) # disk-based gain margin of 3.3 dB
461461
assert_allclose([DPMo[np.argmin(DMo)]], [21.26],\
462462
atol=0.1) # disk-based phase margin of 21.26 deg
463463

@@ -468,7 +468,7 @@ def test_mimo_disk_margin_return_all():
468468
assert_allclose([min(DMi)], [0.3754],\
469469
atol=0.1) # disk margin of 0.3754
470470
assert_allclose([DGMi[np.argmin(DMi)]], [3.3],\
471-
atol=0.1) # disk-based gain margin of 3.3 dB
471+
atol=0.1) # disk-based gain margin of 3.3 dB
472472
assert_allclose([DPMi[np.argmin(DMi)]], [21.26],\
473473
atol=0.1) # disk-based phase margin of 21.26 deg
474474
else:

doc/develop.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ Filenames
110110
* Source files are lower case, usually less than 10 characters (and 8
111111
or less is better).
112112

113-
* Unit tests (in `control/tests/`) are of the form `module_test.py` or
114-
`module_function.py`.
113+
* Unit tests (in `control/tests/`) are of the form `module_test.py`,
114+
`module_functionality_test.py`, or `functionality_test.py`.
115115

116116

117117
Class names

0 commit comments

Comments
 (0)