@@ -78,11 +78,11 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
78
78
If True, plot phase in degrees (else radians)
79
79
Plot : boolean
80
80
If True, plot magnitude and phase
81
- omega_limits: tuple, list, ... of two values
81
+ omega_limits: tuple, list, ... of two values
82
82
Limits of the to generate frequency vector.
83
83
If Hz=True the limits are in Hz otherwise in rad/s.
84
84
omega_num: int
85
- number of samples
85
+ number of samples
86
86
*args, **kwargs:
87
87
Additional options to matplotlib (color, linestyle, etc)
88
88
@@ -120,7 +120,7 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
120
120
# If argument was a singleton, turn it into a list
121
121
if (not getattr (syslist ,'__iter__' ,False )):
122
122
syslist = (syslist ,)
123
-
123
+
124
124
if omega is None :
125
125
if omega_limits is None :
126
126
# Select a default range if none is provided
@@ -133,7 +133,7 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
133
133
omega = sp .logspace (np .log10 (omega_limits [0 ]),np .log10 (omega_limits [1 ]),num = omega_num ,endpoint = True )
134
134
else :
135
135
omega = sp .logspace (np .log10 (omega_limits [0 ]),np .log10 (omega_limits [1 ]),endpoint = True )
136
-
136
+
137
137
mags ,phases ,omegas ,nyquistfrqs = [], [], [], []
138
138
for sys in syslist :
139
139
if (sys .inputs > 1 or sys .outputs > 1 ):
@@ -142,8 +142,8 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
142
142
else :
143
143
omega_sys = np .array (omega )
144
144
if sys .isdtime (True ):
145
- nyquistfrq = 2. * np .pi * 1. / sys .dt / 2.
146
- omega_sys = omega_sys [omega_sys < nyquistfrq ]
145
+ nyquistfrq = 2. * np .pi * 1. / sys .dt / 2.
146
+ omega_sys = omega_sys [omega_sys < nyquistfrq ]
147
147
# TODO: What distance to the Nyquist frequency is appropriate?
148
148
else :
149
149
nyquistfrq = None
@@ -179,7 +179,7 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
179
179
plt .hold (True );
180
180
if nyquistfrq_plot :
181
181
ax_mag .axvline (nyquistfrq_plot ,color = pltline [0 ].get_color ())
182
-
182
+
183
183
# Add a grid to the plot + labeling
184
184
ax_mag .grid (True ,which = 'both' )
185
185
ax_mag .set_ylabel ("Magnitude (dB)" if dB else "Magnitude" )
@@ -194,30 +194,31 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
194
194
ax_phase .hold (True );
195
195
if nyquistfrq_plot :
196
196
ax_phase .axvline (nyquistfrq_plot ,color = pltline [0 ].get_color ())
197
-
197
+
198
198
# Add a grid to the plot + labeling
199
- ax_phase .set_ylabel ("Phase (deg)" if deg else "Phase (rad)" )
199
+ ax_phase .set_ylabel ("Phase (deg)" if deg else "Phase (rad)" )
200
+
200
201
def genZeroCenteredSeries (val_min ,val_max ,period ):
201
202
v1 = np .ceil (val_min / period - 0.2 )
202
203
v2 = np .floor (val_max / period + 0.2 )
203
- return np .arange (v1 ,v2 + 1 )* period
204
+ return np .arange (v1 ,v2 + 1 )* period
204
205
if deg :
205
206
ylim = ax_phase .get_ylim ()
206
- ax_phase .set_yticks (genZeroCenteredSeries (ylim [0 ],ylim [1 ],45. ))
207
- ax_phase .set_yticks (genZeroCenteredSeries (ylim [0 ],ylim [1 ],15. ),minor = True )
207
+ ax_phase .set_yticks (genZeroCenteredSeries (ylim [0 ],ylim [1 ],45. ))
208
+ ax_phase .set_yticks (genZeroCenteredSeries (ylim [0 ],ylim [1 ],15. ),minor = True )
208
209
else :
209
210
ylim = ax_phase .get_ylim ()
210
- ax_phase .set_yticks (genZeroCenteredSeries (ylim [0 ],ylim [1 ],np .pi / 4. ))
211
+ ax_phase .set_yticks (genZeroCenteredSeries (ylim [0 ],ylim [1 ],np .pi / 4. ))
211
212
ax_phase .set_yticks (genZeroCenteredSeries (ylim [0 ],ylim [1 ],np .pi / 12. ),minor = True )
212
213
ax_phase .grid (True ,which = 'both' )
213
- # ax_mag.grid(which='minor', alpha=0.3)
214
+ # ax_mag.grid(which='minor', alpha=0.3)
214
215
# ax_mag.grid(which='major', alpha=0.9)
215
- # ax_phase.grid(which='minor', alpha=0.3)
216
- # ax_phase.grid(which='major', alpha=0.9)
217
-
216
+ # ax_phase.grid(which='minor', alpha=0.3)
217
+ # ax_phase.grid(which='major', alpha=0.9)
218
+
218
219
# Label the frequency axis
219
- ax_phase .set_xlabel ("Frequency (Hz)" if Hz else "Frequency (rad/sec)" )
220
-
220
+ ax_phase .set_xlabel ("Frequency (Hz)" if Hz else "Frequency (rad/sec)" )
221
+
221
222
if len (syslist )== 1 :
222
223
return mags [0 ],phases [0 ],omegas [0 ]
223
224
else :
@@ -314,7 +315,7 @@ def nyquist_plot(syslist, omega=None, Plot=True, color='b',
314
315
# instead of 1.0, and this would otherwise be
315
316
# truncated to 0.
316
317
plt .text (xpt ,ypt ,
317
- ' ' + str (int (np .round (f / 1000 ** pow1000 ,0 )))+
318
+ ' ' + str (int (np .round (f / 1000 ** pow1000 ,0 )))+
318
319
' ' + prefix + 'Hz' )
319
320
return x ,y ,omega
320
321
@@ -394,18 +395,18 @@ def default_frequency_range(syslist, Hz=None, number_of_samples=None, feature_pe
394
395
syslist : list of LTI
395
396
List of linear input/output systems (single system is OK)
396
397
Hz: boolean
397
- If True, the limits (first and last value) of the frequencies
398
- are set to full decades in Hz so it fits plotting with logarithmic
398
+ If True, the limits (first and last value) of the frequencies
399
+ are set to full decades in Hz so it fits plotting with logarithmic
399
400
scale in Hz otherwise in rad/s. Omega is always returned in rad/sec.
400
401
number_of_samples: int
401
402
Number of samples to generate
402
403
feature_periphery_decade: float
403
- Defines how many decades shall be included in the frequency range on
404
- both sides of features (poles, zeros).
404
+ Defines how many decades shall be included in the frequency range on
405
+ both sides of features (poles, zeros).
405
406
Example: If there is a feature, e.g. a pole, at 1Hz and feature_periphery_decade=1.
406
- then the range of frequencies shall span 0.1 .. 10 Hz.
407
+ then the range of frequencies shall span 0.1 .. 10 Hz.
407
408
The default value is read from config.bode_feature_periphery_decade.
408
-
409
+
409
410
Returns
410
411
-------
411
412
omega : array
@@ -425,14 +426,14 @@ def default_frequency_range(syslist, Hz=None, number_of_samples=None, feature_pe
425
426
426
427
# Set default values for options
427
428
from .import config
428
- if (number_of_samples is None ):
429
+ if (number_of_samples is None ):
429
430
number_of_samples = config .bode_number_of_samples
430
- if (feature_periphery_decade is None ):
431
- feature_periphery_decade = config .bode_feature_periphery_decade
431
+ if (feature_periphery_decade is None ):
432
+ feature_periphery_decade = config .bode_feature_periphery_decade
432
433
433
434
# Find the list of all poles and zeros in the systems
434
435
features = np .array (())
435
- freq_interesting = []
436
+ freq_interesting = []
436
437
437
438
# detect if single sys passed by checking if it is sequence-like
438
439
if (not getattr (syslist ,'__iter__' ,False )):
@@ -443,34 +444,34 @@ def default_frequency_range(syslist, Hz=None, number_of_samples=None, feature_pe
443
444
# Add new features to the list
444
445
if sys .isctime ():
445
446
features_ = np .concatenate ((np .abs (sys .pole ()),
446
- np .abs (sys .zero ())))
447
+ np .abs (sys .zero ())))
447
448
# Get rid of poles and zeros at the origin
448
449
features_ = features_ [features_ != 0.0 ];
449
450
features = np .concatenate ((features ,features_ ))
450
451
elif sys .isdtime (strict = True ):
451
452
fn = np .pi * 1. / sys .dt
452
- # TODO: What distance to the Nyquist frequency is appropriate?
453
+ # TODO: What distance to the Nyquist frequency is appropriate?
453
454
freq_interesting .append (fn * 0.9 )
454
455
455
456
features_ = np .concatenate ((sys .pole (),
456
- sys .zero ()))
457
- # Get rid of poles and zeros
457
+ sys .zero ()))
458
+ # Get rid of poles and zeros
458
459
# * at the origin and real <= 0 & imag==0: log!
459
460
# * at 1.: would result in omega=0. (logaritmic plot!)
460
461
features_ = features_ [(features_ .imag != 0.0 )| (features_ .real > 0. )]
461
462
features_ = features_ [np .bitwise_not ((features_ .imag == 0.0 )& (np .abs (features_ .real - 1.0 )< 1.e-10 ))]
462
463
# TODO: improve
463
464
features__ = np .abs (np .log (features_ )/ (1.j * sys .dt ))
464
- features = np .concatenate ((features ,features__ ))
465
+ features = np .concatenate ((features ,features__ ))
465
466
else :
466
467
# TODO
467
- raise NotImplementedError ('type of system in not implemented now' )
468
+ raise NotImplementedError ('type of system in not implemented now' )
468
469
except :
469
470
pass
470
471
471
472
472
473
# Make sure there is at least one point in the range
473
- if (features .shape [0 ]== 0 ):
474
+ if (features .shape [0 ]== 0 ):
474
475
features = np .array ([1. ]);
475
476
476
477
if Hz :