Measures, expressions, splines, drivers¶
Measures¶
A measure is a named scalar of the state – a distance, a displacement component, an angle, a velocity – used in expression forces and drivers by its name. They are not result channels themselves; to plot one, write it as a formula channel in the viewer, look at the force that uses it, or make it an output.
measures:
z_wheel: {type: displacement, body1: wheel, component: z, offset: initial} # travel from the start
vz_wheel: {type: velocity, body1: wheel, component: z}
gap: {type: distance, body1: a, point1: [0, 0, 1], body2: b, point2: [0, 0, 2]}
steer: {type: angle, body1: knuckle, body2: carrier, orientation: [1, 0, 0, 0]} # about z of the frame
lean: {type: direction, body1: frame, vector: [0, 0, 1], component: y} # vertical in the body frame
| type | value |
|---|---|
displacement / velocity |
a component of P1 − P2 (V1 − V2), in frame (global or a body) |
distance / distance_rate |
|P1 − P2| and its rate |
angle / angular_rate |
rotation of body1 about the z axis of orientation fixed on body2 (continuous: counts turns) |
direction |
a component of a global vector in a frame (default body1), e.g. the lean of a vehicle |
angular_velocity |
a component of ω1 − ω2 in frame |
offset: initial subtracts the initial value; a number subtracts that number.
| key | value | |
|---|---|---|
id |
id | |
type (required) |
displacement | velocity | distance | distance_rate | angle | angular_rate | direction | angular_velocity |
displacement / velocity: component of P1 - P2 / V1 - V2 in frame; distance: |P1 - P2| and its rate; angle: rotation of body1 about the z axis of orientation fixed on body2 (as torsion_spring) and its rate; direction: component of the global vector in the frame (default body1), e.g. the vertical in a vehicle frame (lean); angular_velocity: component of omega1 - omega2 in frame (global or a body). |
body1 (required) |
string | |
body2 |
string | A body or 'ground'. Default ground. |
point1 |
[x, y, z] or a point name | Point on body1, global, at t = 0. Default its center of mass. |
point2 |
[x, y, z] or a point name | Point on body2 or the ground, global, at t = 0. Default its center of mass / the origin. |
component |
x | y | z |
|
vector |
[x, y, z] | direction: a global vector. |
frame |
string | displacement / velocity: 'global' (default) or a body whose frame gives the components. |
orientation |
list of 4 or a frame name | angle: frame (axis z), global at t = 0. |
offset |
number or list | initial: subtract the initial value (displacement, distance, angle); a number: subtract it. Default none. |
plane |
list of 2 | angle / angular_rate, with vector: the vectors b, c (on body2 or the ground, global at t = 0) of the plane the angle of vector (on body1) is measured in, atan2(a.c, a.b), instead of orientation (legacy Measure Rotational MeasurePlaneVec1 / 2). |
normalize |
boolean | angle / angular_rate with vector and plane: normalize the three vectors (false: as given, as legacy Angle and body-body AngleVel measures). Default True. |
form |
legacy |
angular_rate: legacy gives the numerator x ydot - y xdot of the rate only (legacy AngleVel measures). Default the exact rate. |
Expressions¶
Force laws, driver motions and formulas share one small language (it is parsed, never executed):
- numbers,
+ - * / ^(or**), unary minus, parentheses; - names:
t(time),pi, the parameters, the runtime inputs and the measures (both not in formulas), the splines as functions:damper_curve(v); - functions:
sin cos tan asin acos atan atan2 sinh cosh tanh exp log sqrt abs sign min max; step(x, x0, y0, x1, y1): smooth step from y0 (x ≤ x0) to y1 (x ≥ x1) – a 9th order polynomial;step(x, x0, y0, x1, y1, "cosine")or"hard"(the legacy FreeDyn STEP);if_else(condition, a, b)with< <= > >= == !=; conditions multiply as and:if_else((t > 1) * (t < 2), 1, 0).
Everything is differentiated exactly (CasADi); there are no numerical derivatives.
Splines¶
Named curves y(x), called like functions in expressions: a damper characteristic, a measured road, a motor map.
splines:
damper_curve: {x: [-1, -0.2, 0, 0.2, 1], y: [-3000, -900, 0, 600, 1500]} # [m/s] -> [N]
road: {file: data/road.txt, columns: [0, 1], header_lines: 1} # from a table
forces:
damper: {type: expression_force, body1: wheel, body2: body, point1: [0, 0, 0.3], point2: [0, 0, 0.65],
force: damper_curve(v_rel)}
type: akima (default: no overshoot, linear beyond the ends) or zcc (the legacy FreeDyn
spline).
| key | value | |
|---|---|---|
id |
id | |
file |
string | Text table with the data instead of x / y (relative to the model file): columns separated by spaces, as the legacy spline data files. |
header_lines |
integer | file: lines to skip. Default 0. |
columns |
list of 2 | file: column indices (from 0) of x and y. Default [0, 1]. |
x |
list | Strictly increasing. |
y |
list | |
type |
akima | zcc |
akima (default): Akima, linear beyond the ends; zcc: zero clamped C2 cubic, quadratic beyond the last point (legacy FreeDyn splines). |
Outputs¶
An output is a named expression of measures, parameters and runtime
inputs, written as the result channel <name>.value. It acts on
nothing. A program that runs the model and reads its channels (fd::System::outputs) gets
derived quantities, a lean angle, an engine speed, a suspension travel, without knowing the
model's geometry.
measures:
lean: {type: direction, body1: frame, vector: [0, 0, 1], component: y} # sin(lean)
w_crank: {type: angular_rate, body1: crank, body2: frame, orientation: [0.7071068, -0.7071068, 0, 0]}
outputs:
lean_deg: asin(lean) * 180 / pi
rpm: w_crank * 30 / pi
Each output must use a measure; its name must differ from the bodies, joints, forces, sensors and drivers.
Drivers¶
A driver prescribes a measure – a displacement, distance or angle – as a function of time: a
constraint m(q) − f(t) = 0. With a runtime input in f the motion
is set from outside while the model runs (motion: x_set). The reaction is a result channel (<driver>.lambda).
measures:
phi: {type: angle, body1: rotor, orientation: [1, 0, 0, 0]}
drivers:
spin: {measure: phi, motion: w * t} # a constant speed
lift: {measure: z_table, motion: 0.1 * sin(2 * pi * t), ramp: 0.5} # from rest, smoothly
Without ramp the motion must start where the measure is at t = 0. With ramp: Ta a smooth
polynomial joins the initial value at rest to the motion at Ta.
| key | value | |
|---|---|---|
id |
id | |
measure (required) |
string | |
motion (required) |
string | Expression of t, parameters and splines, e.g. '0.1 * sin(2 * pi * t)'. |
ramp |
number | Activation time Ta: for t < Ta a 7th order polynomial from the initial measure value at rest joins the motion C2 at Ta (legacy TimeMotion ActivationPeriod). Default 0: the motion must start at the initial configuration. |