ObjectConnectorSpringDamper

An simple spring-damper element with additional force; connects to position-based markers.

Additional information for ObjectConnectorSpringDamper:

  • This Object has/provides the following types = Connector
  • Requested Marker type = Position
  • Short name for Python = SpringDamper
  • Short name for Python visualization object = VSpringDamper

The item ObjectConnectorSpringDamper with type = ‘ConnectorSpringDamper’ has the following parameters:

  • name [type = String, default = ‘’]:
    connector’s unique name
  • markerNumbers [\([m0,m1]\tp\), type = ArrayMarkerIndex, default = [ invalid [-1], invalid [-1] ]]:
    list of markers used in connector
  • referenceLength [\(L_0\), type = UReal, default = 0.]:
    reference length [SI:m] of spring
  • stiffness [\(k\), type = UReal, default = 0.]:
    stiffness [SI:N/m] of spring; force acts against (length-initialLength)
  • damping [\(d\), type = UReal, default = 0.]:
    damping [SI:N/(m s)] of damper; force acts against d/dt(length)
  • force [\(f_{a}\), type = Real, default = 0.]:
    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 [\(\dot L_0\), type = Real, default = 0.]:
    velocity offset [SI:m/s] of damper, being equivalent to time change of reference length
  • activeConnector [type = Bool, default = True]:
    flag, which determines, if the connector is active; used to deactivate (temporarily) a connector or constraint
  • springForceUserFunction [\(\mathrm{UF} \in \Rcal\), type = PyFunctionMbsScalarIndexScalar5, default = 0]:
    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 [type = VObjectConnectorSpringDamper]:
    parameters for visualization of item

The item VObjectConnectorSpringDamper has the following parameters:

  • show [type = Bool, default = True]:
    set true, if item is shown in visualization and false if it is not shown
  • drawSize [type = float, default = -1.]:
    drawing size = diameter of spring; size == -1.f means that default connector size is used
  • color [type = Float4, default = [-1.,-1.,-1.,-1.]]:
    RGBA connector color; if R==-1, use default color

DESCRIPTION of ObjectConnectorSpringDamper

The following output variables are available as OutputVariableType in sensors, Get…Output() and other functions:

  • Distance:
    distance between both points
  • Displacement:
    relative displacement between both points
  • Velocity:
    relative velocity between both points
  • Force: \({\mathbf{f}}\)
    3D spring-damper force vector
  • ForceLocal: \(f_{SD}\)
    scalar spring-damper force

Definition of quantities

intermediate variables
symbol
description
marker m0 position
\(\LU{0}{{\mathbf{p}}}_{m0}\)
current global position which is provided by marker m0
marker m1 position
\(\LU{0}{{\mathbf{p}}}_{m1}\)

marker m0 velocity
\(\LU{0}{{\mathbf{v}}}_{m0}\)
current global velocity which is provided by marker m0
marker m1 velocity
\(\LU{0}{{\mathbf{v}}}_{m1}\)

time derivative of distance
\(\dot L\)
\(\Delta\! \LU{0}{{\mathbf{v}}}\tp {\mathbf{v}}_{f}\)
output variables
symbol
formula
Displacement
\(\Delta\! \LU{0}{{\mathbf{p}}}\)
\(\LU{0}{{\mathbf{p}}}_{m1} - \LU{0}{{\mathbf{p}}}_{m0}\)
Velocity
\(\Delta\! \LU{0}{{\mathbf{v}}}\)
\(\LU{0}{{\mathbf{v}}}_{m1} - \LU{0}{{\mathbf{v}}}_{m0}\)
Distance
\(L\)
\(|\Delta\! \LU{0}{{\mathbf{p}}}|\)
Force
\({\mathbf{f}}\)
see below

Connector forces

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

\[{\mathbf{v}}_{f} = \frac{1}{L} \Delta\! \LU{0}{{\mathbf{p}}}\]

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, \({\mathbf{f}}\) 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

\[{\mathbf{f}} = f_{SD}{\mathbf{v}}_{f}\]

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

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

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

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

The generalized (elastic) forces thus result from

\[{\mathbf{Q}}_{SD} = \frac{\partial \LU{0}{{\mathbf{p}}}}{\partial {\mathbf{q}}_{SD}\tp} {\mathbf{f}} ,\]

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

