74
74
75
75
# External function declarations
76
76
from numpy import angle , any , array , empty , finfo , insert , ndarray , ones , \
77
- polyadd , polymul , polyval , roots , sort , sqrt , zeros , squeeze , inner
78
- from scipy .interpolate import interp1d
77
+ polyadd , polymul , polyval , roots , sort , sqrt , zeros , squeeze , inner , \
78
+ real , imag , matrix , absolute
79
+ from scipy .interpolate import splprep , splev
79
80
from copy import deepcopy
80
81
from lti import Lti
81
82
import statesp
@@ -84,7 +85,7 @@ class FRD(Lti):
84
85
85
86
"""The FRD class represents (measured?) frequency response
86
87
TF instances and functions.
87
- 4
88
+
88
89
The FRD class is derived from the Lti parent class. It is used
89
90
throughout the python-control library to represent systems in frequency
90
91
response data form.
@@ -127,7 +128,6 @@ def __init__(self, *args):
127
128
# not an FRD, but still a system, second argument should be
128
129
# the frequency range
129
130
otherlti = args [0 ]
130
- print args [1 ]
131
131
self .omega = array (args [1 ], dtype = float )
132
132
self .omega .sort ()
133
133
numfreq = len (self .omega )
@@ -166,10 +166,13 @@ def __init__(self, *args):
166
166
167
167
# create interpolation functions
168
168
self .ifunc = empty ((self .fresp .shape [1 ], self .fresp .shape [0 ]),
169
- dtype = interp1d )
169
+ dtype = tuple )
170
170
for i in range (self .fresp .shape [1 ]):
171
171
for j in range (self .fresp .shape [0 ]):
172
- self .ifunc [i ,j ] = interp1d (self .omega , self .fresp [i , j , :])
172
+ self .ifunc [i ,j ],u = splprep (
173
+ u = self .omega , x = [real (self .fresp [i , j , :]),
174
+ imag (self .fresp [i , j , :])],
175
+ w = 1.0 / (absolute (self .fresp [i , j , :])+ 0.001 ), s = 0.01 )
173
176
174
177
Lti .__init__ (self , self .fresp .shape [1 ], self .fresp .shape [0 ])
175
178
@@ -179,14 +182,15 @@ def __str__(self):
179
182
mimo = self .inputs > 1 or self .outputs > 1
180
183
outstr = [ 'frequency response data ' ]
181
184
185
+ mt , pt , wt = self .freqresp (self .omega )
182
186
for i in range (self .inputs ):
183
187
for j in range (self .outputs ):
184
188
if mimo :
185
189
outstr .append ("Input %i to output %i:" % (i + 1 , j + 1 ))
186
190
outstr .append ('Freq [rad/s] Magnitude Phase' )
187
191
outstr .extend (
188
192
[ '%f %f %f' % (w , m , p * 180.0 )
189
- for m , p , w in self . freqresp ( self . omega ) ])
193
+ for m , p , w in zip ( mt [ i ][ j ], pt [ i ][ j ], wt ) ])
190
194
191
195
return '\n ' .join (outstr )
192
196
@@ -335,7 +339,8 @@ def evalfr(self, omega):
335
339
336
340
for i in range (self .outputs ):
337
341
for j in range (self .inputs ):
338
- out [i ,j ] = self .ifunc [i ,j ](omega )
342
+ out [i ,j ] = inner (array ([1 , 1j ]),
343
+ splev (omega , self .ifunc [i ,j ], der = 0 ))
339
344
340
345
return out
341
346
@@ -360,7 +365,7 @@ def freqresp(self, omega):
360
365
361
366
for i in range (self .outputs ):
362
367
for j in range (self .inputs ):
363
- fresp = self .ifunc [i ,j ]( omega )
368
+ fresp = matrix ([[ 1 , 1j ]]) * splev ( omega , self .ifunc [i ,j ])
364
369
mag [i , j , :] = abs (fresp )
365
370
phase [i , j , :] = angle (fresp )
366
371
@@ -375,18 +380,18 @@ def feedback(self, other, sign=-1):
375
380
self .inputs != other .outputs ):
376
381
raise ValueError (
377
382
"FRD.feedback, inputs/outputs mismatch" )
378
- fresp = empty (self .outputs , self .inputs , len (other .omega ))
383
+ fresp = empty ((self .outputs , self .inputs , len (other .omega )),
384
+ dtype = complex )
379
385
# TODO: vectorize this
380
386
# TODO: handle omega re-mapping
381
387
for k , w in enumerate (other .omega ):
382
- for i in range (0 , self .inputs ):
383
- for j in range (0 , self .outputs ):
388
+ for i in range (self .inputs ):
389
+ for j in range (self .outputs ):
384
390
fresp [i , j , k ] = \
385
391
self .fresp [i , j , k ] / \
386
- (1.0 + inner (self .fresp [i , : , k ], other .fresp [:, i , k ]))
392
+ (1.0 - sign * inner (self .fresp [:, j , k ], other .fresp [i , : , k ]))
387
393
388
394
return FRD (fresp , other .omega )
389
-
390
395
391
396
def _convertToFRD (sys , omega , inputs = 1 , outputs = 1 ):
392
397
"""Convert a system to frequency response data form (if needed).
@@ -442,9 +447,20 @@ def _convertToFRD(sys, omega, inputs=1, outputs=1):
442
447
return FRD (fresp , omega )
443
448
444
449
elif isinstance (sys , (int , long , float , complex )):
445
-
446
450
fresp = ones ((outputs , inputs , len (omega )), dtype = float )* sys
447
-
448
451
return FRD (fresp , omega )
449
- else :
450
- raise TypeError ("Can't convert given type to FRD system." )
452
+
453
+ # try converting constant matrices
454
+ try :
455
+ sys = array (sys )
456
+ outputs ,inputs = sys .shape
457
+ fresp = empty ((outputs , inputs , len (omega )), dtype = float )
458
+ for i in range (outputs ):
459
+ for j in range (inputs ):
460
+ fresp [i ,j ,:] = sys [i ,j ]
461
+ return FRD (fresp , omega )
462
+ except :
463
+ pass
464
+
465
+ raise TypeError ('''Can't convert given type "%s" to FRD system.''' %
466
+ sys .__class__ )
0 commit comments