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