Source code for exlink.constants
"""Physical constants and specification data for the Honda EX-link derived engine.
Unit system used throughout the package
---------------------------------------
============ =====================================
quantity unit
============ =====================================
length mm
angle rad (degrees only at the API surface)
area mm^2
volume mm^3
pressure MPa (= N/mm^2); 1 bar = 0.1 MPa
force N
torque N.mm
============ =====================================
The numbers below define a single-cylinder Shell Eco-marathon engine and are
held fixed throughout; only the linkage geometry and the member sections are
designed.
"""
from __future__ import annotations
import math
from dataclasses import dataclass
BAR = 0.1
"""One bar expressed in MPa."""
[docs]
@dataclass(frozen=True)
class EngineSpec:
"""Fixed data of the thermodynamic cycle and of the cylinder.
Everything that is *not* a design variable lives here, so that a study can
be repeated with a different brief by passing another :class:`EngineSpec`
around instead of editing the code.
"""
bore: float = 32.0
"""Piston diameter ``phi`` [mm]."""
piston_length: float = 16.0
"""Distance ``p`` from the wrist pin ``P`` to the piston crown ``H`` [mm]."""
piston_skirt: float = 16.0
"""Guided length ``h`` of the piston inside the liner [mm].
Only enters the (unused) reaction moment ``M_D``, so it simply defaults to
the piston length.
"""
dead_volume: float = 3000.0
"""Clearance volume ``V0`` at top dead centre [mm^3] (3 cc)."""
p_intake: float = 1.2 * BAR
"""Intake / exhaust plenum pressure ``P0`` [MPa] (1.2 bar)."""
heat_capacity_ratio: float = 1.22
"""Polytropic exponent ``gamma`` of compression and expansion."""
explosion_ratio: float = 1.7
"""``k = P3 / P2``, the instantaneous pressure jump modelling combustion."""
gear_ratio: float = 2.0
"""``r1 / r2`` between the analysis shaft's gear and the output shaft's.
The kinematics of :mod:`exlink.kinematics` are parametrised on ``theta_1``,
the shaft carrying ``q_1`` and the *large* gear, and the four strokes
complete in one turn of it. The second shaft therefore turns
``theta_2 = -2 theta_1 + theta_f``: twice per cycle, or **720 deg**, which is
what a conventional four-stroke crankshaft does. Power is taken from that
shaft, so ``theta_1`` is the half-speed member of the pair -- Honda's own
arrangement -- and every engine speed the study quotes is the output
shaft's, at :attr:`output_revolutions_per_cycle` times the ``speed_rpm``
the analysis functions take.
"""
pressure_angle: float = math.radians(20.0)
"""Gear pressure angle ``alpha``.
20 deg is the standard involute profile and is used throughout; ``alpha``
enters only the gear-mesh separating force.
"""
@property
def piston_area(self) -> float:
"""Cross-section ``pi phi^2 / 4`` on which the gas pressure acts [mm^2]."""
return math.pi * self.bore**2 / 4.0
@property
def output_revolutions_per_cycle(self) -> float:
"""Turns of the output shaft per four-stroke cycle [-].
Two, from :attr:`gear_ratio`, and the same as a conventional engine --
which is what makes the comparison of section 6.3 a comparison at equal
speed and equal firing rate rather than one needing a correction.
"""
return self.gear_ratio
[docs]
def output_speed_rpm(self, speed_rpm: float) -> float:
"""Output-shaft speed for an analysis speed ``theta_1`` [rev/min]."""
return float(speed_rpm) * self.gear_ratio
[docs]
def output_torque(self, torque: float) -> float:
"""Torque referred from ``theta_1`` to the output shaft [N.mm].
The virtual-work identity of :mod:`exlink.loads` makes ``M_r`` the
*whole* engine torque referred to ``theta_1``, so referring it to a
shaft turning ``gear_ratio`` times faster divides it by that ratio and
leaves the power untouched. Nothing physical depends on which shaft
the reading is taken from; only the numbers on the datasheet do.
"""
return float(torque) / self.gear_ratio
[docs]
@dataclass(frozen=True)
class DesignTargets:
"""Right-hand sides of the equality and inequality constraints.
The performance requirements the engine must meet, plus the well-posedness
constraints that keep the linkage analysable (see :mod:`exlink.kinematics`).
"""
expansion_stroke: float = 74.0
"""Required expansion stroke ``STE`` [mm] (equality constraint)."""
compression_ratio: float = 16.0
"""Required compression ratio ``epsilon`` (equality constraint)."""
max_rod_angle: float = 10.0
"""Upper bound on ``mra``, the piston-rod tilt away from vertical [deg]."""
max_transmission: float = 0.985
"""Upper bound ``C`` on ``W = max(delta_c1, delta_c2)``.
``C = 0.9848`` keeps the transmission angle ``T`` inside
``[10 deg, 170 deg]``; it is rounded to 0.985 here.
"""
max_tdc_gap: float = 0.01
"""Upper bound on ``g``, the gap between the two top dead centres [mm]."""
min_clearance: float = 10.0
"""Lower bound on ``d``, trigonal-link to cylinder clearance [mm]."""
max_side_load: float = 0.02
"""Upper bound on ``gamma = max(D) / max(P)``, the piston side-load ratio."""
max_bearing_load: float = 25_000.0
"""Upper bound on the peak crankshaft bearing reaction [N].
Only meaningful once inertia is in the load path: at rest this mechanism
peaks near 7.7 kN, but the reaction grows as the square of engine speed and
is what a plain bearing actually has to survive.
"""
[docs]
@dataclass(frozen=True)
class PenaltyValues:
"""Values substituted when a design cannot be analysed at all.
``eta(X) = 0``, ``H(X) = 1000``, ``B(X) = 1000`` are substituted whenever
the kinematic compatibility conditions (4a)/(6a) fail, or whenever
``lambda(theta_1)`` does not have four monotone phases.
"""
efficiency: float = 0.0
height: float = 1000.0
width: float = 1000.0
DEFAULT_SPEC = EngineSpec()
DEFAULT_TARGETS = DesignTargets()
DEFAULT_PENALTY = PenaltyValues()