ObjectConnectorSpringDamper

An simple spring-damper element with additional force, connecting to position-based markers.

../../../_images/ObjectConnectorSpringDamper.png

Simpler: mbs.CreateSpringDamper adds this item, with what it needs, in one call.

Interface

Parameters

The parameters of the item; in a dictionary, its type is ‘ConnectorSpringDamper’:

name

type

size

default

description

name

String

‘’

connector’s unique name

markerNumbers

ArrayMarkerIndex

[ invalid (-1), invalid (-1) ]

(symbol: \([m0,m1]\tp\)) list of markers used in connector

referenceLength

UReal

0.

(symbol: \(L_0\)) reference length [SI:m] of spring

stiffness

UReal

0.

(symbol: \(k\)) stiffness [SI:N/m] of spring; force acts against (length-initialLength)

damping

UReal

0.

(symbol: \(d\)) damping [SI:N/(m s)] of damper; force acts against d/dt(length)

force

Real

0.

(symbol: \(f_{a}\)) added constant force [SI:N] of spring; scalar force; f=1 is equivalent to reducing initialLength by 1/stiffness; f > 0: tension; f < 0: compression; can be used to model actuator force

velocityOffset

Real

0.

(symbol: \(\dot L_0\)) velocity offset [SI:m/s] of damper, being equivalent to time change of reference length

activeConnector

Bool

True

flag, which determines, if the connector is active; used to deactivate (temporarily) a connector or constraint

springForceUserFunction

ObjectConnectorSpringDamperSpringForceUserFunction

0

(symbol: \(\mathrm{UF} \in \Rcal\)) A Python function which defines the spring force with parameters; the Python function will only be evaluated, if activeConnector is true, otherwise the SpringDamper is inactive; see description below

visualization

VObjectConnectorSpringDamper

parameters for visualization of item

Visualization parameters

The parameters of VObjectConnectorSpringDamper, given as visualization:

name

type

size

default

description

show

Bool

True

set true, if item is shown in visualization and false if it is not shown

drawSize

float

-1.

drawing size = diameter of spring; size == -1.f means that default connector size is used

color

Float4

4

[-1.,-1.,-1.,-1.]

RGBA connector color; if R==-1, use default color

Drawing

Drawn as all connectors; a spring of diameter drawSize between the markers: connectors.springNumberOfWindings windings of connectors.curveTiling segments, lines with connectors.drawSimplified, otherwise a tube.

Settings beyond those of all connectors: connectors.curveTiling, connectors.drawSimplified, connectors.springNumberOfWindings, general.cylinderTiling.

Output variables

Available as OutputVariableType in sensors, Get...Output() and other functions:

output variable

symbol

description

Distance

distance between both points

Displacement

relative displacement between both points

Velocity

relative velocity between both points

Force

\(\fv\)

3D spring-damper force vector

ForceLocal

\(f_{SD}\)

scalar spring-damper force

PotentialEnergy

\(V = \frac{1}{2} k\, (L - L_0)^2 + f_c\, (L - L_0)\)

elastic energy of the spring and the potential of the constant force; zero if the connector is not active; raises for a springForceUserFunction

Detailed description

Definition of quantities

intermediate variables

symbol

description

marker m0 position

\(\LU{0}{\pv}_{m0}\)

current global position which is provided by marker m0

marker m1 position

\(\LU{0}{\pv}_{m1}\)

marker m0 velocity

\(\LU{0}{\vv}_{m0}\)

current global velocity which is provided by marker m0

marker m1 velocity

\(\LU{0}{\vv}_{m1}\)

time derivative of distance

\(\dot L\)

\(\Delta\! \LU{0}{\vv}\tp \vv_{f}\)

output variables

symbol

formula

Displacement

\(\Delta\! \LU{0}{\pv}\)

\(\LU{0}{\pv}_{m1} - \LU{0}{\pv}_{m0}\)

Velocity

\(\Delta\! \LU{0}{\vv}\)

\(\LU{0}{\vv}_{m1} - \LU{0}{\vv}_{m0}\)

Distance

\(L\)

\(\vert\Delta\! \LU{0}{\pv}\vert\)

Force

\(\fv\)

see below

Connector forces

The unit vector in force direction reads (raises SysError if \(L=0\)),

\[ \vv_{f} = \frac{1}{L} \Delta\! \LU{0}{\pv} \]

If activeConnector = True, the scalar spring force is computed as

\[ f_{SD} = k\cdot(L-L_0) + d \cdot(\dot L -\dot L_0)+ f_{a} \]

If the springForceUserFunction \(\mathrm{UF}\) is defined, \(\fv\) instead becomes (\(t\) is current time)

\[ f_{SD} = \mathrm{UF}(mbs, t, i_N, L-L_0, \dot L - \dot L_0, k, d, f_{a}) \]

and iN represents the itemNumber (=objectNumber). Note that, if activeConnector = False, \(f_{SD}\) is set to zero.

The vector of the spring-damper force applied at both markers finally reads

\[ \fv = f_{SD}\vv_{f} \]

