Change API to work with ndarray and TimeResponseData as input · python-control/python-control@2b1cd21

@@ -43,8 +43,7 @@

4343

# External packages and modules

4444

import numpy as np

4545

import warnings

46-

from .exception import ControlSlycot, ControlMIMONotImplemented, \

47-

ControlDimension

46+

from .exception import ControlSlycot, ControlArgument, ControlDimension

4847

from .iosys import isdtime, isctime

4948

from .statesp import StateSpace

5049

from .statefbk import gram

@@ -403,8 +402,10 @@ def era(YY, m, n, nin, nout, r):

403402

raise NotImplementedError('This function is not implemented yet.')

404403405404406-

def markov(data, m=None, dt=True, truncate=False):

407-

"""Calculate the first `m` Markov parameters [D CB CAB ...]

405+

def markov(*args, **kwargs):

406+

"""markov(Y, U, [, m])

407+408+

Calculate the first `m` Markov parameters [D CB CAB ...]

408409

from data

409410410411

This function computes the Markov parameters for a discrete time system

@@ -419,14 +420,31 @@ def markov(data, m=None, dt=True, truncate=False):

419420

the input data is less than the desired number of Markov parameters (a

420421

warning message is generated in this case).

421422423+

The function can be called with either 1, 2, or 3 arguments:

424+425+

* ``K, S, E = lqr(response)``

426+

* ``K, S, E = lqr(respnose, m)``

427+

* ``K, S, E = lqr(Y, U)``

428+

* ``K, S, E = lqr(Y, U, m)``

429+430+

where `response` is an `TimeResponseData` object, and `Y`, `U`, are 1D or 2D

431+

array and m is an integer.

432+422433

Parameters

423434

----------

435+

Y : array_like

436+

Output data. If the array is 1D, the system is assumed to be single

437+

input. If the array is 2D and transpose=False, the columns of `Y`

438+

are taken as time points, otherwise the rows of `Y` are taken as

439+

time points.

440+

U : array_like

441+

Input data, arranged in the same way as `Y`.

424442

data : TimeResponseData

425443

Response data from which the Markov parameters where estimated.

426444

Input and output data must be 1D or 2D array.

427445

m : int, optional

428446

Number of Markov parameters to output. Defaults to len(U).

429-

dt : (True of float, optional)

447+

dt : True of float, optional

430448

True indicates discrete time with unspecified sampling time,

431449

positive number is discrete time with specified sampling time.

432450

It can be used to scale the markov parameters in order to match

@@ -460,17 +478,41 @@ def markov(data, m=None, dt=True, truncate=False):

460478

--------

461479

>>> T = np.linspace(0, 10, 100)

462480

>>> U = np.ones((1, 100))

463-

>>> response = ct.forced_response(ct.tf([1], [1, 0.5], True), T, U)

464-

>>> H = ct.markov(response, 3)

481+

>>> T, Y = ct.forced_response(ct.tf([1], [1, 0.5], True), T, U)

482+

>>> H = ct.markov(Y, U, 3, transpose=False)

465483466484

"""

467485

# Convert input parameters to 2D arrays (if they aren't already)

468-

Umat = np.array(data.inputs, ndmin=2)

469-

Ymat = np.array(data.outputs, ndmin=2)

470486471-

# If data is in transposed format, switch it around

472-

if data.transpose and not data.issiso:

473-

Umat, Ymat = np.transpose(Umat), np.transpose(Ymat)

487+

# Get the system description

488+

if (len(args) < 1):

489+

raise ControlArgument("not enough input arguments")

490+491+

if isinstance(args[0], TimeResponseData):

492+

Umat = np.array(args[0].inputs, ndmin=2)

493+

Ymat = np.array(args[0].outputs, ndmin=2)

494+

transpose = args[0].transpose

495+

if args[0].transpose and not args[0].issiso:

496+

Umat, Ymat = np.transpose(Umat), np.transpose(Ymat)

497+

index = 1

498+

else:

499+

if (len(args) < 2):

500+

raise ControlArgument("not enough input arguments")

501+

Umat = np.array(args[0], ndmin=2)

502+

Ymat = np.array(args[1], ndmin=2)

503+

transpose = kwargs.pop('transpose', False)

504+

if transpose:

505+

Umat, Ymat = np.transpose(Umat), np.transpose(Ymat)

506+

index = 2

507+508+509+

if (len(args) > index):

510+

m = args[index]

511+

else:

512+

m = None

513+514+

dt = kwargs.pop('dt', True)

515+

truncate = kwargs.pop('truncate', False)

474516475517

# Make sure the number of time points match

476518

if Umat.shape[1] != Ymat.shape[1]:

@@ -549,4 +591,4 @@ def markov(data, m=None, dt=True, truncate=False):

549591

H = np.squeeze(H)

550592551593

# Return the first m Markov parameters

552-

return H if not data.transpose else np.transpose(H)

594+

return H if not transpose else np.transpose(H)