|
50 | 50 | real, imag, absolute, eye, linalg, where, sort |
51 | 51 | from scipy.interpolate import splprep, splev |
52 | 52 | from .lti import LTI, _process_frequency_response |
| 53 | +from .exception import pandas_check |
| 54 | +from .namedio import _NamedIOSystem |
53 | 55 | from . import config |
54 | 56 |
|
55 | 57 | __all__ = ['FrequencyResponseData', 'FRD', 'frd'] |
56 | 58 |
|
57 | 59 |
|
58 | | -class FrequencyResponseData(LTI): |
| 60 | +class FrequencyResponseData(LTI, _NamedIOSystem): |
59 | 61 | """FrequencyResponseData(d, w[, smooth]) |
60 | 62 |
|
61 | 63 | A class for models defined by frequency response data (FRD). |
@@ -152,10 +154,6 @@ def __init__(self, *args, **kwargs): |
152 | 154 | # TODO: discrete-time FRD systems? |
153 | 155 | smooth = kwargs.pop('smooth', False) |
154 | 156 |
|
155 | | - # Make sure there were no extraneous keywords |
156 | | - if kwargs: |
157 | | - raise TypeError("unrecognized keywords: ", str(kwargs)) |
158 | | - |
159 | 157 | if len(args) == 2: |
160 | 158 | if not isinstance(args[0], FRD) and isinstance(args[0], LTI): |
161 | 159 | # not an FRD, but still a system, second argument should be |
@@ -196,6 +194,23 @@ def __init__(self, *args, **kwargs): |
196 | 194 | raise ValueError( |
197 | 195 | "Needs 1 or 2 arguments; received %i." % len(args)) |
198 | 196 |
|
| 197 | + # Set the size of the system |
| 198 | + self.noutputs = self.fresp.shape[0] |
| 199 | + self.ninputs = self.fresp.shape[1] |
| 200 | + |
| 201 | + # Process signal names |
| 202 | + _NamedIOSystem.__init__( |
| 203 | + self, name=kwargs.pop('name', None), |
| 204 | + inputs=kwargs.pop('inputs', self.ninputs), |
| 205 | + outputs=kwargs.pop('outputs', self.noutputs)) |
| 206 | + |
| 207 | + # Keep track of return type |
| 208 | + self.return_magphase=kwargs.pop('return_magphase', False) |
| 209 | + |
| 210 | + # Make sure there were no extraneous keywords |
| 211 | + if kwargs: |
| 212 | + raise TypeError("unrecognized keywords: ", str(kwargs)) |
| 213 | + |
199 | 214 | # create interpolation functions |
200 | 215 | if smooth: |
201 | 216 | self.ifunc = empty((self.fresp.shape[0], self.fresp.shape[1]), |
@@ -260,11 +275,13 @@ def __add__(self, other): |
260 | 275 |
|
261 | 276 | # Check that the input-output sizes are consistent. |
262 | 277 | if self.ninputs != other.ninputs: |
263 | | - raise ValueError("The first summand has %i input(s), but the \ |
264 | | -second has %i." % (self.ninputs, other.ninputs)) |
| 278 | + raise ValueError( |
| 279 | + "The first summand has %i input(s), but the " \ |
| 280 | + "second has %i." % (self.ninputs, other.ninputs)) |
265 | 281 | if self.noutputs != other.noutputs: |
266 | | - raise ValueError("The first summand has %i output(s), but the \ |
267 | | -second has %i." % (self.noutputs, other.noutputs)) |
| 282 | + raise ValueError( |
| 283 | + "The first summand has %i output(s), but the " \ |
| 284 | + "second has %i." % (self.noutputs, other.noutputs)) |
268 | 285 |
|
269 | 286 | return FRD(self.fresp + other.fresp, other.omega) |
270 | 287 |
|
@@ -551,6 +568,22 @@ def feedback(self, other=1, sign=-1): |
551 | 568 |
|
552 | 569 | return FRD(fresp, other.omega, smooth=(self.ifunc is not None)) |
553 | 570 |
|
| 571 | + # Convert to pandas |
| 572 | + def to_pandas(self): |
| 573 | + if not pandas_check(): |
| 574 | + ImportError('pandas not installed') |
| 575 | + import pandas |
| 576 | + |
| 577 | + # Create a dict for setting up the data frame |
| 578 | + data = {'omega': self.omega} |
| 579 | + data.update( |
| 580 | + {'H_{%s, %s}' % (out, inp): self.fresp[i, j] \ |
| 581 | + for i, out in enumerate(self.output_labels) \ |
| 582 | + for j, inp in enumerate(self.input_labels)}) |
| 583 | + |
| 584 | + return pandas.DataFrame(data) |
| 585 | + |
| 586 | + |
554 | 587 | # |
555 | 588 | # Allow FRD as an alias for the FrequencyResponseData class |
556 | 589 | # |
|
0 commit comments