examples.Engine1b_analytic
One-cylinder engine with gas force (planar loop solved analytically)
Same one-cylinder engine as Engine1b, but the central part of the planar kinematic loop is replaced by the assembly joint JointRRP (revolute - revolute
- prismatic).
JointRRPsolves the non-linear loop equation analytically instead
of numerically, so no non-linear algebraic system is introduced. The crankshaft (bearing + crank1..crank4) is driven by the flywheel inertia (initial 10 rad/s); the connecting rod and piston are carried by the interior frames frame_ia/frame_ib of jointRRP, and gasForce drives the prismatic axis.
The analytic loop solution is a quadratic with two roots, and jointRRP picks the one closest to its s_guess when the mechanism is assembled at initialization. That is the configuration in which the piston sits between the cylinder head and the crank pin. The other root mirrors the connecting rod through the cylinder-head plane; it satisfies the same length constraint, so it is kinematically valid and raises no error, but it inverts the piston geometry so that the gas force brakes the crankshaft instead of driving it, and the mechanism locks up at half a revolution.
The diagram layout is preserved from the reference engine model using the same Modelica->Dyad coordinate transform as Engine1b (x_d = 500 + 5_x_m, y_d = 500 - 5_y_m, rot_d = (360 - rot_m) mod 360). Do not run dyad layout on this model.
Usage
MultibodyComponents.examples.Engine1b_analytic()
Behavior
using MultibodyComponents #hide
using ModelingToolkit #hide
@named sys = MultibodyComponents.examples.Engine1b_analytic() #hide
let eqs = full_equations(sys); Base.length(eqs) > 25 ? nothing : eqs end #hide<< @example-block not executed in draft mode >>Source
"""
# One-cylinder engine with gas force (planar loop solved analytically)
Same one-cylinder engine as `Engine1b`, but the central part of the planar
kinematic loop is replaced by the assembly joint `JointRRP` (revolute - revolute
- prismatic). `JointRRP` solves the non-linear loop equation analytically instead
of numerically, so no non-linear algebraic system is introduced. The crankshaft
(`bearing` + `crank1`..`crank4`) is driven by the flywheel `inertia` (initial
10 rad/s); the connecting rod and piston are carried by the interior frames
`frame_ia`/`frame_ib` of `jointRRP`, and `gasForce` drives the prismatic axis.
The analytic loop solution is a quadratic with two roots, and `jointRRP` picks the
one closest to its `s_guess` when the mechanism is assembled at initialization.
That is the configuration in which the piston sits between the cylinder head and
the crank pin. The other root mirrors the connecting rod through the cylinder-head
plane; it satisfies the same length constraint, so it is kinematically valid and
raises no error, but it inverts the piston geometry so that the gas force brakes
the crankshaft instead of driving it, and the mechanism locks up at half a
revolution.
The diagram layout is preserved from the reference engine model using the same
Modelica->Dyad coordinate transform as `Engine1b` (x_d = 500 + 5*x_m,
y_d = 500 - 5*y_m, rot_d = (360 - rot_m) mod 360). Do not run `dyad layout` on
this model.
"""
example component Engine1b_analytic
world = MultibodyComponents.World() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 0, "y1": 900, "x2": 100, "y2": 1000, "rot": 0}
},
"tags": []
}
}
piston = MultibodyComponents.BodyCylinder(diameter = 0.1, r = [0, -0.1, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 880, "y1": 310, "x2": 980, "y2": 410, "rot": 0}
},
"tags": []
}
}
connectingRod = MultibodyComponents.BodyBox(width_dir = [1, 0, 0], width = 0.02, height = 0.06, color = [0, 0, 0.784, 1], r = [0, -0.2, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 900, "y1": 550, "x2": 1000, "y2": 650, "rot": 270}
},
"tags": []
}
}
bearing = MultibodyComponents.Revolute(n = [1, 0, 0], cylinder_length = 0.02, radius = 0.025) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 200, "y1": 900, "x2": 300, "y2": 1000, "rot": 0}
},
"tags": []
}
}
inertia = RotationalComponents.Components.Inertia(J = 1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 200, "y1": 700, "x2": 300, "y2": 800, "rot": 0}
},
"tags": []
}
}
crank1 = MultibodyComponents.BodyCylinder(diameter = 0.05, r = [0.1, 0, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 350, "y1": 900, "x2": 450, "y2": 1000, "rot": 0}
},
"tags": []
}
}
crank2 = MultibodyComponents.BodyBox(height = 0.05, width_dir = [1, 0, 0], width = 0.02, r = [0, 0.1, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": 850, "x2": 550, "y2": 950, "rot": 270}
},
"tags": []
}
}
crank3 = MultibodyComponents.BodyCylinder(diameter = 0.03, r = [0.1, 0, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 700, "y1": 780, "x2": 800, "y2": 880, "rot": 0}
},
"tags": []
}
}
crank4 = MultibodyComponents.BodyBox(height = 0.05, width_dir = [1, 0, 0], width = 0.02, r = [0, -0.1, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 1000, "y1": 850, "x2": 900, "y2": 950, "rot": 270}
},
"tags": []
}
}
mid = MultibodyComponents.FixedTranslation(r = [0.05, 0, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 550, "y1": 650, "x2": 650, "y2": 750, "rot": 0}
},
"tags": []
}
}
cylPosition = MultibodyComponents.FixedTranslation(r = [0.15, 0.45, 0], render = false) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 100, "y1": 250, "x2": 200, "y2": 350, "rot": 270}
},
"tags": []
}
}
gasForce = MultibodyComponents.GasForce2(d = 0.1, L = 0.35) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 860, "y1": 400, "x2": 960, "y2": 500, "rot": 270}
},
"tags": []
}
}
jointRRP = MultibodyComponents.JointRRP(n_a = [1, 0, 0], n_b = [0, -1, 0], rRod1_ia = [0, 0.2, 0], rRod2_ib = [0, -0.1, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 600, "y1": 300, "x2": 800, "y2": 500, "rot": 270}
},
"tags": []
}
}
relations
initial inertia.phi = 0
initial inertia.w = 10
connect(world.frame_b, bearing.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(crank2.frame_a, crank1.frame_b) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 500, "y": 950}], "E": 2}],
"renderStyle": "standard"
}
}
connect(bearing.frame_b, crank1.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(world.frame_b, cylPosition.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 150, "y": 950}], "E": 2}],
"renderStyle": "standard"
}
}
connect(crank3.frame_b, crank4.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 950, "y": 830}], "E": 2}],
"renderStyle": "standard"
}
}
connect(inertia.spline_b, bearing.axis) {
"Dyad": {
"edges": [
{
"S": 1,
"M": [{"x": 350, "y": 750}, {"x": 350, "y": 850}, {"x": 250, "y": 850}],
"E": 2
}
],
"renderStyle": "standard"
}
}
connect(crank2.frame_b, crank3.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 500, "y": 830}], "E": 2}],
"renderStyle": "standard"
}
}
connect(crank2.frame_b, mid.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 500, "y": 700}], "E": 2}],
"renderStyle": "standard"
}
}
connect(mid.frame_b, jointRRP.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 700, "y": 700}], "E": 2}],
"renderStyle": "standard"
}
}
connect(jointRRP.frame_b, cylPosition.frame_b) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 700, "y": 200}, {"x": 150, "y": 200}], "E": 2}],
"renderStyle": "standard"
}
}
connect(jointRRP.frame_ib, piston.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 890, "y": 364}], "E": 2}],
"renderStyle": "standard"
}
}
connect(connectingRod.frame_b, jointRRP.frame_ia) {
"Dyad": {
"edges": [
{
"S": 1,
"M": [
{"x": 950, "y": 550},
{"x": 750, "y": 550},
{"x": 750, "y": 440},
{"x": 700, "y": 440}
],
"E": 2
}
],
"renderStyle": "standard"
}
}
connect(jointRRP.axis, gasForce.flange_b) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 800, "y": 390}, {"x": 910, "y": 390}], "E": 2}],
"renderStyle": "standard"
}
}
connect(jointRRP.bearing, gasForce.flange_a) {
"Dyad": {
"edges": [
{
"S": 1,
"M": [
{"x": 800, "y": 462},
{"x": 800, "y": 510},
{"x": 910, "y": 510},
{"x": 910, "y": 500}
],
"E": 2
}
],
"renderStyle": "standard"
}
}
endFlattened Source
"""
# One-cylinder engine with gas force (planar loop solved analytically)
Same one-cylinder engine as `Engine1b`, but the central part of the planar
kinematic loop is replaced by the assembly joint `JointRRP` (revolute - revolute
- prismatic). `JointRRP` solves the non-linear loop equation analytically instead
of numerically, so no non-linear algebraic system is introduced. The crankshaft
(`bearing` + `crank1`..`crank4`) is driven by the flywheel `inertia` (initial
10 rad/s); the connecting rod and piston are carried by the interior frames
`frame_ia`/`frame_ib` of `jointRRP`, and `gasForce` drives the prismatic axis.
The analytic loop solution is a quadratic with two roots, and `jointRRP` picks the
one closest to its `s_guess` when the mechanism is assembled at initialization.
That is the configuration in which the piston sits between the cylinder head and
the crank pin. The other root mirrors the connecting rod through the cylinder-head
plane; it satisfies the same length constraint, so it is kinematically valid and
raises no error, but it inverts the piston geometry so that the gas force brakes
the crankshaft instead of driving it, and the mechanism locks up at half a
revolution.
The diagram layout is preserved from the reference engine model using the same
Modelica->Dyad coordinate transform as `Engine1b` (x_d = 500 + 5*x_m,
y_d = 500 - 5*y_m, rot_d = (360 - rot_m) mod 360). Do not run `dyad layout` on
this model.
"""
example component Engine1b_analytic
world = MultibodyComponents.World() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 0, "y1": 900, "x2": 100, "y2": 1000, "rot": 0}
},
"tags": []
}
}
piston = MultibodyComponents.BodyCylinder(diameter = 0.1, r = [0, -0.1, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 880, "y1": 310, "x2": 980, "y2": 410, "rot": 0}
},
"tags": []
}
}
connectingRod = MultibodyComponents.BodyBox(width_dir = [1, 0, 0], width = 0.02, height = 0.06, color = [0, 0, 0.784, 1], r = [0, -0.2, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 900, "y1": 550, "x2": 1000, "y2": 650, "rot": 270}
},
"tags": []
}
}
bearing = MultibodyComponents.Revolute(n = [1, 0, 0], cylinder_length = 0.02, radius = 0.025) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 200, "y1": 900, "x2": 300, "y2": 1000, "rot": 0}
},
"tags": []
}
}
inertia = RotationalComponents.Components.Inertia(J = 1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 200, "y1": 700, "x2": 300, "y2": 800, "rot": 0}
},
"tags": []
}
}
crank1 = MultibodyComponents.BodyCylinder(diameter = 0.05, r = [0.1, 0, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 350, "y1": 900, "x2": 450, "y2": 1000, "rot": 0}
},
"tags": []
}
}
crank2 = MultibodyComponents.BodyBox(height = 0.05, width_dir = [1, 0, 0], width = 0.02, r = [0, 0.1, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 450, "y1": 850, "x2": 550, "y2": 950, "rot": 270}
},
"tags": []
}
}
crank3 = MultibodyComponents.BodyCylinder(diameter = 0.03, r = [0.1, 0, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 700, "y1": 780, "x2": 800, "y2": 880, "rot": 0}
},
"tags": []
}
}
crank4 = MultibodyComponents.BodyBox(height = 0.05, width_dir = [1, 0, 0], width = 0.02, r = [0, -0.1, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 1000, "y1": 850, "x2": 900, "y2": 950, "rot": 270}
},
"tags": []
}
}
mid = MultibodyComponents.FixedTranslation(r = [0.05, 0, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 550, "y1": 650, "x2": 650, "y2": 750, "rot": 0}
},
"tags": []
}
}
cylPosition = MultibodyComponents.FixedTranslation(r = [0.15, 0.45, 0], render = false) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 100, "y1": 250, "x2": 200, "y2": 350, "rot": 270}
},
"tags": []
}
}
gasForce = MultibodyComponents.GasForce2(d = 0.1, L = 0.35) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 860, "y1": 400, "x2": 960, "y2": 500, "rot": 270}
},
"tags": []
}
}
jointRRP = MultibodyComponents.JointRRP(n_a = [1, 0, 0], n_b = [0, -1, 0], rRod1_ia = [0, 0.2, 0], rRod2_ib = [0, -0.1, 0]) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 600, "y1": 300, "x2": 800, "y2": 500, "rot": 270}
},
"tags": []
}
}
relations
initial inertia.phi = 0
initial inertia.w = 10
connect(world.frame_b, bearing.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(crank2.frame_a, crank1.frame_b) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 500, "y": 950}], "E": 2}],
"renderStyle": "standard"
}
}
connect(bearing.frame_b, crank1.frame_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(world.frame_b, cylPosition.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 150, "y": 950}], "E": 2}],
"renderStyle": "standard"
}
}
connect(crank3.frame_b, crank4.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 950, "y": 830}], "E": 2}],
"renderStyle": "standard"
}
}
connect(inertia.spline_b, bearing.axis) {
"Dyad": {
"edges": [
{
"S": 1,
"M": [{"x": 350, "y": 750}, {"x": 350, "y": 850}, {"x": 250, "y": 850}],
"E": 2
}
],
"renderStyle": "standard"
}
}
connect(crank2.frame_b, crank3.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 500, "y": 830}], "E": 2}],
"renderStyle": "standard"
}
}
connect(crank2.frame_b, mid.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 500, "y": 700}], "E": 2}],
"renderStyle": "standard"
}
}
connect(mid.frame_b, jointRRP.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 700, "y": 700}], "E": 2}],
"renderStyle": "standard"
}
}
connect(jointRRP.frame_b, cylPosition.frame_b) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 700, "y": 200}, {"x": 150, "y": 200}], "E": 2}],
"renderStyle": "standard"
}
}
connect(jointRRP.frame_ib, piston.frame_a) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 890, "y": 364}], "E": 2}],
"renderStyle": "standard"
}
}
connect(connectingRod.frame_b, jointRRP.frame_ia) {
"Dyad": {
"edges": [
{
"S": 1,
"M": [
{"x": 950, "y": 550},
{"x": 750, "y": 550},
{"x": 750, "y": 440},
{"x": 700, "y": 440}
],
"E": 2
}
],
"renderStyle": "standard"
}
}
connect(jointRRP.axis, gasForce.flange_b) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 800, "y": 390}, {"x": 910, "y": 390}], "E": 2}],
"renderStyle": "standard"
}
}
connect(jointRRP.bearing, gasForce.flange_a) {
"Dyad": {
"edges": [
{
"S": 1,
"M": [
{"x": 800, "y": 462},
{"x": 800, "y": 510},
{"x": 910, "y": 510},
{"x": 910, "y": 500}
],
"E": 2
}
],
"renderStyle": "standard"
}
}
metadata {}
endTest Cases
No test cases defined.
Related
Examples
Experiments
Analyses
<< @example-block not executed in draft mode >>