@@ -149,12 +149,13 @@ def bode_plot(syslist, omega=None,
149
149
the `deg` parameter. Default is -180 if wrap_phase is False, 0 if
150
150
wrap_phase is True.
151
151
wrap_phase : bool or float
152
- If wrap_phase is `False`, then the phase will be unwrapped so that it
153
- is continuously increasing or decreasing. If wrap_phase is `True` the
154
- phase will be restricted to the range [-180, 180) (or [:math:`-\\ pi`,
155
- :math:`\\ pi`) radians). If `wrap_phase` is specified as a float, the
156
- phase will be offset by 360 degrees if it falls below the specified
157
- value. Default to `False`, set by config.defaults['freqplot.wrap_phase'].
152
+ If wrap_phase is `False` (default), then the phase will be unwrapped
153
+ so that it is continuously increasing or decreasing. If wrap_phase is
154
+ `True` the phase will be restricted to the range [-180, 180) (or
155
+ [:math:`-\\ pi`, :math:`\\ pi`) radians). If `wrap_phase` is specified
156
+ as a float, the phase will be offset by 360 degrees if it falls below
157
+ the specified value. Default value is `False` and can be set using
158
+ config.defaults['freqplot.wrap_phase'].
158
159
159
160
The default values for Bode plot configuration parameters can be reset
160
161
using the `config.defaults` dictionary, with module name 'bode'.
@@ -573,9 +574,6 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
573
574
return_contour : bool, optional
574
575
If 'True', return the contour used to evaluate the Nyquist plot.
575
576
576
- *args : :func:`matplotlib.pyplot.plot` positional properties, optional
577
- Additional arguments for `matplotlib` plots (color, linestyle, etc)
578
-
579
577
**kwargs : :func:`matplotlib.pyplot.plot` keyword properties, optional
580
578
Addition
8000
al keywords (passed to `matplotlib`)
581
579
@@ -586,15 +584,12 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
586
584
multiple systems are given, an array of counts is returned.
587
585
588
586
contour : ndarray (or list of ndarray if len(syslist) > 1)), optional
589
- The contour used to create the primary Nyquist curve segment. To
590
- obtain the Nyquist curve values, evaluate system(s) along contour.
587
+ The contour used to create the primary Nyquist curve segment, returned
588
+ if `return_contour` is Tue. To obtain the Nyquist curve values,
589
+ evaluate system(s) along contour.
591
590
592
591
Additional Parameters
593
592
---------------------
594
- label_freq : int, optiona
595
- Label every nth frequency on the plot. If not specified, no labels
596
- are generated.
597
-
598
593
arrows : int or 1D/2D array of floats, optional
599
594
Specify the number of arrows to plot on the Nyquist curve. If an
600
595
integer is passed. that number of equally spaced arrows will be
@@ -630,6 +625,10 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
630
625
imaginary axis. Portions of the Nyquist plot corresponding to indented
631
626
portions of the contour are plotted using a different line style.
632
627
628
+ label_freq : int, optiona
629
+ Label every nth frequency on the plot. If not specified, no labels
630
+ are generated.
631
+
633
632
max_curve_magnitude : float, optional
634
633
Restrict the maximum magnitude of the Nyquist plot to this value.
635
634
Portions of the Nyquist plot whose magnitude is restricted are
@@ -666,6 +665,10 @@ def nyquist_plot(syslist, omega=None, plot=True, omega_limits=None,
666
665
warn_nyquist : bool, optional
667
666
If set to 'False', turn off warnings about frequencies above Nyquist.
668
667
668
+ warn_encirclements : bool, optional
669
+ If set to 'False', turn off warnings about number of encirclements not
670
+ meeting the Nyquist criterion.
671
+
669
672
Notes
670
673
-----
671
674
1. If a discrete time model is given, the frequency response is computed
@@ -885,22 +888,22 @@ def _parse_linestyle(style_name, allow_false=False):
885
888
# See if we need to indent around it
886
889
if abs (s - p ) < indent_radius :
887
890
# Figure out how much to offset (simple trigonometry)
888
- offset = np .sqrt (indent_radius ** 2 - (s - p ).imag ** 2 ) \
889
- - ( s - p ).real
891
+ offset = np .sqrt (indent_radius ** 2 - (s - p ).imag ** 2 ) \
892
+ - ( s - p ).real
890
893
891
894
# Figure out which way to offset the contour point
892
- if p .real < 0 or (np .isclose (p .real , 0 ) \
893
- and indent_direction == 'right' ):
895
+ if p .real < 0 or (np .isclose (p .real , 0 )
896
+ and indent_direction == 'right' ):
894
897
# Indent to the right
895
898
splane_contour [i ] += offset
896
899
897
- elif p .real > 0 or (np .isclose (p .real , 0 ) \
898
- and indent_direction == 'left' ):
900
+ elif p .real > 0 or (np .isclose (p .real , 0 )
901
+ and indent_direction == 'left' ):
899
902
# Indent to the left
900
903
splane_contour [i ] -= offset
901
904
902
905
else :
903
- ValueError ("unknown value for indent_direction" )
906
+ raise ValueError ("unknown value for indent_direction" )
904
907
905
908
# change contour to z-plane if necessary
906
909
if sys .isctime ():
@@ -939,7 +942,8 @@ def _parse_linestyle(style_name, allow_false=False):
939
942
"number of encirclements does not match Nyquist criterion;"
940
943
" check frequency range and indent radius/direction" ,
941
944
UserWarning , stacklevel = 2 )
942
- elif indent_direction == 'none' and any (sys .pole ().real == 0 ):
945
+ elif indent_direction == 'none' and \
946
+ any (np .isclose (sys .pole ().real , 0 )):
943
947
warnings .warn (
944
948
"system has pure imaginary poles but indentation is"
945
949
" turned off; results may be meaningless" ,
@@ -950,14 +954,14 @@ def _parse_linestyle(style_name, allow_false=False):
950
954
951
955
if plot :
952
956
# Parse the arrows keyword
953
- if isinstance (arrows , int ):
957
+ if not arrows :
958
+ arrow_pos = []
959
+ elif isinstance (arrows , int ):
954
960
N = arrows
955
961
# Space arrows out, starting midway along each "region"
956
962
arrow_pos = np .linspace (0.5 / N , 1 + 0.5 / N , N , endpoint = False )
957
963
elif isinstance (arrows , (list , np .ndarray )):
958
964
arrow_pos = np .sort (np .atleast_1d (arrows ))
959
- elif not arrows :
960
- arrow_pos = []
961
965
else :
962
966
raise ValueError ("unknown or unsupported arrow location" )
963
967
@@ -1150,6 +1154,7 @@ def _add_arrows_to_line2D(
1150
1154
arrows .append (p )
1151
1155
return arrows
1152
1156
1157
+
1153
1158
#
1154
1159
# Function to compute Nyquist curve offsets
1155
1160
#
@@ -1172,13 +1177,13 @@ def _compute_curve_offset(resp, mask, max_offset):
1172
1177
while i < resp .size and mask [i ]:
1173
1178
i += 1 # Increment the counter
1174
1179
if i == resp .size :
1175
- break ;
1180
+ break
1176
1181
# Keep track of the arclength
1177
1182
arclen [i ] = arclen [i - 1 ] + np .abs (resp [i ] - resp [i - 1 ])
1178
1183
1179
1184
nsegs += 0.5
1180
1185
if i == resp .size :
1181
- break ;
1186
+ break
1182
1187
1183
1188
# Save the starting offset of this segment
1184
1189
seg_start = i
@@ -1187,13 +1192,13 @@ def _compute_curve_offset(resp, mask, max_offset):
1187
1192
while i < resp .size and not mask [i ]:
1188
1193
i += 1
1189
1194
if i == resp .size : # See if we are done with this segment
1190
- break ;
1195
+ break
1191
1196
# Keep track of the arclength
1192
1197
arclen [i ] = arclen [i - 1 ] + np .abs (resp [i ] - resp [i - 1 ])
1193
1198
1194
1199
nsegs += 0.5
1195
1200
if i == resp .size :
1196
- break ;
1201
+ break
1197
1202
1198
1203
# Save the ending offset of this segment
1199
1204
seg_end = i
@@ -1333,7 +1338,8 @@ def singular_values_plot(syslist, omega=None,
1333
1338
* args , ** kwargs ):
1334
1339
"""Singular value plot for a system
1335
1340
1336
- Plots a Singular Value plot for the system over a (optional) frequency range.
1341
+ Plots a singular value plot for the system over a (optional) frequency
1342
+ range.
1337
1343
1338
1344
Parameters
1339
1345
----------
@@ -1347,11 +1353,11 @@ def singular_values_plot(syslist, omega=None,
1347
1353
Limits of the frequency vector to generate.
1348
1354
If Hz=True the limits are in Hz otherwise in rad/s.
1349
1355
omega_num : int
1350
- Number of samples to plot.
1351
- Default value (1000) set by config.defaults['freqplot.number_of_samples'].
1356
+ Number of samples to plot. Default value (1000) set by
1357
+ config.defaults['freqplot.number_of_samples'].
1352
1358
dB : bool
1353
- If True, plot result in dB.
1354
- Default value (False) set by config.defaults['freqplot.dB'].
1359
+ If True, plot result in dB. Default value (False) set by
1360
+ config.defaults['freqplot.dB'].
1355
1361
Hz : bool
1356
1362
If True, plot frequency in Hz (omega must be provided in rad/sec).
1357
1363
Default value (False) set by config.defaults['freqplot.Hz']
@@ -1373,7 +1379,8 @@ def singular_values_plot(syslist, omega=None,
1373
1379
--------
1374
1380
>>> import numpy as np
1375
1381
>>> den = [75, 1]
1376
- >>> sys = TransferFunction([[[87.8], [-86.4]], [[108.2], [-109.6]]], [[den, den], [den, den]])
1382
+ >>> sys = TransferFunction(
1383
+ [[[87.8], [-86.4]], [[108.2], [-109.6]]], [[den, den], [den, den]])
1377
1384
>>> omega = np.logspace(-4, 1, 1000)
1378
1385
>>> sigma, omega = singular_values_plot(sys, plot=True)
1379
1386
>>> singular_values_plot(sys, 0.0, plot=False)
@@ -1480,7 +1487,8 @@ def singular_values_plot(syslist, omega=None,
1480
1487
# Add a grid to the plot + labeling
1481
1488
if plot :
1482
1489
ax_sigma .grid (grid , which = 'both' )
1483
- ax_sigma .set_ylabel ("Singular Values (dB)" if dB else "Singular Values" )
1490
+ ax_sigma .set_ylabel (
1491
+ "Singular Values (dB)" if dB else "Singular Values" )
1484
1492
ax_sigma .set_xlabel ("Frequency (Hz)" if Hz else "Frequency (rad/sec)" )
1485
1493
1486
1494
if len (syslist ) == 1 :
0 commit comments