7575# External function declarations
7676from numpy import angle , any , array , empty , finfo , insert , ndarray , ones , \
7777 polyadd , polymul , polyval , roots , sort , sqrt , zeros , squeeze , inner , \
78- real , imag , matrix , absolute , eye , linalg , pi
78+ real , imag , matrix , absolute , eye , linalg , pi , where
7979from scipy .interpolate import splprep , splev
8080from copy import deepcopy
8181from lti import Lti
@@ -106,7 +106,7 @@ class FRD(Lti):
106106
107107 epsw = 1e-8
108108
109- def __init__ (self , * args ):
109+ def __init__ (self , * args , ** kwargs ):
110110 """Construct a transfer function.
111111
112112 The default constructor is FRD(w, d), where w is an iterable of
@@ -122,6 +122,7 @@ def __init__(self, *args):
122122 object, other than an FRD, call FRD(sys, omega)
123123
124124 """
125+ smooth = kwargs .get ('smooth' , False )
125126
126127 if len (args ) == 2 :
127128 if not isinstance (args [0 ], FRD ) and isinstance (args [0 ], Lti ):
@@ -165,15 +166,17 @@ def __init__(self, *args):
165166 raise ValueError ("Needs 1 or 2 arguments; receivd %i." % len (args ))
166167
167168 # create interpolation functions
168- self .ifunc = empty ((self .fresp .shape [1 ], self .fresp .shape [0 ]),
169- dtype = tuple )
170- for i in range (self .fresp .shape [1 ]):
171- for j in range (self .fresp .shape [0 ]):
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.0 )
176-
169+ if smooth :
170+ self .ifunc = empty ((self .fresp .shape [1 ], self .fresp .shape [0 ]),
171+ dtype = tuple )
172+ for i in range (self .fresp .shape [1 ]):
173+ for j in range (self .fresp .shape [0 ]):
174+ self .ifunc [i ,j ],u = splprep (
175+ u = self .omega , x = [real (self .fresp [i , j , :]),
176+ imag (self .fresp [i , j , :])],
177+ w = 1.0 / (absolute (self .fresp [i , j , :])+ 0.001 ), s = 0.0 )
178+ else :
179+ self .ifunc = None
177180 Lti .__init__ (self , self .fresp .shape [1 ], self .fresp .shape [0 ])
178181
179182 def __str__ (self ):
@@ -187,14 +190,11 @@ def __str__(self):
187190 for j in range (self .outputs ):
188191 if mimo :
189192 outstr .append ("Input %i to output %i:" % (i + 1 , j + 1 ))
190- outstr .append ('Freq [rad/s] Magnitude Phase' )
191- outstr .append ('------------ ----------- -----------' )
192- # outstr.extend(
193- # [ '%12.3f %11.3e %11.2f' % (w, m, p*180.0/pi)
194- # for m, p, w in zip(mt[i][j], pt[i][j], wt) ])
193+ outstr .append ('Freq [rad/s] Response ' )
194+ outstr .append ('------------ ------------------------' )
195195 outstr .extend (
196196 [ '%12.3f %10.4g + %10.4g' % (w , m , p )
197- for m , p , w in zip (real (self .fresp [i , j , :]), imag (self .fresp [i , j ,:]), wt ) ])
197+ for m , p , w in zip (real (self .fresp [j , i , :]), imag (self .fresp [j , i ,:]), wt ) ])
198198
199199
200200 return '\n ' .join (outstr )
@@ -316,10 +316,12 @@ def __rdiv__(self, other):
316316
317317 if (self .inputs > 1 or self .outputs > 1 or
318318 other .inputs > 1 or other .outputs > 1 ):
319- raise NotImplementedError ("FRD.__rdiv__ is currently \
320- implemented only for SISO systems." )
319+ raise NotImplementedError (
320+ "FRD.__rdiv__ is currently implemented only for SISO systems." )
321321
322322 return other / self
323+
324+
323325 def __pow__ (self ,other ):
324326 if not type (other ) == int :
325327 raise ValueError ("Exponent must be an integer" )
@@ -342,10 +344,18 @@ def evalfr(self, omega):
342344 # Preallocate the output.
343345 out = empty ((self .outputs , self .inputs ), dtype = complex )
344346
345- for i in range (self .outputs ):
346- for j in range (self .inputs ):
347- frraw = splev (omega , self .ifunc [i ,j ], der = 0 )
348- out [i ,j ] = frraw [0 ] + 1.0j * frraw [1 ]
347+ if self .ifunc is None :
348+ try :
349+ out = self .fresp [:, :, where (self .omega == omega )[0 ][0 ]]
350+ except :
351+ raise ValueError (
352+ "Frequency %f not in frequency list, try an interpolating"
353+ " FRD if you want additional points" )
354+ else :
355+ for i in range (self .outputs ):
356+ for j in range (self .inputs ):
357+ frraw = splev (omega , self .ifunc [i ,j ], der = 0 )
358+ out [i ,j ] = frraw [0 ] + 1.0j * frraw [1 ]
349359
350360 return out
351361
@@ -389,19 +399,13 @@ def feedback(self, other, sign=-1):
389399 # TODO: vectorize this
390400 # TODO: handle omega re-mapping
391401 for k , w in enumerate (other .omega ):
392- fresp [:, :, k ] = linalg .solve (
402+ fresp [:, :, k ] = self .fresp [:, :, k ].view (type = matrix )* \
403+ linalg .solve (
393404 eye (self .inputs ) +
394- self .fresp [:, :, k ].view (type = matrix ) *
395- other .fresp [:, :, k ].view (type = matrix ),
396- eye (self .inputs ))* self . fresp [:, :, k ]. view ( type = matrix )
405+ other .fresp [:, :, k ].view (type = matrix ) *
406+ self .fresp [:, :, k ].view (type = matrix ),
407+ eye (self .inputs ))
397408
398- # for i in range(self.inputs):
399- # for j in range(self.outputs):
400- # fresp[i, j, k] = \
401- # self.fresp[i, j, k] / \
402- # (1.0-sign*inner(self.fresp[:, j, k],
403- # other.fresp[i, :, k]))
404-
405409 return FRD (fresp , other .omega )
406410
407411def _convertToFRD (sys , omega , inputs = 1 , outputs = 1 ):
@@ -429,26 +433,9 @@ def _convertToFRD(sys, omega, inputs=1, outputs=1):
429433 # frequencies match, and system was already frd; simply use
430434 return sys
431435
432- # omega becomes lowest common range
433- omega = omega [omega >= min (sys .omega )]
434- omega = omega [omega <= max (sys .omega )]
435- if not omega :
436- raise ValueError ("Frequency ranges of FRD do not overlap" )
437-
438- # if there would be data beyond the extremes, add omega points at the
439- # edges
440- if omega [0 ] - sys .omega [0 ] > FRD .epsw :
441- omega .insert (sys .omega [0 ], 0 )
442- if sys .omega [- 1 ] - omega [- 1 ] > FRD .epsw :
443- omega .append (sys .omega [- 1 ])
444- print "Adjusting frequency range in FRD"
445-
446- fresp = empty ((sys .outputs , sys .inputs , len (omega )), dtype = complex )
447- for k , w in enumerate (omega ):
448- fresp [:, :, k ] = sys .evalfr (w )
449-
450- return FRD (fresp , omega )
451-
436+ raise NotImplementedError (
437+ "Frequency ranges of FRD do not match, conversion not implemented" )
438+
452439 elif isinstance (sys , Lti ):
453440 omega .sort ()
454441 fresp = empty ((sys .outputs , sys .inputs , len (omega )), dtype = complex )
0 commit comments