@@ -111,7 +111,7 @@ class for a set of subclasses that are used to implement specific
111111 The :class:`~control.InputOuputSystem` class (and its subclasses) makes
112112 use of two special methods for implementing much of the work of the class:
113113
114- * _rhs (t, x, u): compute the right hand side of the differential or
114+ * dynamics (t, x, u): compute the right hand side of the differential or
115115 difference equation for the system. This must be specified by the
116116 subclass for the system.
117117
@@ -353,28 +353,69 @@ def _process_signal_list(self, signals, prefix='s'):
353353 # Find a signal by name
354354 def _find_signal (self , name , sigdict ): return sigdict .get (name , None )
355355
356- # Update parameters used for _rhs , _out (used by subclasses)
356+ # Update parameters used for dynamics , _out (used by subclasses)
357357 def _update_params (self , params , warning = False ):
358358 if (warning ):
359359 warn ("Parameters passed to InputOutputSystem ignored." )
360360
361- def _rhs (self , t , x , u ):
362- """Evaluate right hand side of a differential or difference equation.
361+ def dynamics (self , t , x , u ):
362+ """Compute the dynamics of a differential or difference equation.
363363
364- Private function used to compute the right hand side of an
365- input/output system model.
364+ Given time `t`, input `u` and state `x`, returns the dynamics of the
365+ system. If the system is continuous, returns the time derivative
366366
367+ ``dx/dt = f(t, x, u)``
368+
369+ where `f` is the system's (possibly nonlinear) dynamics function.
370+ If the system is discrete-time, returns the next value of `x`:
371+
372+ ``x[t+dt] = f(t, x[t], u[t])``
373+
374+ Where `t` is a scalar.
375+
376+ The inputs `x` and `u` must be of the correct length.
377+
378+ Parameters
379+ ----------
380+ t : float
381+ the time at which to evaluate
382+ x : array_like
383+ current state
384+ u : array_like
385+ input
386+
387+ Returns
388+ -------
389+ `dx/dt` or `x[t+dt]` : ndarray
367390 """
368- NotImplemented ("Evaluation not implemented for system of type " ,
391+
392+ NotImplemented ("Dynamics not implemented for system of type " ,
369393 type (self ))
370394
371395 def _out (self , t , x , u , params = {}):
372- """Evaluate the output of a system at a given state, input, and time
396+ """Compute the output of the system
397+
398+ Given time `t`, input `u` and state `x`, returns the output of the
399+ system:
400+
401+ ``y = g(t, x, u)``
373402
374- Private function used to compute the output of of an input/output
375- system model given the state, input, parameters, and time.
403+ The inputs `x` and `u` must be of the correct length.
376404
405+ Parameters
406+ ----------
407+ t : float
408+ the time at which to evaluate
409+ x : array_like
410+ current state
411+ u : array_like
412+ input
413+
414+ Returns
415+ -------
416+ y : ndarray
377417 """
418+
378419 # If no output function was defined in subclass, return state
379420 return x
380421
@@ -533,7 +574,7 @@ def linearize(self, x0, u0, t=0, params={}, eps=1e-6,
533574 """
534575 #
535576 # If the linearization is not defined by the subclass, perform a
536- # numerical linearization use the `_rhs ()` and `_out()` member
577+ # numerical linearization use the `dynamics ()` and `_out()` member
537578 # functions.
538579 #
539580
@@ -554,7 +595,7 @@ def linearize(self, x0, u0, t=0, params={}, eps=1e-6,
554595 self ._update_params (params )
555596
556597 # Compute the nominal value of the update law and output
557- F0 = self ._rhs (t , x0 , u0 )
598+ F0 = self .dynamics (t , x0 , u0 )
558599 H0 = self ._out (t , x0 , u0 )
559600
560601 # Create empty matrices that we can fill up with linearizations
@@ -567,14 +608,14 @@ def linearize(self, x0, u0, t=0, params={}, eps=1e-6,
567608 for i in range (nstates ):
568609 dx = np .zeros ((nstates ,))
569610 dx [i ] = eps
570- A [:, i ] = (self ._rhs (t , x0 + dx , u0 ) - F0 ) / eps
611+ A [:, i ] = (self .dynamics (t , x0 + dx , u0 ) - F0 ) / eps
571612 C [:, i ] = (self ._out (t , x0 + dx , u0 ) - H0 ) / eps
572613
573614 # Perturb each of the input variables and compute linearization
574615 for i in range (ninputs ):
575616 du = np .zeros ((ninputs ,))
576617 du [i ] = eps
577- B [:, i ] = (self ._rhs (t , x0 , u0 + du ) - F0 ) / eps
618+ B [:, i ] = (self .dynamics (t , x0 , u0 + du ) - F0 ) / eps
578619 D [:, i ] = (self ._out (t , x0 , u0 + du ) - H0 ) / eps
579620
580621 # Create the state space system
@@ -694,7 +735,7 @@ def _update_params(self, params={}, warning=True):
694735 if params and warning :
695736 warn ("Parameters passed to LinearIOSystems are ignored." )
696737
697- def _rhs (self , t , x , u ):
738+ def dynamics (self , t , x , u ):
698739 # Convert input to column vector and then change output to 1D array
699740 xdot = np .dot (self .A , np .reshape (x , (- 1 , 1 ))) \
700741 + np .dot (self .B , np .reshape (u , (- 1 , 1 )))
@@ -863,7 +904,7 @@ def _update_params(self, params, warning=False):
863904 self ._current_params = self .params .copy ()
864905 self ._current_params .update (params )
865906
866- def _rhs (self , t , x , u ):
907+ def dynamics (self , t , x , u ):
867908 xdot = self .updfcn (t , x , u , self ._current_params ) \
868909 if self .updfcn is not None else []
869910 return np .array (xdot ).reshape ((- 1 ,))
@@ -1033,7 +1074,7 @@ def _update_params(self, params, warning=False):
10331074 local .update (params ) # update with locally passed parameters
10341075 sys ._update_params (local , warning = warning )
10351076
1036- def _rhs (self , t , x , u ):
1077+ def dynamics (self , t , x , u ):
10371078 # Make sure state and input are vectors
10381079 x = np .array (x , ndmin = 1 )
10391080 u = np .array (u , ndmin = 1 )
@@ -1047,7 +1088,7 @@ def _rhs(self, t, x, u):
10471088 for sys in self .syslist :
10481089 # Update the right hand side for this subsystem
10491090 if sys .nstates != 0 :
1050- xdot [state_index :state_index + sys .nstates ] = sys ._rhs (
1091+ xdot [state_index :state_index + sys .nstates ] = sys .dynamics (
10511092 t , x [state_index :state_index + sys .nstates ],
10521093 ulist [input_index :input_index + sys .ninputs ])
10531094
@@ -1497,14 +1538,14 @@ def input_output_response(sys, T, U=0., X0=0, params={}, method='RK45',
14971538
14981539 # Create a lambda function for the right hand side
14991540 u = sp .interpolate .interp1d (T , U , fill_value = "extrapolate" )
1500- def ivp_rhs (t , x ): return sys ._rhs (t , x , u (t ))
1541+ def ivp_dynamics (t , x ): return sys .dynamics (t , x , u (t ))
15011542
15021543 # Perform the simulation
15031544 if isctime (sys ):
15041545 if not hasattr (sp .integrate , 'solve_ivp' ):
15051546 raise NameError ("scipy.integrate.solve_ivp not found; "
15061547 "use SciPy 1.0 or greater" )
1507- soln = sp .integrate .solve_ivp (ivp_rhs , (T0 , Tf ), X0 , t_eval = T ,
1548+ soln = sp .integrate .solve_ivp (ivp_dynamics , (T0 , Tf ), X0 , t_eval = T ,
15081549 method = method , vectorized = False )
15091550
15101551 # Compute the output associated with the state (and use sys.out to
@@ -1549,7 +1590,7 @@ def ivp_rhs(t, x): return sys._rhs(t, x, u(t))
15491590 y .append (sys ._out (T [i ], x , u (T [i ])))
15501591
15511592 # Update the state for the next iteration
1552- x = sys ._rhs (T [i ], x , u (T [i ]))
1593+ x = sys .dynamics (T [i ], x , u (T [i ]))
15531594
15541595 # Convert output to numpy arrays
15551596 soln .y = np .transpose (np .array (soln .y ))
@@ -1670,8 +1711,8 @@ def find_eqpt(sys, x0, u0=[], y0=None, t=0, params={},
16701711 if y0 is None :
16711712 # Take u0 as fixed and minimize over x
16721713 # TODO: update to allow discrete time systems
1673- def ode_rhs (z ): return sys ._rhs (t , z , u0 )
1674- result = root (ode_rhs , x0 , ** kw )
1714+ def ode_dynamics (z ): return sys .dynamics (t , z , u0 )
1715+ result = root (ode_dynamics , x0 , ** kw )
16751716 z = (result .x , u0 , sys ._out (t , result .x , u0 ))
16761717 else :
16771718 # Take y0 as fixed and minimize over x and u
@@ -1680,7 +1721,7 @@ def rootfun(z):
16801721 x , u = np .split (z , [nstates ])
16811722 # TODO: update to allow discrete time systems
16821723 return np .concatenate (
1683- (sys ._rhs (t , x , u ), sys ._out (t , x , u ) - y0 ), axis = 0 )
1724+ (sys .dynamics (t , x , u ), sys ._out (t , x , u ) - y0 ), axis = 0 )
16841725 z0 = np .concatenate ((x0 , u0 ), axis = 0 ) # Put variables together
16851726 result = root (rootfun , z0 , ** kw ) # Find the eq point
16861727 x , u = np .split (result .x , [nstates ]) # Split result back in two
@@ -1782,7 +1823,7 @@ def rootfun(z):
17821823 u [input_vars ] = z [nstate_vars :]
17831824
17841825 # Compute the update and output maps
1785- dx = sys ._rhs (t , x , u ) - dx0
1826+ dx = sys .dynamics (t , x , u ) - dx0
17861827 if dtime :
17871828 dx -= x # TODO: check
17881829 dy = sys ._out (t , x , u ) - y0
0 commit comments