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

Commitf5bca43

Browse files
committed
additional updates based on@roryyorke review feedback
1 parent1965eb3 commitf5bca43

File tree

3 files changed

+35
-38
lines changed

3 files changed

+35
-38
lines changed

‎control/descfcn.py

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from .freqplotimportnyquist_plot
2222

2323
__all__= ['describing_function','describing_function_plot',
24-
'DescribingFunctionNonlinearity','backlash_nonlinearity',
24+
'DescribingFunctionNonlinearity','friction_backlash_nonlinearity',
2525
'relay_hysteresis_nonlinearity','saturation_nonlinearity']
2626

2727
# Class for nonlinearities with a built-in describing function
@@ -95,7 +95,7 @@ def describing_function(
9595
use the :class:`~control.DescribingFunctionNonlinearity` class,
9696
which provides this functionality.
9797
98-
A :float orarray_like
98+
A : array_like
9999
The amplitude(s) at which the describing function should be calculated.
100100
101101
zero_check : bool, optional
@@ -112,25 +112,19 @@ def describing_function(
112112
113113
Returns
114114
-------
115-
df : complex or array of complex
116-
The (complex) value of the describing function at the given amplitude.
117-
If the `A` parameter is an array of amplitudes, then an array of
118-
corresponding describing function values is returned.
115+
df : array of complex
116+
The (complex) value of the describing function at the given amplitudes.
119117
120118
Raises
121119
------
122120
TypeError
123-
If A < 0 or if A = 0 and the function F(0) is non-zero.
121+
If A[i] < 0 or if A[i] = 0 and the function F(0) is non-zero.
124122
125123
"""
126124
# If there is an analytical solution, trying using that first
127125
iftry_methodandhasattr(F,'describing_function'):
128126
try:
129-
# Go through all of the amplitudes we were given
130-
df= []
131-
forainnp.atleast_1d(A):
132-
df.append(F.describing_function(a))
133-
returnnp.array(df).reshape(np.shape(A))
127+
returnnp.vectorize(F.describing_function,otypes=[complex])(A)
134128
exceptNotImplementedError:
135129
# Drop through and do the numerical computation
136130
pass
@@ -170,17 +164,20 @@ def describing_function(
170164
# See if this is a static nonlinearity (assume not, just in case)
171165
ifnothasattr(F,'_isstatic')ornotF._isstatic():
172166
# Initialize any internal state by going through an initial cycle
173-
[F(x)forxinnp.atleast_1d(A).min()*sin_theta]
167+
forxinnp.atleast_1d(A).min()*sin_theta:
168+
F(x)# ignore the result
174169

175170
# Go through all of the amplitudes we were given
176-
df= []
177-
forainnp.atleast_1d(A):
171+
retdf=np.empty(np.shape(A),dtype=complex)
172+
df=retdf# Access to the return array
173+
df.shape= (-1, )# as a 1D array
174+
fori,ainenumerate(np.atleast_1d(A)):
178175
# Make sure we got a valid argument
179176
ifa==0:
180177
# Check to make sure the function has zero output with zero input
181178
ifzero_checkandnp.squeeze(F(0.))!=0:
182179
raiseValueError("function must evaluate to zero at zero")
183-
df.append(1.)
180+
df[i]=1.
184181
continue
185182
elifa<0:
186183
raiseValueError("cannot evaluate describing function for A < 0")
@@ -195,10 +192,10 @@ def describing_function(
195192
df_real= (F_eval @sin_theta)*scale# = M_1 \cos\phi / a
196193
df_imag= (F_eval @cos_theta)*scale# = M_1 \sin\phi / a
197194

198-
df.append(df_real+1j*df_imag)
195+
df[i]=df_real+1j*df_imag
199196

200197
# Return the values in the same shape as they were requested
201-
returnnp.array(df).reshape(np.shape(A))
198+
returnretdf
202199

203200

204201
defdescribing_function_plot(
@@ -437,16 +434,16 @@ def describing_function(self, A):
437434
returndf_real+1j*df_imag
438435

439436

440-
#Backlash nonlinearity (#48 in Gelb and Vander Velde, 1968)
441-
classbacklash_nonlinearity(DescribingFunctionNonlinearity):
437+
#Friction-dominated backlash nonlinearity (#48 in Gelb and Vander Velde, 1968)
438+
classfriction_backlash_nonlinearity(DescribingFunctionNonlinearity):
442439
"""Backlash nonlinearity for use in describing function analysis
443440
444-
This class creates a nonlinear function representing abacklash
445-
nonlinearity ,including the describing function for the nonlinearity. The
446-
following call creates a nonlinear function suitable for describing
447-
function analysis:
441+
This class creates a nonlinear function representing afriction-dominated
442+
backlashnonlinearity ,including the describing function for the
443+
nonlinearity. Thefollowing call creates a nonlinear function suitable
444+
for describingfunction analysis:
448445
449-
F =backlash_nonlinearity(b)
446+
F =friction_backlash_nonlinearity(b)
450447
451448
This function maintains an internal state representing the 'center' of a
452449
mechanism with backlash. If the new input is within `b/2` of the current
@@ -457,7 +454,7 @@ class backlash_nonlinearity(DescribingFunctionNonlinearity):
457454

458455
def__init__(self,b):
459456
# Create the describing function nonlinearity object
460-
super(backlash_nonlinearity,self).__init__()
457+
super(friction_backlash_nonlinearity,self).__init__()
461458

462459
self.b=b# backlash distance
463460
self.center=0# current center position

‎control/tests/descfcn_test.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
importnumpyasnp
1313
importcontrolasct
1414
importmath
15-
fromcontrol.descfcnimportsaturation_nonlinearity,backlash_nonlinearity,\
16-
relay_hysteresis_nonlinearity
15+
fromcontrol.descfcnimportsaturation_nonlinearity, \
16+
friction_backlash_nonlinearity,relay_hysteresis_nonlinearity
1717

1818

1919
# Static function via a class
@@ -84,15 +84,15 @@ def test_saturation_describing_function(satsys):
8484
df_anal= [satfcn.describing_function(a)forainamprange]
8585

8686
# Compute describing function for a static function
87-
df_fcn=[ct.describing_function(saturation,a)forainamprange]
87+
df_fcn=ct.describing_function(saturation,amprange)
8888
np.testing.assert_almost_equal(df_fcn,df_anal,decimal=3)
8989

9090
# Compute describing function for a describing function nonlinearity
91-
df_fcn=[ct.describing_function(satfcn,a)forainamprange]
91+
df_fcn=ct.describing_function(satfcn,amprange)
9292
np.testing.assert_almost_equal(df_fcn,df_anal,decimal=3)
9393

9494
# Compute describing function for a static I/O system
95-
df_sys=[ct.describing_function(satsys,a)forainamprange]
95+
df_sys=ct.describing_function(satsys,amprange)
9696
np.testing.assert_almost_equal(df_sys,df_anal,decimal=3)
9797

9898
# Compute describing function on an array of values
@@ -109,13 +109,13 @@ class my_saturation(ct.DescribingFunctionNonlinearity):
109109
def__call__(self,x):
110110
returnsaturation(x)
111111
satfcn_nometh=my_saturation()
112-
df_nometh=[ct.describing_function(satfcn_nometh,a)forainamprange]
112+
df_nometh=ct.describing_function(satfcn_nometh,amprange)
113113
np.testing.assert_almost_equal(df_nometh,df_anal,decimal=3)
114114

115115

116116
@pytest.mark.parametrize("fcn, amin, amax", [
117117
[saturation_nonlinearity(1),0,10],
118-
[backlash_nonlinearity(2),1,10],
118+
[friction_backlash_nonlinearity(2),1,10],
119119
[relay_hysteresis_nonlinearity(1,1),3,10],
120120
])
121121
deftest_describing_function(fcn,amin,amax):
@@ -161,7 +161,7 @@ def test_describing_function_plot():
161161
# Multiple intersections
162162
H_multiple=H_simple*ct.tf(*ct.pade(5,4))*4
163163
omega=np.logspace(-1,3,50)
164-
F_backlash=ct.descfcn.backlash_nonlinearity(1)
164+
F_backlash=ct.descfcn.friction_backlash_nonlinearity(1)
165165
amp=np.linspace(0.6,5,50)
166166
xsects=ct.describing_function_plot(H_multiple,F_backlash,amp,omega)
167167
fora,winxsects:

‎examples/describing_functions.ipynb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
"metadata": {},
9898
"source": [
9999
"### Backlash nonlinearity\n",
100-
"A backlash nonlinearity can be obtained using the `ct.backlash_nonlinearity` function. This function takes as is argument the size of the backlash region."
100+
"Afriction-dominatedbacklash nonlinearity can be obtained using the `ct.friction_backlash_nonlinearity` function. This function takes as is argument the size of the backlash region."
101101
]
102102
},
103103
{
@@ -119,13 +119,13 @@
119119
}
120120
],
121121
"source": [
122-
"backlash = ct.backlash_nonlinearity(0.5)\n",
122+
"backlash = ct.friction_backlash_nonlinearity(0.5)\n",
123123
"theta = np.linspace(0, 2*np.pi, 50)\n",
124124
"x = np.sin(theta)\n",
125125
"plt.plot(x, [backlash(z) for z in x])\n",
126126
"plt.xlabel(\"Input, x\")\n",
127127
"plt.ylabel(\"Output, y = backlash(x)\")\n",
128-
"plt.title(\"Input/output map for a backlash nonlinearity\");"
128+
"plt.title(\"Input/output map for afriction-dominatedbacklash nonlinearity\");"
129129
]
130130
},
131131
{
@@ -365,7 +365,7 @@
365365
"omega = np.logspace(-3, 3, 500)\n",
366366
"\n",
367367
"# Nonlinearity\n",
368-
"F_backlash = ct.backlash_nonlinearity(1)\n",
368+
"F_backlash = ct.friction_backlash_nonlinearity(1)\n",
369369
"amp = np.linspace(0.6, 5, 50)\n",
370370
"\n",
371371
"# Describing function plot\n",

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp