Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0f03778

Browse files
Merge branch 'python-control:main' into main
2 parents0f08b1e +ad6b49e commit0f03778

19 files changed

+930
-137
lines changed

‎control/bdalg.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,11 @@ def negate(sys):
201201
--------
202202
>>> G = ct.tf([2], [1, 1])
203203
>>> G.dcgain()
204-
2.0
204+
np.float64(2.0)
205205
206206
>>> Gn = ct.negate(G) # Same as sys2 = -sys1.
207207
>>> Gn.dcgain()
208-
-2.0
208+
np.float64(-2.0)
209209
210210
"""
211211
return-sys

‎control/descfcn.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -525,11 +525,11 @@ class saturation_nonlinearity(DescribingFunctionNonlinearity):
525525
--------
526526
>>> nl = ct.saturation_nonlinearity(5)
527527
>>> nl(1)
528-
1
528+
np.int64(1)
529529
>>> nl(10)
530-
5
530+
np.int64(5)
531531
>>> nl(-10)
532-
-5
532+
np.int64(-5)
533533
534534
"""
535535
def__init__(self,ub=1,lb=None):

‎control/freqplot.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,7 +1919,7 @@ def _parse_linestyle(style_name, allow_false=False):
19191919
# Internal function to add arrows to a curve
19201920
def_add_arrows_to_line2D(
19211921
axes,line,arrow_locs=[0.2,0.4,0.6,0.8],
1922-
arrowstyle='-|>',arrowsize=1,dir=1,transform=None):
1922+
arrowstyle='-|>',arrowsize=1,dir=1):
19231923
"""
19241924
Add arrows to a matplotlib.lines.Line2D at selected locations.
19251925
@@ -1930,7 +1930,6 @@ def _add_arrows_to_line2D(
19301930
arrow_locs: list of locations where to insert arrows, % of total length
19311931
arrowstyle: style of the arrow
19321932
arrowsize: size of the arrow
1933-
transform: a matplotlib transform instance, default to data coordinates
19341933
19351934
Returns:
19361935
--------
@@ -1939,13 +1938,13 @@ def _add_arrows_to_line2D(
19391938
Based on https://stackoverflow.com/questions/26911898/
19401939
19411940
"""
1941+
# Get the coordinates of the line, in plot coordinates
19421942
ifnotisinstance(line,mpl.lines.Line2D):
19431943
raiseValueError("expected a matplotlib.lines.Line2D object")
19441944
x,y=line.get_xdata(),line.get_ydata()
19451945

1946-
arrow_kw= {
1947-
"arrowstyle":arrowstyle,
1948-
}
1946+
# Determine the arrow properties
1947+
arrow_kw= {"arrowstyle":arrowstyle}
19491948

