Last active
September 9, 2022 01:50
-
-
Save LuizZak/e0f4f2df9c3c68fda3abc321a6247ff8 to your computer and use it in GitHub Desktop.
RC221V
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "engine_sim.mr" | |
// Honda RC211V 75.5° V5 - used in MotoGP from ~2001-2004 | |
// Reference for some of the numbers in the design: https://patents.google.com/patent/US6745730B2/en | |
// Potential firing order referenced from: https://youtu.be/U5_wWC2cURU?t=260 | |
/* | |
- Running engine: | |
- main.mr: | |
set_engine( | |
RC211V( | |
timings: v5_75_2004_timings() // or v5_75_2001_timings() | |
) | |
) | |
set_vehicle( | |
RC211V_vehicle() | |
) | |
set_transmission( | |
RC211V_transmission() | |
) | |
- Or: | |
RC211V_main() | |
- Changing timings/firing order on RC211V_main (defaults to v5_75_2004_timings): | |
- main.mr: | |
RC211V_main( | |
timings: v5_75_2001_timings() | |
) | |
*/ | |
units units() | |
constants constants() | |
impulse_response_library ir_lib() | |
label cycle(2 * 360 * units.deg) | |
label bank_separation(77.5 * units.deg) | |
label rod_journal_separation(104.5 * units.deg) | |
label cylinder_volume(197.89 * units.cc) | |
label compression_ratio(1.0 / 13.0) | |
// Timings | |
// Approximate potential ignition timings (in 720° cycle percentage / °degrees): | |
// 3-cylinder bank (bank #1) (odd cylinders): | |
// 0% (0°) | |
// 50% (360°) | |
// 3-cylinder bank (center cylinder): | |
// 14.51% (104.5°) | |
// 64.51% (464.5°) | |
// 2-cylinder bank (bank #2): | |
// 39.51% (284.5°) | |
// 89.51% (644.5°) | |
// Defines timings of piston firing on a V5 engine based on the TDC of the front-most piston (first piston on 3-cylinder bank) | |
// Timings are in degrees, adding up to 720° (4-strokes of 180° each). | |
// Timings are also assumed to be the TDC point of the respective cylinder, as timing of the camshaft is also computed from the | |
// pistons' ignition timings. | |
public node v5_75_timings { | |
// A textual label appended to the engine's name for context. | |
input label; | |
// Top dead center of the first piston (forward cylinder in 3-cylinder bank) | |
input tdc_crankshaft: bank_separation / 2.0; | |
input piston1_ignition; // Bank 1 piston 1 | |
input piston2_ignition; // Bank 2 piston 1 | |
input piston3_ignition; // Bank 2 piston 2 (off by 104°) | |
input piston4_ignition; // Bank 1 piston 2 | |
input piston5_ignition; // Bank 2 piston 3 | |
} | |
// Approximates the timings of the initial Honda RC211V v5 from 2001 | |
// Source: https://en.wikipedia.org/wiki/Big-bang_firing_order#Five-cylinder_engines | |
public node v5_75_2001_timings { | |
alias output __out: | |
v5_75_timings( | |
label: "2001 ignition", | |
piston1_ignition: 0.0 * units.deg, | |
piston2_ignition: 284.5 * units.deg, | |
piston3_ignition: 464.5 * units.deg, | |
piston4_ignition: 644.5 * units.deg, | |
piston5_ignition: 360.0 * units.deg | |
); | |
} | |
// Approximates the timings of the initial Honda RC211V v5 from 2004 | |
// Source: https://en.wikipedia.org/wiki/Big-bang_firing_order#Five-cylinder_engines | |
public node v5_75_2004_timings { | |
alias output __out: | |
v5_75_timings( | |
label: "2004 ignition", | |
piston1_ignition: 0.0 * units.deg, | |
piston2_ignition: 284.5 * units.deg, | |
piston3_ignition: 464.5 * units.deg, | |
piston4_ignition: 284.5 * units.deg, | |
piston5_ignition: 0.0 * units.deg | |
); | |
} | |
// Head | |
private node add_flow_sample { | |
input lift; | |
input flow; | |
input this; | |
alias output __out: this; | |
this.add_sample(lift * units.thou, k_28inH2O(flow)) | |
} | |
// This cylinder head is a work of plugging numbers and seeing what works | |
public node v5_75_head { | |
input intake_camshaft; | |
input exhaust_camshaft; | |
input chamber_volume: cylinder_volume * compression_ratio; | |
input flip_display: false; | |
alias output __out: head; | |
input flow_attenuation: 1.7; | |
input lift_scale: 1.0; | |
function intake_flow(50 * units.thou) | |
intake_flow | |
.add_flow_sample(0 * lift_scale, 0 * flow_attenuation) | |
.add_flow_sample(160 * lift_scale, 135 * flow_attenuation) | |
.add_flow_sample(210 * lift_scale, 186 * flow_attenuation) | |
.add_flow_sample(260 * lift_scale, 210 * flow_attenuation) | |
.add_flow_sample(310 * lift_scale, 256 * flow_attenuation) | |
.add_flow_sample(360 * lift_scale, 285 * flow_attenuation) | |
.add_flow_sample(410 * lift_scale, 322 * flow_attenuation) | |
.add_flow_sample(460 * lift_scale, 330 * flow_attenuation) | |
.add_flow_sample(510 * lift_scale, 365 * flow_attenuation) | |
.add_flow_sample(560 * lift_scale, 385 * flow_attenuation) | |
.add_flow_sample(610 * lift_scale, 404 * flow_attenuation) | |
.add_flow_sample(660 * lift_scale, 410 * flow_attenuation) | |
.add_flow_sample(710 * lift_scale, 424 * flow_attenuation) | |
.add_flow_sample(760 * lift_scale, 424 * flow_attenuation) | |
.add_flow_sample(810 * lift_scale, 424 * flow_attenuation) | |
function exhaust_flow(50 * units.thou) | |
exhaust_flow | |
.add_flow_sample(0 * lift_scale, 0 * flow_attenuation) | |
.add_flow_sample(160 * lift_scale, 135 * flow_attenuation) | |
.add_flow_sample(210 * lift_scale, 180 * flow_attenuation) | |
.add_flow_sample(260 * lift_scale, 210 * flow_attenuation) | |
.add_flow_sample(310 * lift_scale, 242 * flow_attenuation) | |
.add_flow_sample(360 * lift_scale, 250 * flow_attenuation) | |
.add_flow_sample(410 * lift_scale, 266 * flow_attenuation) | |
.add_flow_sample(460 * lift_scale, 280 * flow_attenuation) | |
.add_flow_sample(510 * lift_scale, 291 * flow_attenuation) | |
.add_flow_sample(560 * lift_scale, 301 * flow_attenuation) | |
.add_flow_sample(610 * lift_scale, 317 * flow_attenuation) | |
.add_flow_sample(660 * lift_scale, 324 * flow_attenuation) | |
.add_flow_sample(710 * lift_scale, 338 * flow_attenuation) | |
.add_flow_sample(760 * lift_scale, 338 * flow_attenuation) | |
.add_flow_sample(810 * lift_scale, 338 * flow_attenuation) | |
cylinder_head head( | |
chamber_volume: chamber_volume, | |
intake_runner_volume: 900.00 * units.cc, | |
intake_runner_cross_section_area: 7.00 * units.cm2, | |
intake_port_flow: intake_flow, | |
exhaust_port_flow: exhaust_flow, | |
intake_camshaft: intake_camshaft, | |
exhaust_camshaft: exhaust_camshaft, | |
flip_display: flip_display | |
) | |
} | |
// Distributor / wiring | |
private node wires { | |
output wire1: ignition_wire(); | |
output wire2: ignition_wire(); | |
output wire3: ignition_wire(); | |
output wire4: ignition_wire(); | |
output wire5: ignition_wire(); | |
} | |
label ignition_offset(-5.0 * units.deg) | |
private node v5_75_distributor { | |
input wires; | |
input timing_curve; | |
input rev_limit; | |
input timings; | |
alias output __out: | |
ignition_module(timing_curve: timing_curve, rev_limit: rev_limit) | |
.connect_wire(wires.wire1, timings.piston1_ignition + ignition_offset) | |
.connect_wire(wires.wire2, timings.piston2_ignition + ignition_offset) | |
.connect_wire(wires.wire3, timings.piston3_ignition + ignition_offset) | |
.connect_wire(wires.wire4, timings.piston4_ignition + ignition_offset) | |
.connect_wire(wires.wire5, timings.piston5_ignition + ignition_offset); | |
} | |
// Camshaft | |
private node v5_75_camshaft_builder { | |
input intake_lobe_profile; | |
input exhaust_lobe_profile; | |
input base_radius; | |
input lobe_separation: 114.0 * units.deg; | |
input intake_lobe_center: lobe_separation; | |
input exhaust_lobe_center: lobe_separation; | |
input advance: 0.0 * units.deg; | |
input timings; | |
output intake_cam_0: _intake_cam_0; | |
output intake_cam_1: _intake_cam_1; | |
output exhaust_cam_0: _exhaust_cam_0; | |
output exhaust_cam_1: _exhaust_cam_1; | |
camshaft_parameters params( | |
advance: advance, | |
base_radius: base_radius | |
) | |
camshaft _intake_cam_0(params, lobe_profile: intake_lobe_profile) | |
camshaft _intake_cam_1(params, lobe_profile: intake_lobe_profile) | |
camshaft _exhaust_cam_0(params, lobe_profile: exhaust_lobe_profile) | |
camshaft _exhaust_cam_1(params, lobe_profile: exhaust_lobe_profile) | |
label rot360(360 * units.deg) | |
label intake_after_ignition(rot360 - 20 * units.deg) | |
label exhaust_before_ignition(-rot360 - 10 * units.deg) | |
label camshaft_offset(0.0 * units.deg) | |
_intake_cam_0 | |
.add_lobe(timings.piston1_ignition + intake_after_ignition + intake_lobe_center + camshaft_offset) | |
.add_lobe(timings.piston3_ignition + intake_after_ignition + intake_lobe_center + camshaft_offset) | |
.add_lobe(timings.piston5_ignition + intake_after_ignition + intake_lobe_center + camshaft_offset) | |
_exhaust_cam_0 | |
.add_lobe(timings.piston1_ignition + exhaust_before_ignition - exhaust_lobe_center + camshaft_offset) | |
.add_lobe(timings.piston3_ignition + exhaust_before_ignition - exhaust_lobe_center + camshaft_offset) | |
.add_lobe(timings.piston5_ignition + exhaust_before_ignition - exhaust_lobe_center + camshaft_offset) | |
_intake_cam_1 | |
.add_lobe(timings.piston2_ignition + intake_after_ignition + intake_lobe_center + camshaft_offset) | |
.add_lobe(timings.piston4_ignition + intake_after_ignition + intake_lobe_center + camshaft_offset) | |
_exhaust_cam_1 | |
.add_lobe(timings.piston2_ignition + exhaust_before_ignition - exhaust_lobe_center + camshaft_offset) | |
.add_lobe(timings.piston4_ignition + exhaust_before_ignition - exhaust_lobe_center + camshaft_offset) | |
} | |
private node v5_75_camshaft { | |
input timings; | |
alias output __out: | |
v5_75_camshaft_builder( | |
intake_lobe_profile: intake_lobe, | |
exhaust_lobe_profile: exhaust_lobe, | |
lobe_separation: 112 * units.deg, | |
base_radius: 12 * units.mm, | |
timings: timings | |
); | |
harmonic_cam_lobe intake_lobe( | |
duration_at_50_thou: 185 * units.deg, | |
gamma: 0.9, | |
lift: 11 * units.mm, | |
steps: 100 | |
) | |
harmonic_cam_lobe exhaust_lobe( | |
duration_at_50_thou: 200 * units.deg, | |
gamma: 0.9, | |
lift: 11 * units.mm, | |
steps: 100 | |
) | |
} | |
// Engine | |
public node RC211V { | |
alias output __out: engine; | |
input timings; | |
// Engine specs constants | |
label stroke_length(48.2 * units.mm) | |
label bore_diameter(72.3 * units.mm) | |
label piston_compression_height(20.0 * units.mm) | |
label connecting_rod_length(95.0 * units.mm) | |
// | |
wires wires() | |
engine engine( | |
name: string_add( | |
"Honda RC211V", | |
string_add( | |
" (", | |
string_add( | |
timings.label, | |
")" | |
) | |
) | |
), | |
starter_torque: 300 * units.lb_ft, | |
starter_speed: 1000 * units.rpm, | |
redline: 14000 * units.rpm, | |
fuel: fuel( | |
max_turbulence_effect: 1.0, | |
burning_efficiency_randomness: 0.2, | |
max_burning_efficiency: 1.0 | |
) | |
) | |
// idk | |
crankshaft c0( | |
throw: stroke_length / 2, | |
flywheel_mass: 2.3 * units.kg, | |
mass: 3 * units.kg, | |
friction_torque: 10.0 * units.Nm, | |
moment_of_inertia: 0.02, | |
position_x: 0.0, | |
position_y: 0.0, | |
tdc: timings.tdc_crankshaft | |
) | |
rod_journal rj0(angle: 0.0) | |
rod_journal rj1(angle: rod_journal_separation) | |
rod_journal rj2(angle: 0.0) | |
c0 | |
.add_rod_journal(rj0) | |
.add_rod_journal(rj1) | |
.add_rod_journal(rj2) | |
piston_parameters piston_params( | |
mass: 450.0 * units.g, | |
blowby: k_28inH2O(0.07), | |
compression_height: piston_compression_height, | |
wrist_pin_position: 0.0, | |
displacement: 0 * units.cc | |
) | |
connecting_rod_parameters cr_params( | |
mass: 380.0 * units.g, | |
moment_of_inertia: 0.0014, | |
center_of_mass: 0.0, | |
length: connecting_rod_length | |
) | |
cylinder_bank_parameters bank_params( | |
bore: bore_diameter, | |
deck_height: connecting_rod_length + piston_compression_height + stroke_length / 2 | |
) | |
// ?? | |
intake intake1( | |
plenum_volume: 2.5 * units.L, | |
plenum_cross_section_area: 20.0 * units.cm2, | |
intake_flow_rate: k_carb(800.0), | |
idle_flow_rate: k_carb(0.0), | |
idle_throttle_plate_position: 0.991, | |
throttle_gamma: 1.0 | |
) | |
// ?? copied from a Kawasaki Ninja 650R | |
exhaust_system_parameters es_params( | |
outlet_flow_rate: k_carb(700.0), | |
primary_tube_length: 10.0 * units.cm, | |
primary_flow_rate: k_carb(120.0), | |
velocity_decay: 0.4, | |
volume: 40.0 * units.L | |
) | |
exhaust_system exhaust0( | |
es_params, | |
audio_volume: 0.4, | |
impulse_response: ir_lib.default_0 | |
) | |
exhaust_system exhaust1( | |
es_params, | |
audio_volume: 0.2, | |
impulse_response: ir_lib.default_0 | |
) | |
exhaust_system exhaust2( | |
es_params, | |
audio_volume: 0.1, | |
impulse_response: ir_lib.default_0 | |
) | |
exhaust_system exhaust3( | |
es_params, | |
audio_volume: 0.1, | |
impulse_response: ir_lib.default_0 | |
) | |
cylinder_bank b0(bank_params, angle: -bank_separation / 2.0) | |
b0 | |
.add_cylinder( | |
piston: piston(piston_params), | |
connecting_rod: connecting_rod(cr_params), | |
rod_journal: rj0, | |
intake: intake1, | |
exhaust_system: exhaust0, | |
ignition_wire: wires.wire1 | |
) | |
.add_cylinder( | |
piston: piston(piston_params), | |
connecting_rod: connecting_rod(cr_params), | |
rod_journal: rj1, | |
intake: intake1, | |
exhaust_system: exhaust2, | |
ignition_wire: wires.wire3 | |
) | |
.add_cylinder( | |
piston: piston(piston_params), | |
connecting_rod: connecting_rod(cr_params), | |
rod_journal: rj2, | |
intake: intake1, | |
exhaust_system: exhaust1, | |
ignition_wire: wires.wire5 | |
) | |
cylinder_bank b1(bank_params, angle: bank_separation / 2.0) | |
b1 | |
.add_cylinder( | |
piston: piston(piston_params), | |
connecting_rod: connecting_rod(cr_params), | |
rod_journal: rj0, | |
intake: intake1, | |
exhaust_system: exhaust3, | |
ignition_wire: wires.wire2 | |
) | |
.add_cylinder( | |
piston: piston(piston_params), | |
connecting_rod: connecting_rod(cr_params), | |
rod_journal: rj2, | |
intake: intake1, | |
exhaust_system: exhaust3, | |
ignition_wire: wires.wire4 | |
) | |
engine | |
.add_cylinder_bank(b0) | |
.add_cylinder_bank(b1) | |
engine.add_crankshaft(c0) | |
v5_75_camshaft camshaft( | |
timings: timings | |
) | |
b0.set_cylinder_head ( | |
v5_75_head( | |
intake_camshaft: camshaft.intake_cam_0, | |
exhaust_camshaft: camshaft.exhaust_cam_0 | |
) | |
) | |
b1.set_cylinder_head ( | |
v5_75_head( | |
intake_camshaft: camshaft.intake_cam_1, | |
exhaust_camshaft: camshaft.exhaust_cam_1, | |
flip_display: true | |
) | |
) | |
// Timing curves are very exceptionally off, especially at higher RPMs | |
label timing_curve_offset(10 * units.deg) | |
label timing_curve_attenuation(1.20) | |
function timing_curve(1000 * units.rpm) | |
timing_curve | |
.add_sample(0 * units.rpm, (0 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(1000 * units.rpm, (10 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(2000 * units.rpm, (20 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(3000 * units.rpm, (30 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(4000 * units.rpm, (40 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(5000 * units.rpm, (50 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(6000 * units.rpm, (60 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(7000 * units.rpm, (70 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(8000 * units.rpm, (80 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(9000 * units.rpm, (85 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(10000 * units.rpm, (90 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(12000 * units.rpm, (93 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(13000 * units.rpm, (95 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(14000 * units.rpm, (99 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(15000 * units.rpm, (103 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
.add_sample(16000 * units.rpm, (107 * units.deg) * timing_curve_attenuation + timing_curve_offset) | |
engine.add_ignition_module( | |
v5_75_distributor( | |
wires: wires, | |
timing_curve: timing_curve, | |
rev_limit: 14000 * units.rpm, | |
timings: timings | |
) | |
) | |
} | |
public node RC211V_vehicle { | |
input mass: 200 * units.kg; | |
// Tire radius and cross section area approximated from: https://en.wikipedia.org/wiki/Honda_RC211V#Specifications | |
input cross_section_area: (600 * units.mm) * (1130 * units.mm); | |
input tire_radius: 21.0 * units.cm; | |
input drag_coefficient: 0.92; // Guessed drag coefficient between 0.5-1.0, typical of MotoGP bikes | |
input diff_ratio: 3.5; // ?? | |
input rolling_resistance: 25; | |
alias output __out: vehicle; | |
vehicle vehicle( | |
mass: mass, | |
diff_ratio: diff_ratio, | |
tire_radius: tire_radius, | |
drag_coefficient: drag_coefficient, | |
rolling_resistance: rolling_resistance | |
) | |
} | |
// Quick and dirty gear ratio derived from a Honda CB500K2 from https://ultimatemotorcycling.com/2019/12/18/motorcycle-gear-calculator-demystifies-gearing-ratios-and-calculated-top-speeds/ | |
// Works very badly, but it works. | |
public node RC211V_transmission { | |
alias output __out: trans; | |
transmission trans( | |
max_clutch_torque: 250.0 * units.Nm // random number idk | |
) | |
trans | |
.add_gear(3.5) | |
.add_gear(2.5) | |
.add_gear(2) | |
.add_gear(1.536) | |
.add_gear(1.2) | |
.add_gear(1.0) | |
} | |
public node RC211V_main { | |
input timings: v5_75_2004_timings(); | |
set_engine( | |
RC211V( | |
timings: timings | |
) | |
) | |
set_vehicle( | |
RC211V_vehicle() | |
) | |
set_transmission( | |
RC211V_transmission() | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment