|
73 | 73 | # config.use_matlab() |
74 | 74 |
|
75 | 75 | # Control system library |
76 | | -from .. import ctrlutil |
77 | | -from .. import freqplot |
78 | | -from .. import timeresp |
79 | | -from .. import margins |
80 | 76 | from ..statesp import * |
81 | 77 | from ..xferfcn import * |
82 | 78 | from ..lti import * |
83 | 79 | from ..frdata import * |
84 | 80 | from ..dtime import sample_system |
85 | 81 | from ..exception import ControlArgument |
86 | | -from .timeresp import * |
87 | 82 |
|
88 | 83 | # Import MATLAB-like functions that can be used as-is |
89 | 84 | from ..ctrlutil import unwrap |
|
96 | 91 | from ..modelsimp import hsvd, balred, modred, minreal |
97 | 92 | from ..mateqn import lyap, dlyap, dare, care |
98 | 93 |
|
| 94 | +# Import functions specific to Matlab compatibility package |
| 95 | +from .timeresp import * |
| 96 | +from .plots import * |
| 97 | + |
99 | 98 | __doc__ += r""" |
100 | 99 | The following tables give an overview of the module ``control.matlab``. |
101 | 100 | They also show the implementation progress and the planned features of the |
|
387 | 386 |
|
388 | 387 | """ |
389 | 388 |
|
390 | | -# Bode plots |
391 | | -def bode(*args, **keywords): |
392 | | - """Bode plot of the frequency response |
393 | | -
|
394 | | - Plots a bode gain and phase diagram |
395 | | -
|
396 | | - Parameters |
397 | | - ---------- |
398 | | - sys : LTI, or list of LTI |
399 | | - System for which the Bode response is plotted and give. Optionally |
400 | | - a list of systems can be entered, or several systems can be |
401 | | - specified (i.e. several parameters). The sys arguments may also be |
402 | | - interspersed with format strings. A frequency argument (array_like) |
403 | | - may also be added, some examples: |
404 | | - * >>> bode(sys, w) # one system, freq vector |
405 | | - * >>> bode(sys1, sys2, ..., sysN) # several systems |
406 | | - * >>> bode(sys1, sys2, ..., sysN, w) |
407 | | - * >>> bode(sys1, 'plotstyle1', ..., sysN, 'plotstyleN') # + plot formats |
408 | | - omega: freq_range |
409 | | - Range of frequencies in rad/s |
410 | | - dB : boolean |
411 | | - If True, plot result in dB |
412 | | - Hz : boolean |
413 | | - If True, plot frequency in Hz (omega must be provided in rad/sec) |
414 | | - deg : boolean |
415 | | - If True, return phase in degrees (else radians) |
416 | | - Plot : boolean |
417 | | - If True, plot magnitude and phase |
418 | | -
|
419 | | - Examples |
420 | | - -------- |
421 | | - >>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.") |
422 | | - >>> mag, phase, omega = bode(sys) |
423 | | -
|
424 | | - .. todo:: |
425 | | -
|
426 | | - Document these use cases |
427 | | -
|
428 | | - * >>> bode(sys, w) |
429 | | - * >>> bode(sys1, sys2, ..., sysN) |
430 | | - * >>> bode(sys1, sys2, ..., sysN, w) |
431 | | - * >>> bode(sys1, 'plotstyle1', ..., sysN, 'plotstyleN') |
432 | | - """ |
433 | | - |
434 | | - # If the first argument is a list, then assume python-control calling format |
435 | | - if (getattr(args[0], '__iter__', False)): |
436 | | - return freqplot.bode(*args, **keywords) |
437 | | - |
438 | | - # Otherwise, run through the arguments and collect up arguments |
439 | | - syslist = []; plotstyle=[]; omega=None; |
440 | | - i = 0; |
441 | | - while i < len(args): |
442 | | - # Check to see if this is a system of some sort |
443 | | - if (ctrlutil.issys(args[i])): |
444 | | - # Append the system to our list of systems |
445 | | - syslist.append(args[i]) |
446 | | - i += 1 |
447 | | - |
448 | | - # See if the next object is a plotsytle (string) |
449 | | - if (i < len(args) and isinstance(args[i], str)): |
450 | | - plotstyle.append(args[i]) |
451 | | - i += 1 |
452 | | - |
453 | | - # Go on to the next argument |
454 | | - continue |
455 | | - |
456 | | - # See if this is a frequency list |
457 | | - elif (isinstance(args[i], (list, np.ndarray))): |
458 | | - omega = args[i] |
459 | | - i += 1 |
460 | | - break |
461 | | - |
462 | | - else: |
463 | | - raise ControlArgument("unrecognized argument type") |
464 | | - |
465 | | - # Check to make sure that we processed all arguments |
466 | | - if (i < len(args)): |
467 | | - raise ControlArgument("not all arguments processed") |
468 | | - |
469 | | - # Check to make sure we got the same number of plotstyles as systems |
470 | | - if (len(plotstyle) != 0 and len(syslist) != len(plotstyle)): |
471 | | - raise ControlArgument("number of systems and plotstyles should be equal") |
472 | | - |
473 | | - # Warn about unimplemented plotstyles |
474 | | - #! TODO: remove this when plot styles are implemented in bode() |
475 | | - #! TODO: uncomment unit test code that tests this out |
476 | | - if (len(plotstyle) != 0): |
477 | | - print("Warning (matabl.bode): plot styles not implemented"); |
478 | | - |
479 | | - # Call the bode command |
480 | | - return freqplot.bode(syslist, omega, **keywords) |
481 | | - |
482 | | -# Nichols chart grid |
483 | | -def ngrid(): |
484 | | - nichols_grid() |
485 | | -ngrid.__doc__ = re.sub('nichols_grid', 'ngrid', nichols_grid.__doc__) |
486 | | - |
487 | | -# Root locus plot |
488 | | -def rlocus(sys, klist = None, **keywords): |
489 | | - """Root locus plot |
490 | | -
|
491 | | - The root-locus plot has a callback function that prints pole location, |
492 | | - gain and damping to the Python consol on mouseclicks on the root-locus |
493 | | - graph. |
494 | | -
|
495 | | - Parameters |
496 | | - ---------- |
497 | | - sys: StateSpace or TransferFunction |
498 | | - Linear system |
499 | | - klist: iterable, optional |
500 | | - optional list of gains |
501 | | - xlim : control of x-axis range, normally with tuple, for |
502 | | - other options, see matplotlib.axes |
503 | | - ylim : control of y-axis range |
504 | | - Plot : boolean (default = True) |
505 | | - If True, plot magnitude and phase |
506 | | - PrintGain: boolean (default = True) |
507 | | - If True, report mouse clicks when close to the root-locus branches, |
508 | | - calculate gain, damping and print |
509 | | -
|
510 | | - Returns |
511 | | - ------- |
512 | | - rlist: |
513 | | - list of roots for each gain |
514 | | - klist: |
515 | | - list of gains used to compute roots |
516 | | - """ |
517 | | - from ..rlocus import root_locus |
518 | | - |
519 | | - return root_locus(sys, klist, **keywords) |
| 389 | +from ..margins import stability_margins |
520 | 390 |
|
521 | 391 | def margin(*args): |
522 | 392 | """Calculate gain and phase margins and associated crossover frequencies |
@@ -548,9 +418,9 @@ def margin(*args): |
548 | 418 | """ |
549 | 419 | if len(args) == 1: |
550 | 420 | sys = args[0] |
551 | | - margin = margins.stability_margins(sys) |
| 421 | + margin = stability_margins(sys) |
552 | 422 | elif len(args) == 3: |
553 | | - margin = margins.stability_margins(args) |
| 423 | + margin = stability_margins(args) |
554 | 424 | else: |
555 | 425 | raise ValueError("Margin needs 1 or 3 arguments; received %i." |
556 | 426 | % len(args)) |
@@ -649,9 +519,6 @@ def damp(sys, doprint=True): |
649 | 519 | (p.real, p.imag, d, w)) |
650 | 520 | return wn, damping, poles |
651 | 521 |
|
652 | | -# Simulation routines |
653 | | -# Call corresponding functions in timeresp, with arguments transposed |
654 | | - |
655 | 522 | # Convert a continuous time system to a discrete time system |
656 | 523 | def c2d(sysc, Ts, method='zoh'): |
657 | 524 | ''' |
|
0 commit comments