\[{\mathbf{Q}}_{SD, m0} = -\left( k\cdot(L-L_0) + d \cdot (\dot L - \dot L_0) + f_{a} \right) {\mathbf{J}}_{pos,m0}\tp {\mathbf{v}}_{f} , \quad {\mathbf{Q}}_{SD, m1} = \left( k\cdot(L-L_0) + d \cdot (\dot L - \dot L_0)+ f_{a} \right) {\mathbf{J}}_{pos,m1}\tp {\mathbf{v}}_{f} ,\]

where \({\mathbf{J}}_{pos,m1}\) represents the derivative of marker \(m1\) w.r.t.its associated coordinates \({\mathbf{q}}_{m1}\), analogously \({\mathbf{J}}_{pos,m0}\).

Connector Jacobian

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

\[{\mathbf{J}}_{SD} = \mp{\frac{\partial {\mathbf{Q}}_{SD, m0}}{\partial {\mathbf{q}}_{m0}} }{\frac{\partial {\mathbf{Q}}_{SD, m0}}{\partial {\mathbf{q}}_{m1}}} {\frac{\partial {\mathbf{Q}}_{SD, m0}}{\partial {\mathbf{q}}_{m1}} }{\frac{\partial {\mathbf{Q}}_{SD, m1}}{\partial {\mathbf{q}}_{m1}}}\]

and the velocity level jacobian reads

\[{\mathbf{J}}_{SD,t} = \mp{\frac{\partial {\mathbf{Q}}_{SD, m0}}{\partial \dot {\mathbf{q}}_{m0}} }{\frac{\partial {\mathbf{Q}}_{SD, m0}}{\partial \dot {\mathbf{q}}_{m1}}} {\frac{\partial {\mathbf{Q}}_{SD, m0}}{\partial \dot {\mathbf{q}}_{m1}} }{\frac{\partial {\mathbf{Q}}_{SD, m1}}{\partial \dot {\mathbf{q}}_{m1}}}\]

The sub-Jacobians follow from

\[\frac{\partial {\mathbf{Q}}_{SD, m0}}{\partial {\mathbf{q}}_{m0}} = -\frac{\partial {\mathbf{J}}_{pos,m0}\tp }{\partial {\mathbf{q}}_{m0}} {\mathbf{v}}_{f} \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) -{\mathbf{J}}_{pos,m0}\tp \frac{\partial {\mathbf{v}}_{f} \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) }{\partial {\mathbf{q}}_{m0}}\]

in which the term \(\frac{\partial {\mathbf{J}}_{pos,m0}\tp }{\partial {\mathbf{q}}_{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 \({\mathbf{f}}\); 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}\frac{\partial {\mathbf{Q}}_{SD, m0}}{\partial {\mathbf{q}}_{m0}} &=& -{\mathbf{J}}_{pos,m0}\tp \frac{\partial {\mathbf{v}}_{f} \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) }{\partial {\mathbf{q}}_{m0}} \nonumber \\ &=& -{\mathbf{J}}_{pos,m0}\tp \frac{\partial \left( k\cdot \left( \Delta\! \LU{0}{{\mathbf{p}}} - L_0 {\mathbf{v}}_{f} \right)+ {\mathbf{v}}_{f} \left(d \cdot {\mathbf{v}}_{f}\tp \Delta\! \LU{0}{{\mathbf{v}}} + f_{a} \right) \right) }{\partial {\mathbf{q}}_{m0}} \nonumber \\ &\approx& {\mathbf{J}}_{pos,m0}\tp \left(k\cdot {\mathbf{I}} - k \frac{L_0}{L}\left({\mathbf{I}} - \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} \right) +\frac{1}{L}\left({\mathbf{I}} - \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} \right) \left(d \cdot {\mathbf{v}}_{f}\tp \Delta\! \LU{0}{{\mathbf{v}}} + f_{a} \right) \right. \nonumber \\ &&\left. + d \LU{0}{{\mathbf{v}}_{f}} \otimes \left(\frac{1}{L}\left({\mathbf{I}} - \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} \right) \LU{0}{{\mathbf{v}}_{f}} \right) \right) \LU{0}{{\mathbf{J}}_{pos,m0}}\end{split}\]

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

\[\begin{split}\frac{\partial {\mathbf{Q}}_{SD, m0}}{\partial {\mathbf{q}}_{m0}} &=& -{\mathbf{J}}_{pos,m0}\tp \frac{\partial {\mathbf{v}}_{f} \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) }{\partial {\mathbf{q}}_{m0}} \nonumber \\ &=& {\mathbf{J}}_{pos,m0}\tp \frac{1}{L}\left({\mathbf{I}} - \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} \right) \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) {\mathbf{J}}_{pos,m0} \nonumber \\ && +{\mathbf{J}}_{pos,m0}\tp \LU{0}{{\mathbf{v}}_{f}} \otimes \left( k\cdot \LU{0}{{\mathbf{v}}_{f}} + d \cdot\Delta\! \LU{0}{{\mathbf{v}}} \frac{1}{L}\left({\mathbf{I}} - \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} \right) \right) {\mathbf{J}}_{pos,m0} - d {\mathbf{J}}_{pos,m0}\tp \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} \frac{\partial \Delta\! \LU{0}{{\mathbf{v}}}}{\partial {\mathbf{q}}_{m0}} \nonumber \\ &=& {\mathbf{J}}_{pos,m0}\tp \left(\frac{f_{SD}}{L}\left({\mathbf{I}} - \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} \right) + k \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} + \frac{d}{L} \left(\LU{0}{{\mathbf{v}}_{f}} \otimes \Delta\! \LU{0}{{\mathbf{v}}}\right) \cdot \left({\mathbf{I}} - \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} \right) + ...! \right) {\mathbf{J}}_{pos,m0}\end{split}\]

Noting that \(\frac{\partial {\mathbf{v}}_{f} }{\partial {\mathbf{q}}_{m0}} = -\frac{1}{L}\left({\mathbf{I}} - \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} \right) \LU{0}{{\mathbf{J}}_{pos,m0}}\) and \(\frac{\partial {\mathbf{v}}_{f} }{\partial {\mathbf{q}}_{m1}} = \frac{1}{L}\left({\mathbf{I}} - \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{f}} \right) \LU{0}{{\mathbf{J}}_{pos,m1}}\). The Jacobian w.r.t.velocity coordinates follows as

\[\begin{split}\frac{\partial {\mathbf{Q}}_{SD, m0}}{\partial \dot {\mathbf{q}}_{m0}} &=& -{\mathbf{J}}_{pos,m0}\tp \frac{\partial {\mathbf{v}}_{f} \left( k\cdot(L-L_0) + d \cdot(\dot L - \dot L_0) + f_{a} \right) }{\partial \dot {\mathbf{q}}_{m0}} \nonumber \\ &=& {\mathbf{J}}_{pos,m0}\tp \left(d {\mathbf{v}}_{f} \otimes {\mathbf{v}}_{f} \right) \LU{0}{{\mathbf{J}}_{pos,m0}}\end{split}\]

Note that in case that \(L=0\), the term \(\frac{1}{L} \left({\mathbf{I}} - \LU{0}{{\mathbf{v}}_{f}} \otimes \LU{0}{{\mathbf{v}}_{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}{{\mathbf{v}}}}{\partial {\mathbf{q}}_{m0}}\), which is important for large damping, yields

\[\frac{\partial \Delta\! \LU{0}{{\mathbf{v}}}}{\partial {\mathbf{q}}_{m0}} = \frac{\partial {\mathbf{J}}_{pos,m0} \dot {\mathbf{q}}_{m0}}{\partial {\mathbf{q}}_{m0}}= \frac{\partial {\mathbf{J}}_{pos,m0} }{\partial {\mathbf{q}}_{m0}} \dot {\mathbf{q}}_{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
returnValue
Real
scalar value of computed spring force

User function 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 for ObjectConnectorSpringDamper

 1node = mbs.AddNode(NodePoint(referenceCoordinates = [1.05,0,0]))
 2oMassPoint = mbs.AddObject(MassPoint(nodeNumber = node, physicsMass=1))
 3
 4m0 = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oGround, localPosition=[0,0,0]))
 5m1 = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oMassPoint, localPosition=[0,0,0]))
 6
 7mbs.AddObject(ObjectConnectorSpringDamper(markerNumbers=[m0,m1],
 8                                          referenceLength = 1, #shorter than initial distance
 9                                          stiffness = 100,
10                                          damping = 1))
11
12#assemble and solve system for default parameters
13mbs.Assemble()
14mbs.SolveDynamic()
15
16#check result at default integration time
17exudynTestGlobals.testResult = mbs.GetNodeOutput(node, exu.OutputVariableType.Position)[0]

Relevant Examples and TestModels with weblink:

The web version may not be complete. For details, consider also the Exudyn PDF documentation : theDoc.pdf