The virtual work of the connector force is computed from the virtual displacement

\[ \delta \Delta\! \LU{0}{\pv} = \delta \LU{0}{\pv}_{m1} - \delta \LU{0}{\pv}_{m0} \, , \]

and the virtual work (note the transposed version here, because the resulting generalized forces shall be a column vector),

\[ \delta W_{SD} = \fv \delta \Delta\! \LU{0}{\pv} = \left( k\cdot(L-L_0) + d \cdot (\dot L - \dot L_0) + f_{a} \right) \left(\delta \LU{0}{\pv}_{m1} - \delta \LU{0}{\pv}_{m0} \right)\tp \vv_{f} \, . \]

The generalized (elastic) forces thus result from

\[ \Qm_{SD} = \frac{\partial \LU{0}{\pv}}{\partial \qv_{SD}\tp} \fv \, , \]

and read for the markers \(m0\) and \(m1\),

\[ \Qm_{SD, m0} = -\left( k\cdot(L-L_0) + d \cdot (\dot L - \dot L_0) + f_{a} \right) \Jm_{pos,m0}\tp \vv_{f} , \quad \Qm_{SD, m1} = \left( k\cdot(L-L_0) + d \cdot (\dot L - \dot L_0)+ f_{a} \right) \Jm_{pos,m1}\tp \vv_{f} \, , \]

where \(\Jm_{pos,m1}\) represents the derivative of marker \(m1\) w.r.t. its associated coordinates \(\qv_{m1}\), analogously \(\Jm_{pos,m0}\).

Connector Jacobian

The position-level jacobian for the connector, involving all coordinates associated with markers \(m0\) and \(m1\), follows from

\[ \Jm_{SD} = \mp{\frac{\partial \Qm_{SD, m0}}{\partial \qv_{m0}} }{\frac{\partial \Qm_{SD, m0}}{\partial \qv_{m1}}} {\frac{\partial \Qm_{SD, m0}}{\partial \qv_{m1}} }{\frac{\partial \Qm_{SD, m1}}{\partial \qv_{m1}}} \]

and the velocity level jacobian reads

\[ \Jm_{SD,t} = \mp{\frac{\partial \Qm_{SD, m0}}{\partial \dot \qv_{m0}} }{\frac{\partial \Qm_{SD, m0}}{\partial \dot \qv_{m1}}} {\frac{\partial \Qm_{SD, m0}}{\partial \dot \qv_{m1}} }{\frac{\partial \Qm_{SD, m1}}{\partial \dot \qv_{m1}}} \]

The sub-Jacobians follow from

\[ \frac{\partial \Qm_{SD, m0}}{\partial \qv_{m0}} = -\frac{\partial \Jm_{pos,m0}\tp }{\partial \qv_{m0}} \vv_{f} \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) -\Jm_{pos,m0}\tp \frac{\partial \vv_{f} \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) }{\partial \qv_{m0}} \]

in which the term \(\frac{\partial \Jm_{pos,m0}\tp }{\partial \qv_{m0}}\) is computed from a special function provided by markers, that compute the derivative of the marker jacobian times a constant vector, in this case the spring force \(\fv\); this jacobian term is usually less dominant, but is included in the numerical as well as the analytical derivatives, see the general jacobian computation information.

The other term, which is the dominant term, is computed as (dependence of velocity term on position coordinates and \(\dot L_0\) term neglected),

\[\begin{split} \begin{aligned} \frac{\partial \Qm_{SD, m0}}{\partial \qv_{m0}} &= -\Jm_{pos,m0}\tp \frac{\partial \vv_{f} \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) }{\partial \qv_{m0}} \\ &= -\Jm_{pos,m0}\tp \frac{\partial \left( k\cdot \left( \Delta\! \LU{0}{\pv} - L_0 \vv_{f} \right)+ \vv_{f} \left(d \cdot \vv_{f}\tp \Delta\! \LU{0}{\vv} + f_{a} \right) \right) }{\partial \qv_{m0}} \\ &\approx& \Jm_{pos,m0}\tp \left(k\cdot \Im - k \frac{L_0}{L}\left(\Im - \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \right) +\frac{1}{L}\left(\Im - \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \right) \left(d \cdot \vv_{f}\tp \Delta\! \LU{0}{\vv} + f_{a} \right) \right. \\ &&\left. + d \LU{0}{\vv_{f}} \otimes \left(\frac{1}{L}\left(\Im - \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \right) \LU{0}{\vv_{f}} \right) \right) \LU{0}{\Jm_{pos,m0}} \end{aligned} \end{split}\]

Alternatively (again \(\dot L_0\) term neglected):

\[\begin{split} \begin{aligned} \frac{\partial \Qm_{SD, m0}}{\partial \qv_{m0}} &= -\Jm_{pos,m0}\tp \frac{\partial \vv_{f} \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) }{\partial \qv_{m0}} \\ &= \Jm_{pos,m0}\tp \frac{1}{L}\left(\Im - \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \right) \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) \Jm_{pos,m0} \\ && +\Jm_{pos,m0}\tp \LU{0}{\vv_{f}} \otimes \left( k\cdot \LU{0}{\vv_{f}} + d \cdot\Delta\! \LU{0}{\vv} \frac{1}{L}\left(\Im - \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \right) \right) \Jm_{pos,m0} - d \Jm_{pos,m0}\tp \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \frac{\partial \Delta\! \LU{0}{\vv}}{\partial \qv_{m0}} \\ &= \Jm_{pos,m0}\tp \left(\frac{f_{SD}}{L}\left(\Im - \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \right) + k \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} + \frac{d}{L} \left(\LU{0}{\vv_{f}} \otimes \Delta\! \LU{0}{\vv}\right) \cdot \left(\Im - \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \right) + ...! \right) \Jm_{pos,m0} \end{aligned} \end{split}\]

Noting that \(\frac{\partial \vv_{f} }{\partial \qv_{m0}} = -\frac{1}{L}\left(\Im - \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \right) \LU{0}{\Jm_{pos,m0}}\) and \(\frac{\partial \vv_{f} }{\partial \qv_{m1}} = \frac{1}{L}\left(\Im - \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \right) \LU{0}{\Jm_{pos,m1}}\).

The Jacobian w.r.t. velocity coordinates follows as

\[\begin{split} \begin{aligned} \frac{\partial \Qm_{SD, m0}}{\partial \dot \qv_{m0}} &= -\Jm_{pos,m0}\tp \frac{\partial \vv_{f} \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) }{\partial \dot \qv_{m0}} \\ &= \Jm_{pos,m0}\tp \left(d \vv_{f} \otimes \vv_{f} \right) \LU{0}{\Jm_{pos,m0}} \end{aligned} \end{split}\]

Note that in case that \(L=0\), the term \(\frac{1}{L} \left(\Im - \LU{0}{\vv_{f}} \otimes \LU{0}{\vv_{f}} \right)\) is replaced by the unit matrix, in order to avoid zero (singular) jacobian; this is a workaround and should only occur in exceptional cases.

The term \(\frac{\partial \Delta\! \LU{0}{\vv}}{\partial \qv_{m0}}\), which is important for large damping, yields

\[ \frac{\partial \Delta\! \LU{0}{\vv}}{\partial \qv_{m0}} = \frac{\partial \Jm_{pos,m0} \dot \qv_{m0}}{\partial \qv_{m0}}= \frac{\partial \Jm_{pos,m0} }{\partial \qv_{m0}} \dot \qv_{m0} \]

The latter term is currently neglected.

Jacobians for markers \(m1\) and mixed \(m0\)/\(m1\) terms follow analogously.

Userfunction: springForceUserFunction(mbs, t, itemNumber, deltaL, deltaL_t, stiffness, damping, force) A user function, which computes the spring force depending on time, object variables (deltaL, deltaL_t) and object parameters (stiffness, damping, force). The object variables are provided to the function using the current values of the SpringDamper object. Note that itemNumber represents the index of the object in mbs, which can be used to retrieve additional data from the object through mbs.GetObjectParameter(itemNumber, ...), see the according description of GetObjectParameter.

arguments / return

type or size

description

mbs

MainSystem

provides MainSystem mbs to which object belongs

t

Real

current time in mbs

itemNumber

Index

integer number \(i_N\) of the object in mbs, allowing easy access to all object data via mbs.GetObjectParameter(itemNumber, …)

deltaL

Real

\(L-L_0\), spring elongation

deltaL_t

Real

\((\dot L - \dot L_0)\), spring velocity, including offset

stiffness

Real

copied from object

damping

Real

copied from object

force

Real

copied from object; constant force

return value

Real

scalar value of computed spring force

Example:

#define nonlinear force
def UFforce(mbs, t, itemNumber, u, v, k, d, F0):
    return k*u + d*v + F0
#markerNumbers taken from mini example
mbs.AddObject(ObjectConnectorSpringDamper(markerNumbers=[m0,m1],
                                          referenceLength = 1,
                                          stiffness = 100, damping = 1,
                                          springForceUserFunction = UFforce))

Mini example

node = mbs.AddNode(NodePoint(referenceCoordinates = [1.05,0,0]))
oMassPoint = mbs.AddObject(MassPoint(nodeNumber = node, mass=1))

m0 = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oGround, localPosition=[0,0,0]))
m1 = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oMassPoint, localPosition=[0,0,0]))

mbs.AddObject(ObjectConnectorSpringDamper(markerNumbers=[m0,m1],
                                          referenceLength = 1, #shorter than initial distance
                                          stiffness = 100,
                                          damping = 1))

#assemble and solve system for default parameters
mbs.Assemble()
mbs.SolveDynamic()

#check result at default integration time
exu.sys['testResult'] = mbs.GetNodeOutput(node, exu.OutputVariableType.Position)[0]

Examples (Ex) and TestModels (TM) that show this item, with weblink to github: basicTutorial2024.py (Ex), tutorialSpringDamperCreate.py (Ex), SpringDamperMassUserFunction.py (Ex), loadUserFunctionTest.py (TM)