11
22"""
33 force = Bushing(; obj1, obj2,
4- nominalForce = Modia3D.ZeroVector3D,
5- stiffness = Modia3D.ZeroVector3D,
6- damping = Modia3D.ZeroVector3D )
4+ nominalForce = Modia3D.ZeroVector3D,
5+ springForceLaw = Modia3D.ZeroVector3D,
6+ damperForceLaw = Modia3D.ZeroVector3D,
7+ nominalTorque = Modia3D.ZeroVector3D,
8+ rotSpringForceLaw = Modia3D.ZeroVector3D,
9+ rotDamperForceLaw = Modia3D.ZeroVector3D,
10+ largeAngles = false )
711
812Return a `force` acting as bushing between `obj1::`[`Object3D`](@ref) and
9- `obj2::`[`Object3D`](@ref). Vectors `stiffness`, `damping` and
10- `nominalForce` define the stiffness, damping and nominal force values in
11- x, y and z direction of `obj1`. The orientation of `obj2` does not
12- influence the resulting forces.
13+ `obj2::`[`Object3D`](@ref). The force directions are defined by `obj1`,
14+ i.e. the orientation of `obj2` does not influence the resulting forces.
15+
16+ # Arguments
17+
18+ - `nominalForce` defines the nominal force vector, i.e. the force that
19+ acts when spring and damper forces are zero. Positive values act in
20+ positive axis directions at `obj1` and in opposite directions at `obj2`.
21+ - `springForceLaw` defines the force law of the spring in x-, y- and
22+ z-direction:
23+ - A `Float64` value represents a linear stiffness coefficient.
24+ - An univariate `Function` is used to compute the spring force
25+ dependent of its deflection.
26+ - `damperForceLaw` defines the force law of the damper in x-, y- and
27+ z-direction:
28+ - A `Float64` value represents a linear damping coefficient.
29+ - An univariate `Function` is used to compute the damper force
30+ dependent of its deflection velocity.
31+ - `nominalTorque` defines nominal torques about alpha, beta and gamma
32+ directions.
33+ - `rotSpringForceLaw` defines the force law of the rotational spring
34+ about alpha-, beta- and gamma-direction:
35+ - A `Float64` value represents a linear damping coefficient.
36+ - An univariate `Function` is used to compute the spring force
37+ dependent of its deflection.
38+ - `rotDamperForceLaw` defines the force law of the rotational damper
39+ about alpha-, beta- and gamma-direction:
40+ - A `Float64` value represents a linear damping coefficient.
41+ - An univariate `Function` is used to compute the damper force
42+ dependent of its deflection velocity.
43+ - `largeAngles` can be used to enable large angle mode.
44+ - When disabled, small deformation angles (< 10°) are assumed. This
45+ option deals equally with rotations [alpha, beta gamma] about the
46+ axes [x, y, z] of `obj1`, but causes approximation errors for
47+ larger angles.
48+ - When enabled, the deformation angles and torque directions are
49+ calculated as [Cardan (Tait–Bryan) angles](https://en.wikipedia.org/wiki/Euler_angles#Chained_rotations_equivalence)
50+ (rotation sequence x-y-z from `obj1` to `obj2`). This option
51+ supports angles up to nearly 90°, but introduces local rotation
52+ directions [alpha, beta gamma] which differ from the axes [x, y, z]
53+ of `obj1` and increases computation effort.
1354"""
1455mutable struct Bushing <: Modia3D.AbstractForceElement
1556
1657 obj1:: Object3D
1758 obj2:: Object3D
1859
1960 nominalForce:: SVector{3,Float64}
20- stiffness:: SVector{3,Float64}
21- damping:: SVector{3,Float64}
61+ springForceFunction:: SVector{3,Function}
62+ damperForceFunction:: SVector{3,Function}
63+ nominalTorque:: SVector{3,Float64}
64+ rotSpringForceFunction:: SVector{3,Function}
65+ rotDamperForceFunction:: SVector{3,Function}
66+ largeAngles:: Bool
2267
2368 function Bushing (; obj1:: Object3D ,
2469 obj2:: Object3D ,
2570 nominalForce:: AbstractVector = Modia3D. ZeroVector3D,
26- stiffness:: AbstractVector = Modia3D. ZeroVector3D,
27- damping:: AbstractVector = Modia3D. ZeroVector3D)
71+ springForceLaw:: AbstractVector = Modia3D. ZeroVector3D,
72+ damperForceLaw:: AbstractVector = Modia3D. ZeroVector3D,
73+ nominalTorque:: AbstractVector = Modia3D. ZeroVector3D,
74+ rotSpringForceLaw:: AbstractVector = Modia3D. ZeroVector3D,
75+ rotDamperForceLaw:: AbstractVector = Modia3D. ZeroVector3D,
76+ largeAngles:: Bool = false )
77+ for dir in 1 : 3
78+ @assert (typeof (springForceLaw[dir]) == Float64 || isa (springForceLaw[dir], Function))
79+ @assert (typeof (damperForceLaw[dir]) == Float64 || isa (damperForceLaw[dir], Function))
80+ @assert (typeof (rotSpringForceLaw[dir]) == Float64 || isa (rotSpringForceLaw[dir], Function))
81+ @assert (typeof (rotDamperForceLaw[dir]) == Float64 || isa (rotDamperForceLaw[dir], Function))
82+ end
83+
84+ nomForce = Modia3D. convertAndStripUnit (SVector{3 ,Float64}, u " N" , nominalForce)
85+ nomTorque = Modia3D. convertAndStripUnit (SVector{3 ,Float64}, u " N*m" , nominalTorque)
86+ springForceFunction = Vector {Function} (undef, 3 )
87+ damperForceFunction = Vector {Function} (undef, 3 )
88+ rotSpringForceFunction = Vector {Function} (undef, 3 )
89+ rotDamperForceFunction = Vector {Function} (undef, 3 )
90+ irand = rand (Int)
91+ for dir in 1 : 3
92+ if (typeof (springForceLaw[dir]) == Float64)
93+ stiffness = Modia3D. convertAndStripUnit (Float64, u " N/m" , springForceLaw[dir])
94+ fsymb = Symbol (" fc" , dir, " _" , irand) # todo: replace irand by force.path
95+ springForceFunction[dir] = eval (:($ fsymb (pos) = $ stiffness * pos))
96+ else
97+ springForceFunction[dir] = springForceLaw[dir]
98+ end
99+ if (typeof (damperForceLaw[dir]) == Float64)
100+ damping = Modia3D. convertAndStripUnit (Float64, u " N*s/m" , damperForceLaw[dir])
101+ fsymb = Symbol (" fd" , dir, " _" , irand) # todo: replace irand by force.path
102+ damperForceFunction[dir] = eval (:($ fsymb (vel) = $ damping * vel))
103+ else
104+ damperForceFunction[dir] = damperForceLaw[dir]
105+ end
106+ if (typeof (rotSpringForceLaw[dir]) == Float64)
107+ stiffness = Modia3D. convertAndStripUnit (Float64, u " N*m/rad" , rotSpringForceLaw[dir])
108+ fsymb = Symbol (" mc" , dir, " _" , irand) # todo: replace irand by force.path
109+ rotSpringForceFunction[dir] = eval (:($ fsymb (ang) = $ stiffness * ang))
110+ else
111+ rotSpringForceFunction[dir] = rotSpringForceLaw[dir]
112+ end
113+ if (typeof (rotDamperForceLaw[dir]) == Float64)
114+ damping = Modia3D. convertAndStripUnit (Float64, u " N*m*s/rad" , rotDamperForceLaw[dir])
115+ fsymb = Symbol (" md" , dir, " _" , irand) # todo: replace irand by force.path
116+ rotDamperForceFunction[dir] = eval (:($ fsymb (angd) = $ damping * angd))
117+ else
118+ rotDamperForceFunction[dir] = rotDamperForceLaw[dir]
119+ end
120+ end
28121
29- nomForce = Modia3D . convertAndStripUnit (SVector{ 3 ,Float64}, u " N " , nominalForce )
30- stiff = Modia3D . convertAndStripUnit (SVector{ 3 ,Float64}, u " N/m " , stiffness)
31- damp = Modia3D . convertAndStripUnit (SVector{ 3 ,Float64}, u " N*s/m " , damping)
122+ return new (obj1, obj2, nomForce, springForceFunction, damperForceFunction, nomTorque, rotSpringForceFunction, rotDamperForceFunction, largeAngles )
123+ end
124+ end
32125
33- return new (obj1, obj2, nomForce, stiff, damp)
34126
127+ # Compute deformation angles from rotation matrix
128+ function anglesFromRotation (largeAngles:: Bool , R12:: SMatrix{3,3,Float64} , w12:: SVector{3,Float64} )
129+ if largeAngles
130+ sbe = clamp (R12[3 ,1 ], - 1.0 , 1.0 )
131+ cbe = sqrt (1.0 - sbe* sbe)
132+ if (cbe > 1e-12 )
133+ sal = - R12[3 ,2 ]/ cbe
134+ cal = R12[3 ,3 ]/ cbe
135+ al = atan (- R12[3 ,2 ], R12[3 ,3 ])
136+ be = asin (sbe)
137+ ga = atan (- R12[2 ,1 ], R12[1 ,1 ])
138+ ald = w12[1 ] + (sal* w12[2 ] - cal* w12[3 ])* sbe/ cbe
139+ bed = cal* w12[2 ] + sal* w12[3 ]
140+ gad = (- sal* w12[2 ] + cal* w12[3 ])/ cbe
141+ return (@SVector [al, be, ga], @SVector [ald, bed, gad], @SMatrix [sal sbe; cal cbe])
142+ else
143+ @error (" Gimbal lock of Bushing transformation." )
144+ return (@SVector [0.0 , 0.0 , 0.0 ], @SVector [0.0 , 0.0 , 0.0 ], @SMatrix [0.0 0.0 ; 0.0 0.0 ])
145+ end
146+ else
147+ al = R12[2 ,3 ]
148+ be = R12[3 ,1 ]
149+ ga = R12[1 ,2 ]
150+ ald = w12[1 ]
151+ bed = w12[2 ]
152+ gad = w12[3 ]
153+ if (max (abs (al), abs (be), abs (ga)) > 0.174 )
154+ @warn (" Bushing angle exceeds 10 deg." )
155+ end
156+ return (@SVector [al, be, ga], @SVector [ald, bed, gad], @SMatrix [0.0 0.0 ; 0.0 0.0 ])
157+ end
158+ end
159+
160+ # Compute torque vector from force law moments
161+ function torqueFromMoments (largeAngles:: Bool , moments:: SVector{3,Float64} , sico:: SMatrix{2,2,Float64,4} )
162+ if largeAngles
163+ tx = moments[1 ] + sico[1 ,2 ]* moments[3 ]
164+ ty = sico[2 ,1 ]* moments[2 ] - sico[1 ,1 ]* sico[2 ,2 ]* moments[3 ]
165+ tz = sico[1 ,1 ]* moments[2 ] + sico[2 ,1 ]* sico[2 ,2 ]* moments[3 ]
166+ return @SVector [tx, ty, tz]
167+ else
168+ return moments
35169 end
36170end
37171
@@ -43,12 +177,22 @@ function initializeForceElement(force::Bushing)
43177end
44178
45179function evaluateForceElement (force:: Bushing )
180+ R12 = measFrameRotation (force. obj2; frameOrig= force. obj1)
46181 r12 = measFramePosition (force. obj2; frameOrig= force. obj1, frameCoord= force. obj1)
182+ w12 = measFrameRotVelocity (force. obj2; frameOrig= force. obj1, frameCoord= force. obj1)
47183 v12 = measFrameTransVelocity (force. obj2; frameOrig= force. obj1, frameCoord= force. obj1, frameObsrv= force. obj1)
184+ (ang, angd, sico) = anglesFromRotation (force. largeAngles, R12, w12)
48185
49- f12 = force. stiffness .* r12 + force. damping .* v12 + force. nominalForce
186+ f12 = Vector {Float64} (undef, 3 )
187+ mom = Vector {Float64} (undef, 3 )
188+ for dir in 1 : 3
189+ f12[dir] = force. springForceFunction[dir](r12[dir]) + force. damperForceFunction[dir](v12[dir]) + force. nominalForce[dir]
190+ mom[dir] = force. rotSpringForceFunction[dir](ang[dir]) + force. rotDamperForceFunction[dir](angd[dir]) + force. nominalTorque[dir]
191+ end
192+ t12 = torqueFromMoments (force. largeAngles, SVector {3} (mom), sico)
50193
51- applyFrameForcePair! (force. obj2, force. obj1, f12; frameCoord= force. obj1)
194+ applyFrameForcePair! (force. obj2, force. obj1, SVector {3} (f12); frameCoord= force. obj1)
195+ applyFrameTorquePair! (force. obj2, force. obj1, t12; frameCoord= force. obj1)
52196 return nothing
53197end
54198
0 commit comments