19501949
color=line.get_color()
19511950
use_multicolor_lines=isinstance(color,np.ndarray)
@@ -1960,36 +1959,43 @@ def _add_arrows_to_line2D(
19601959
else:
19611960
arrow_kw['linewidth']=linewidth
19621961

1963-
iftransformisNone:
1964-
transform=axes.transData
1962+
# Figure out the size of the axes (length of diagonal)
1963+
xlim,ylim=axes.get_xlim(),axes.get_ylim()
1964+
ul,lr=np.array([xlim[0],ylim[0]]),np.array([xlim[1],ylim[1]])
1965+
diag=np.linalg.norm(ul-lr)
19651966

19661967
# Compute the arc length along the curve
19671968
s=np.cumsum(np.sqrt(np.diff(x)**2+np.diff(y)**2))
19681969

1970+
# Truncate the number of arrows if the curve is short
1971+
# TODO: figure out a smarter way to do this
1972+
frac=min(s[-1]/diag,1)
1973+
iflen(arrow_locs)andfrac<0.05:
1974+
arrow_locs= []# too short; no arrows at all
1975+
eliflen(arrow_locs)andfrac<0.2:
1976+
arrow_locs= [0.5]# single arrow in the middle
1977+
1978+
# Plot the arrows (and return list if patches)
19691979
arrows= []
19701980
forlocinarrow_locs:
19711981
n=np.searchsorted(s,s[-1]*loc)
19721982

1973-
# Figure out what direction to paint the arrow
1974-
ifdir==1:
1975-
arrow_tail= (x[n],y[n])
1976-
arrow_head= (np.mean(x[n:n+2]),np.mean(y[n:n+2]))
1977-
elifdir==-1:
1978-
# Orient the arrow in the other direction on the segment
1979-
arrow_tail= (x[n+1],y[n+1])
1980-
arrow_head= (np.mean(x[n:n+2]),np.mean(y[n:n+2]))
1981-
else:
1982-
raiseValueError("unknown value for keyword 'dir'")
1983+
ifdir==1andn==0:
1984+
# Move the arrow forward by one if it is at start of a segment
1985+
n=1
1986+
1987+
# Place the head of the arrow at the desired location
1988+
arrow_head= [x[n],y[n]]
1989+
arrow_tail= [x[n-dir],y[n-dir]]
19831990

19841991
p=mpl.patches.FancyArrowPatch(
1985-
arrow_tail,arrow_head,transform=transform,lw=0,
1992+
arrow_tail,arrow_head,transform=axes.transData,lw=0,
19861993
**arrow_kw)
19871994
axes.add_patch(p)
19881995
arrows.append(p)
19891996
returnarrows
19901997

19911998

1992-
19931999
#
19942000
# Function to compute Nyquist curve offsets
19952001
#

‎control/lti.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ def dcgain(sys):
525525
--------
526526
>>> G = ct.tf([1], [1, 2])
527527
>>> ct.dcgain(G) # doctest: +SKIP
528-
0.5
528+
np.float(0.5)
529529
530530
"""
531531
returnsys.dcgain()

‎control/modelsimp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def hsvd(sys):
8787
>>> G = ct.tf2ss([1], [1, 2])
8888
>>> H = ct.hsvd(G)
8989
>>> H[0]
90-
0.25
90+
np.float64(0.25)
9191
9292
"""
9393
# TODO: implement for discrete time systems

‎control/nlsys.py

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,17 @@
1818
1919
"""
2020

21-
importnumpyasnp
22-
importscipyassp
2321
importcopy
2422
fromwarningsimportwarn
2523

24+
importnumpyasnp
25+
importscipyassp
26+
2627
from .importconfig
27-
from .iosysimportInputOutputSystem,_process_signal_list, \
28-
_process_iosys_keywords,isctime,isdtime,common_timebase,_parse_spec
29-
from .timerespimport_check_convert_array,_process_time_response, \
30-
TimeResponseData
28+
from .iosysimportInputOutputSystem,_parse_spec,_process_iosys_keywords, \
29+
_process_signal_list,common_timebase,isctime,isdtime
30+
from .timerespimportTimeResponseData,_check_convert_array, \
31+
_process_time_response
3132

3233
__all__= ['NonlinearIOSystem','InterconnectedSystem','nlsys',
3334
'input_output_response','find_eqpt','linearize',
@@ -132,13 +133,15 @@ def __init__(self, updfcn, outfcn=None, params=None, **kwargs):
132133
ifupdfcnisNone:
133134
ifself.nstatesisNone:
134135
self.nstates=0
136+
self.updfcn=lambdat,x,u,params:np.zeros(0)
135137
else:
136138
raiseValueError(
137139
"states specified but no update function given.")
138140

139141
ifoutfcnisNone:
140-
# No output function specified => outputs = states
141-
ifself.noutputsisNoneandself.nstatesisnotNone:
142+
ifself.noutputs==0:
143+
self.outfcn=lambdat,x,u,params:np.zeros(0)
144+
elifself.noutputsisNoneandself.nstatesisnotNone:
142145
self.noutputs=self.nstates
143146
elifself.noutputsisnotNoneandself.noutputs==self.nstates:
144147
# Number of outputs = number of states => all is OK
@@ -364,9 +367,8 @@ def _rhs(self, t, x, u):
364367
user-friendly interface you may want to use :meth:`dynamics`.
365368
366369
"""
367-
xdot=self.updfcn(t,x,u,self._current_params) \
368-
ifself.updfcnisnotNoneelse []
369-
returnnp.array(xdot).reshape((-1,))
370+
returnnp.asarray(
371+
self.updfcn(t,x,u,self._current_params)).reshape(-1)
370372

371373
defdynamics(self,t,x,u,params=None):
372374
"""Compute the dynamics of a differential or difference equation.
@@ -403,7 +405,8 @@ def dynamics(self, t, x, u, params=None):
403405
dx/dt or x[t+dt] : ndarray
404406
"""
405407
self._update_params(params)
406-
returnself._rhs(t,x,u)
408+
returnself._rhs(
409+
t,np.asarray(x).reshape(-1),np.asarray(u).reshape(-1))
407410

408411
def_out(self,t,x,u):
409412
"""Evaluate the output of a system at a given state, input, and time
@@ -414,9 +417,17 @@ def _out(self, t, x, u):
414417
:meth:`output`.
415418
416419
"""
417-
y=self.outfcn(t,x,u,self._current_params) \
418-
ifself.outfcnisnotNoneelsex
419-
returnnp.array(y).reshape((-1,))
420+
#
421+
# To allow lazy evaluation of the system size, we allow for the
422+
# possibility that noutputs is left unspecified when the system
423+
# is created => we have to check for that case here (and return
424+
# the system state or a portion of it).
425+
#
426+
ifself.outfcnisNone:
427+
returnxifself.noutputsisNoneelsex[:self.noutputs]
428+
else:
429+
returnnp.asarray(
430+
self.outfcn(t,x,u,self._current_params)).reshape(-1)
420431

421432
defoutput(self,t,x,u,params=None):
422433
"""Compute the output of the system
@@ -444,7 +455,8 @@ def output(self, t, x, u, params=None):
444455
y : ndarray
445456
"""
446457
self._update_params(params)
447-
returnself._out(t,x,u)
458+
returnself._out(
459+
t,np.asarray(x).reshape(-1),np.asarray(u).reshape(-1))
448460

449461
deffeedback(self,other=1,sign=-1,params=None):
450462
"""Feedback interconnection between two input/output systems
@@ -517,14 +529,13 @@ def linearize(self, x0, u0, t=0, params=None, eps=1e-6,
517529
# numerical linearization use the `_rhs()` and `_out()` member
518530
# functions.
519531
#
520-
521532
# If x0 and u0 are specified as lists, concatenate the elements
522533
x0=_concatenate_list_elements(x0,'x0')
523534
u0=_concatenate_list_elements(u0,'u0')
524535

525536
# Figure out dimensions if they were not specified.
526-
nstates=_find_size(self.nstates,x0)
527-
ninputs=_find_size(self.ninputs,u0)
537+
nstates=_find_size(self.nstates,x0,"states")
538+
ninputs=_find_size(self.ninputs,u0,"inputs")
528539

529540
# Convert x0, u0 to arrays, if needed
530541
ifnp.isscalar(x0):
@@ -533,7 +544,7 @@ def linearize(self, x0, u0, t=0, params=None, eps=1e-6,
533544
u0=np.ones((ninputs,))*u0
534545

535546
# Compute number of outputs by evaluating the output function
536-
noutputs=_find_size(self.noutputs,self._out(t,x0,u0))
547+
noutputs=_find_size(self.noutputs,self._out(t,x0,u0),"outputs")
537548

538549
# Update the current parameters
539550
self._update_params(params)
@@ -1306,7 +1317,7 @@ def nlsys(
13061317

13071318

13081319
definput_output_response(
1309-
sys,T,U=0.,X0=0,params=None,
1320+
sys,T,U=0.,X0=0,params=None,ignore_errors=False,
13101321
transpose=False,return_x=False,squeeze=None,
13111322
solve_ivp_kwargs=None,t_eval='T',**kwargs):
13121323
"""Compute the output response of a system to a given input.
@@ -1382,6 +1393,11 @@ def input_output_response(
13821393
to 'RK45'.
13831394
solve_ivp_kwargs : dict, optional
13841395
Pass additional keywords to :func:`scipy.integrate.solve_ivp`.
1396+
ignore_errors : bool, optional
1397+
If ``False`` (default), errors during computation of the trajectory
1398+
will raise a ``RuntimeError`` exception. If ``True``, do not raise
1399+
an exception and instead set ``results.success`` to ``False`` and
1400+
place an error message in ``results.message``.
13851401
13861402
Raises
13871403
------
@@ -1516,7 +1532,7 @@ def input_output_response(
15161532
X0=np.hstack([X0,np.zeros(sys.nstates-X0.size)])
15171533

15181534
# Compute the number of states
1519-
nstates=_find_size(sys.nstates,X0)
1535+
nstates=_find_size(sys.nstates,X0,"states")
15201536

15211537
# create X0 if not given, test if X0 has correct shape
15221538
X0=_check_convert_array(X0, [(nstates,), (nstates,1)],
@@ -1583,7 +1599,11 @@ def ivp_rhs(t, x):
15831599
ivp_rhs, (T0,Tf),X0,t_eval=t_eval,
15841600
vectorized=False,**solve_ivp_kwargs)
15851601
ifnotsoln.success:
1586-
raiseRuntimeError("solve_ivp failed: "+soln.message)
1602+
message="solve_ivp failed: "+soln.message
1603+
ifnotignore_errors:
1604+
raiseRuntimeError(message)
1605+
else:
1606+
message=None
15871607

15881608
# Compute inputs and outputs for each time point
15891609
u=np.zeros((ninputs,len(soln.t)))
@@ -1639,7 +1659,7 @@ def ivp_rhs(t, x):
16391659
u=np.transpose(np.array(u))
16401660

16411661
# Mark solution as successful
1642-
soln.success=True# No way to fail
1662+
soln.success,message=True,None# No way to fail
16431663

16441664
else:# Neither ctime or dtime??
16451665
raiseTypeError("Can't determine system type")
@@ -1649,7 +1669,8 @@ def ivp_rhs(t, x):
16491669
output_labels=sys.output_labels,input_labels=sys.input_labels,
16501670
state_labels=sys.state_labels,sysname=sys.name,
16511671
title="Input/output response for "+sys.name,
1652-
transpose=transpose,return_x=return_x,squeeze=squeeze)
1672+
transpose=transpose,return_x=return_x,squeeze=squeeze,
1673+
success=soln.success,message=message)
16531674

16541675

16551676
deffind_eqpt(sys,x0,u0=None,y0=None,t=0,params=None,
@@ -1732,9 +1753,9 @@ def find_eqpt(sys, x0, u0=None, y0=None, t=0, params=None,
17321753
fromscipy.optimizeimportroot
17331754

17341755
# Figure out the number of states, inputs, and outputs
1735-
nstates=_find_size(sys.nstates,x0)
1736-
ninputs=_find_size(sys.ninputs,u0)
1737-
noutputs=_find_size(sys.noutputs,y0)
1756+
nstates=_find_size(sys.nstates,x0,"states")
1757+
ninputs=_find_size(sys.ninputs,u0,"inputs")
1758+
noutputs=_find_size(sys.noutputs,y0,"outputs")
17381759

17391760
# Convert x0, u0, y0 to arrays, if needed
17401761
ifnp.isscalar(x0):
@@ -1977,23 +1998,23 @@ def linearize(sys, xeq, ueq=None, t=0, params=None, **kw):
19771998
returnsys.linearize(xeq,ueq,t=t,params=params,**kw)
19781999

19792000

1980-
def_find_size(sysval,vecval):
2001+
def_find_size(sysval,vecval,label):
19812002
"""Utility function to find the size of a system parameter
19822003
19832004
If both parameters are not None, they must be consistent.
19842005
"""
19852006
ifhasattr(vecval,'__len__'):
19862007
ifsysvalisnotNoneandsysval!=len(vecval):
1987-
raiseValueError("Inconsistent information to determine size "
1988-
"ofsystem component")
2008+
raiseValueError(
2009+
f"inconsistent information for numberof{label}")
19892010
returnlen(vecval)
19902011
# None or 0, which is a valid value for "a (sysval, ) vector of zeros".
19912012
ifnotvecval:
19922013
return0ifsysvalisNoneelsesysval
19932014
elifsysval==1:
19942015
# (1, scalar) is also a valid combination from legacy code
19952016
return1
1996-
raiseValueError("can't determinesize ofsystem component")
2017+
raiseValueError(f"can't determinenumber of{label}")
19972018

19982019

19992020
# Function to create an interconnected system
@@ -2241,7 +2262,7 @@ def interconnect(
22412262
`outputs`, for more natural naming of SISO systems.
22422263
22432264
"""
2244-
from .statespimportStateSpace,LinearICSystem,_convert_to_statespace
2265+
from .statespimportLinearICSystem,StateSpace,_convert_to_statespace
22452266
from .xferfcnimportTransferFunction
22462267

22472268
dt=kwargs.pop('dt',None)# bypass normal 'dt' processing
@@ -2551,7 +2572,7 @@ def interconnect(
25512572
returnnewsys
25522573

25532574

2554-
# Utility function to allow lists states, inputs
2575+
# Utility function to allow listsofstates, inputs
25552576
def_concatenate_list_elements(X,name='X'):
25562577
# If we were passed a list, concatenate the elements together
25572578
ifisinstance(X, (tuple,list)):
@@ -2574,13 +2595,14 @@ def _convert_static_iosystem(sys):
25742595
# Convert sys1 to an I/O system if needed
25752596
ifisinstance(sys, (int,float,np.number)):
25762597
returnNonlinearIOSystem(
2577-
None,lambdat,x,u,params:sys*u,inputs=1,outputs=1)
2598+
None,lambdat,x,u,params:sys*u,
2599+
outputs=1,inputs=1,dt=None)
25782600

25792601
elifisinstance(sys,np.ndarray):
25802602
sys=np.atleast_2d(sys)
25812603
returnNonlinearIOSystem(
25822604
None,lambdat,x,u,params:sys @u,
2583-
outputs=sys.shape[0],inputs=sys.shape[1])
2605+
outputs=sys.shape[0],inputs=sys.shape[1],dt=None)
25842606

25852607
defconnection_table(sys,show_names=False,column_width=32):
25862608
"""Print table of connections inside an interconnected system model.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp