Engine Simulatorの作法 その10

# 概要
Engine Simulatorの作法を調べてみた。
githubでエンジンジェネレータ見つけた。




# サンプルコード

```
def generate_v24():
	cylinders0 = []
	cylinders1 = []
	cylinders = []
	for i in range(12):
		cylinders0.append(i * 2)
		cylinders1.append(i * 2 + 1)
		cylinders += [i * 2, i * 2 + 1]
	b0 = engine_generator.Bank(cylinders0, -45)
	b1 = engine_generator.Bank(cylinders1, 45)
	engine = engine_generator.Engine([b0, b1], cylinders)
	engine.engine_name = "V24"
	engine.starter_torque = 400
	engine.crank_mass = 200
	engine.generate()
	engine.write_to_file("test.mr")

```

# 実行結果

```
import "engine_sim.mr"
units units()
constants constants()
impulse_response_library ir_lib()
private node wires {
	output wire0: ignition_wire();
	output wire1: ignition_wire();
	output wire2: ignition_wire();
	output wire3: ignition_wire();
	output wire4: ignition_wire();
	output wire5: ignition_wire();
	output wire6: ignition_wire();
	output wire7: ignition_wire();
	output wire8: ignition_wire();
	output wire9: ignition_wire();
	output wire10: ignition_wire();
	output wire11: ignition_wire();
	output wire12: ignition_wire();
	output wire13: ignition_wire();
	output wire14: ignition_wire();
	output wire15: ignition_wire();
	output wire16: ignition_wire();
	output wire17: ignition_wire();
	output wire18: ignition_wire();
	output wire19: ignition_wire();
	output wire20: ignition_wire();
	output wire21: ignition_wire();
	output wire22: ignition_wire();
	output wire23: ignition_wire();
}

private node generated_head {
	input intake_camshaft;
	input exhaust_camshaft;
	input chamber_volume: 300 * units.cc;
	input intake_runner_volume: 149.6 * units.cc;
	input intake_runner_cross_section_area: 1.75 * units.inch * 1.75 * units.inch;
	input exhaust_runner_volume: 50.0 * units.cc;
	input exhaust_runner_cross_section_area: 1.75 * units.inch * 1.75 * units.inch;
	input flow_attenuation: 1.0;
	input lift_scale: 1.0;
	input flip_display: false;
	alias output __out: head;
	function intake_flow(50 * units.thou)
	intake_flow
	.add_flow_sample(0 * lift_scale, 0 * flow_attenuation)
	.add_flow_sample(50 * lift_scale, 58 * flow_attenuation)
	.add_flow_sample(100 * lift_scale, 103 * flow_attenuation)
	.add_flow_sample(150 * lift_scale, 156 * flow_attenuation)
	.add_flow_sample(200 * lift_scale, 214 * flow_attenuation)
	.add_flow_sample(250 * lift_scale, 249 * flow_attenuation)
	.add_flow_sample(300 * lift_scale, 268 * flow_attenuation)
	.add_flow_sample(350 * lift_scale, 280 * flow_attenuation)
	.add_flow_sample(400 * lift_scale, 280 * flow_attenuation)
	.add_flow_sample(450 * lift_scale, 281 * flow_attenuation)

	function exhaust_flow(50 * units.thou)
	exhaust_flow
	.add_flow_sample(0 * lift_scale, 0 * flow_attenuation)
	.add_flow_sample(50 * lift_scale, 37 * flow_attenuation)
	.add_flow_sample(100 * lift_scale, 72 * flow_attenuation)
	.add_flow_sample(150 * lift_scale, 113 * flow_attenuation)
	.add_flow_sample(200 * lift_scale, 160 * flow_attenuation)
	.add_flow_sample(250 * lift_scale, 196 * flow_attenuation)
	.add_flow_sample(300 * lift_scale, 222 * flow_attenuation)
	.add_flow_sample(350 * lift_scale, 235 * flow_attenuation)
	.add_flow_sample(400 * lift_scale, 245 * flow_attenuation)
	.add_flow_sample(450 * lift_scale, 246 * flow_attenuation)

	generic_cylinder_head head(
		chamber_volume: chamber_volume,
		intake_runner_volume: intake_runner_volume,
		intake_runner_cross_section_area: intake_runner_cross_section_area,
		exhaust_runner_volume: exhaust_runner_volume,
		exhaust_runner_cross_section_area: exhaust_runner_cross_section_area,
		intake_port_flow: intake_flow,
		exhaust_port_flow: exhaust_flow,
		valvetrain: standard_valvetrain(
			intake_camshaft: intake_camshaft,
			exhaust_camshaft: exhaust_camshaft
		),
		flip_display: flip_display
	)
}

private node generated_camshaft {
	input lobe_profile;
	input intake_lobe_profile: lobe_profile;
	input exhaust_lobe_profile: lobe_profile;
	input lobe_separation: 114 * units.deg;
	input intake_lobe_center: lobe_separation;
	input exhaust_lobe_center: lobe_separation;  
	input advance: 0 * units.deg; 
	input base_radius: 0.5 * units.inch;
	output intake_cam_0: _intake_cam_0;
	output exhaust_cam_0: _exhaust_cam_0;

	output intake_cam_1: _intake_cam_1;
	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 _exhaust_cam_0(params, lobe_profile: exhaust_lobe_profile)

	camshaft _intake_cam_1(params, lobe_profile: intake_lobe_profile)
	camshaft _exhaust_cam_1(params, lobe_profile: exhaust_lobe_profile)
	label rot360(360 * units.deg)
	_exhaust_cam_0
		.add_lobe(rot360 - exhaust_lobe_center + 0.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 60.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 120.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 180.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 240.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 300.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 360.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 420.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 480.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 540.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 600.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 660.0 * units.deg)
	_intake_cam_0
		.add_lobe(rot360 + exhaust_lobe_center + 0.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 60.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 120.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 180.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 240.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 300.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 360.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 420.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 480.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 540.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 600.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 660.0 * units.deg)
	_exhaust_cam_1
		.add_lobe(rot360 - exhaust_lobe_center + 30.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 90.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 150.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 210.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 270.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 330.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 390.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 450.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 510.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 570.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 630.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 690.0 * units.deg)
	_intake_cam_1
		.add_lobe(rot360 + exhaust_lobe_center + 30.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 90.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 150.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 210.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 270.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 330.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 390.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 450.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 510.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 570.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 630.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 690.0 * units.deg)
}

public node generated_engine {
	alias output __out: engine;
	engine engine(
		name: "V24",
		starter_torque: 400 * units.lb_ft,
		starter_speed: 500 * units.rpm,
		redline: 8000 * units.rpm,
		throttle_gamma: 2.0,
		fuel: fuel(
			molecular_mass: 100 * units.g,
			energy_density: 48.1 * units.kJ / units.g,
			density: 0.755 * units.kg / units.L,
			molecular_afr: 12.5,
			max_burning_efficiency: 0.8,
			burning_efficiency_randomness: 0.5,
			low_efficiency_attenuation: 0.6,
			max_turbulence_effect: 2,
			max_dilution_effect: 10
		),
		hf_gain: 0.01,
		noise: 1.0,
		jitter: 0.1,
		simulation_frequency: 10000
	)

	wires wires()

	label stroke(86 * units.mm)
	label bore(86 * units.mm)
	label rod_length(120 * units.mm)
	label rod_mass(50 * units.g)
	label compression_height(25.4 * units.mm)
	label crank_mass(200 * units.kg)
	label flywheel_mass(10 * units.kg)
	label flywheel_radius(100 * units.mm)
	label crank_moment(
		disk_moment_of_inertia(mass: crank_mass, radius: stroke)
	)
	label flywheel_moment(
		disk_moment_of_inertia(mass: flywheel_mass, radius: flywheel_radius)
	)
	label other_moment( // Moment from cams, pulleys, etc [estimated]
		disk_moment_of_inertia(mass: 1 * units.kg, radius: 1.0 * units.cm)
	)

	crankshaft c0(
		throw: stroke / 2,
		flywheel_mass: flywheel_mass,
		mass: crank_mass,
		friction_torque: 1.0 * units.lb_ft,
		moment_of_inertia:
			crank_moment + flywheel_moment + other_moment,
		position_x: 0.0,
		position_y: 0.0,
		tdc: 45 * units.deg
	)

	rod_journal rj0(angle: 0 * units.deg)
	rod_journal rj1(angle: 120.0 * units.deg)
	rod_journal rj2(angle: 60.0 * units.deg)
	rod_journal rj3(angle: 180.0 * units.deg)
	rod_journal rj4(angle: 120.0 * units.deg)
	rod_journal rj5(angle: 240.0 * units.deg)
	rod_journal rj6(angle: 180.0 * units.deg)
	rod_journal rj7(angle: 300.0 * units.deg)
	rod_journal rj8(angle: 240.0 * units.deg)
	rod_journal rj9(angle: 360.0 * units.deg)
	rod_journal rj10(angle: 300.0 * units.deg)
	rod_journal rj11(angle: 420.0 * units.deg)
	rod_journal rj12(angle: 360.0 * units.deg)
	rod_journal rj13(angle: 480.0 * units.deg)
	rod_journal rj14(angle: 420.0 * units.deg)
	rod_journal rj15(angle: 540.0 * units.deg)
	rod_journal rj16(angle: 480.0 * units.deg)
	rod_journal rj17(angle: 600.0 * units.deg)
	rod_journal rj18(angle: 540.0 * units.deg)
	rod_journal rj19(angle: 660.0 * units.deg)
	rod_journal rj20(angle: 600.0 * units.deg)
	rod_journal rj21(angle: 720.0 * units.deg)
	rod_journal rj22(angle: 660.0 * units.deg)
	rod_journal rj23(angle: 780.0 * units.deg)
	c0
		.add_rod_journal(rj0)
		.add_rod_journal(rj1)
		.add_rod_journal(rj2)
		.add_rod_journal(rj3)
		.add_rod_journal(rj4)
		.add_rod_journal(rj5)
		.add_rod_journal(rj6)
		.add_rod_journal(rj7)
		.add_rod_journal(rj8)
		.add_rod_journal(rj9)
		.add_rod_journal(rj10)
		.add_rod_journal(rj11)
		.add_rod_journal(rj12)
		.add_rod_journal(rj13)
		.add_rod_journal(rj14)
		.add_rod_journal(rj15)
		.add_rod_journal(rj16)
		.add_rod_journal(rj17)
		.add_rod_journal(rj18)
		.add_rod_journal(rj19)
		.add_rod_journal(rj20)
		.add_rod_journal(rj21)
		.add_rod_journal(rj22)
		.add_rod_journal(rj23)

	piston_parameters piston_params(
		mass: (50) * units.g, // 414 - piston mass, 152 - pin weight
		compression_height: compression_height,
		wrist_pin_position: 0.0,
		displacement: 0.0
	)

	connecting_rod_parameters cr_params(
		mass: rod_mass,
		moment_of_inertia: rod_moment_of_inertia(
			mass: rod_mass,
			length: rod_length
		),
		center_of_mass: 0.0,
		length: rod_length
	)
	intake intake(
		plenum_volume: 1.325 * units.L,
		plenum_cross_section_area: 20.0 * units.cm2,
		intake_flow_rate: k_carb(3000),
		runner_flow_rate: k_carb(400),
		runner_length: 16 * units.inch,
		idle_flow_rate: k_carb(0),
		idle_throttle_plate_position: 0.999,
		velocity_decay: 0.5
	)
	exhaust_system_parameters es_params(
		outlet_flow_rate: k_carb(2000.0),
		primary_tube_length: 20.0 * units.inch,
		primary_flow_rate: k_carb(200.0),
		velocity_decay: 0.5
	)
	exhaust_system exhaust0(
		es_params,
		audio_volume: 1.0 * 0.004,
		length: 20 * units.inch,
		impulse_response: ir_lib.minimal_muffling_01
	)

	exhaust_system exhaust1(
		es_params,
		audio_volume: 1.0 * 0.004,
		length: 20 * units.inch,
		impulse_response: ir_lib.minimal_muffling_01
	)

	cylinder_bank_parameters bank_params(
		bore: bore,
		deck_height: stroke / 2 + rod_length + compression_height
	)

	label spacing(0.0)
	cylinder_bank b0(bank_params, angle: -45 * units.deg)
	cylinder_bank b1(bank_params, angle: 45 * units.deg)
	b0
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj0,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire0,
			sound_attenuation: 0.5027812953174294,
			primary_length: 0 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj2,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire2,
			sound_attenuation: 0.5262381615363307,
			primary_length: 1 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj4,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire4,
			sound_attenuation: 0.6879159190318933,
			primary_length: 2 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj6,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire6,
			sound_attenuation: 0.8642684740175068,
			primary_length: 3 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj8,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire8,
			sound_attenuation: 0.9492824427635287,
			primary_length: 4 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj10,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire10,
			sound_attenuation: 0.8186770388332751,
			primary_length: 5 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj12,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire12,
			sound_attenuation: 0.9509565597875904,
			primary_length: 6 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj14,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire14,
			sound_attenuation: 0.6510117179395135,
			primary_length: 7 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj16,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire16,
			sound_attenuation: 0.5025200665515671,
			primary_length: 8 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj18,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire18,
			sound_attenuation: 0.5197687139895135,
			primary_length: 9 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj20,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire20,
			sound_attenuation: 0.8225371463351094,
			primary_length: 10 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj22,
			intake: intake,
			exhaust_system: exhaust0,
			ignition_wire: wires.wire22,
			sound_attenuation: 0.8061683004294194,
			primary_length: 11 * spacing * 0.5 * units.cm
		)
		.set_cylinder_head(
			generated_head(
				intake_camshaft: camshaft.intake_cam_0,
				exhaust_camshaft: camshaft.exhaust_cam_0,
				flip_display: false,
				flow_attenuation: 1.0)
		)

	b1
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj1,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire1,
			sound_attenuation: 0.6226817979660249,
			primary_length: 0 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj3,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire3,
			sound_attenuation: 0.8986949944372207,
			primary_length: 1 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj5,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire5,
			sound_attenuation: 0.6661950279876369,
			primary_length: 2 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj7,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire7,
			sound_attenuation: 0.6386158120694707,
			primary_length: 3 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj9,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire9,
			sound_attenuation: 0.6097715176062415,
			primary_length: 4 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj11,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire11,
			sound_attenuation: 0.9397221296627916,
			primary_length: 5 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj13,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire13,
			sound_attenuation: 0.7790958180183185,
			primary_length: 6 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj15,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire15,
			sound_attenuation: 0.8750545854349073,
			primary_length: 7 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj17,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire17,
			sound_attenuation: 0.7249514596866518,
			primary_length: 8 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj19,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire19,
			sound_attenuation: 0.9854332222818465,
			primary_length: 9 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj21,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire21,
			sound_attenuation: 0.7535810442178106,
			primary_length: 10 * spacing * 0.5 * units.cm
		)
		.add_cylinder(
			piston: piston(piston_params, blowby: k_28inH2O(0.0)),
			connecting_rod: connecting_rod(cr_params),
			rod_journal: rj23,
			intake: intake,
			exhaust_system: exhaust1,
			ignition_wire: wires.wire23,
			sound_attenuation: 0.5019456752766771,
			primary_length: 11 * spacing * 0.5 * units.cm
		)
		.set_cylinder_head(
			generated_head(
				intake_camshaft: camshaft.intake_cam_1,
				exhaust_camshaft: camshaft.exhaust_cam_1,
				flip_display: false,
				flow_attenuation: 1.0)
		)

	engine
		.add_cylinder_bank(b0)
		.add_cylinder_bank(b1)

	engine.add_crankshaft(c0)

	harmonic_cam_lobe intake_lobe(
		duration_at_50_thou: 234 * units.deg,
		gamma: 1.1,
		lift: 551 * units.thou,
		steps: 512
	)
	harmonic_cam_lobe exhaust_lobe(
		duration_at_50_thou: 235 * units.deg,
		gamma: 1.1,
		lift: 551 * units.thou,
		steps: 512
	)

	generated_camshaft camshaft(
		lobe_profile: "N/A",
		intake_lobe_profile: intake_lobe,
		exhaust_lobe_profile: exhaust_lobe,
		intake_lobe_center: 90 * units.deg,
		exhaust_lobe_center: 112 * units.deg
	)

	function timing_curve(1000 * units.rpm)
	timing_curve
		.add_sample(0 * units.rpm, 18 * units.deg)
		.add_sample(1000 * units.rpm, 40 * units.deg)
		.add_sample(2000 * units.rpm, 40 * units.deg)
		.add_sample(3000 * units.rpm, 40 * units.deg)
		.add_sample(4000 * units.rpm, 40 * units.deg)
		.add_sample(5000 * units.rpm, 40 * units.deg)
		.add_sample(6000 * units.rpm, 40 * units.deg)
		.add_sample(7000 * units.rpm, 40 * units.deg)
		.add_sample(8000 * units.rpm, 40 * units.deg)
		.add_sample(9000 * units.rpm, 40 * units.deg)

	ignition_module ignition_module(
		timing_curve: timing_curve,
		rev_limit: 9000 * units.rpm,
		limiter_duration: 0.1)

	ignition_module
			.connect_wire(wires.wire0, 0.0 * units.deg)
			.connect_wire(wires.wire1, 30.0 * units.deg)
			.connect_wire(wires.wire2, 60.0 * units.deg)
			.connect_wire(wires.wire3, 90.0 * units.deg)
			.connect_wire(wires.wire4, 120.0 * units.deg)
			.connect_wire(wires.wire5, 150.0 * units.deg)
			.connect_wire(wires.wire6, 180.0 * units.deg)
			.connect_wire(wires.wire7, 210.0 * units.deg)
			.connect_wire(wires.wire8, 240.0 * units.deg)
			.connect_wire(wires.wire9, 270.0 * units.deg)
			.connect_wire(wires.wire10, 300.0 * units.deg)
			.connect_wire(wires.wire11, 330.0 * units.deg)
			.connect_wire(wires.wire12, 360.0 * units.deg)
			.connect_wire(wires.wire13, 390.0 * units.deg)
			.connect_wire(wires.wire14, 420.0 * units.deg)
			.connect_wire(wires.wire15, 450.0 * units.deg)
			.connect_wire(wires.wire16, 480.0 * units.deg)
			.connect_wire(wires.wire17, 510.0 * units.deg)
			.connect_wire(wires.wire18, 540.0 * units.deg)
			.connect_wire(wires.wire19, 570.0 * units.deg)
			.connect_wire(wires.wire20, 600.0 * units.deg)
			.connect_wire(wires.wire21, 630.0 * units.deg)
			.connect_wire(wires.wire22, 660.0 * units.deg)
			.connect_wire(wires.wire23, 690.0 * units.deg)

	engine.add_ignition_module(ignition_module)
}

private node generated_vehicle {
	alias output __out:
		vehicle(
			mass: 798 * units.kg,
			drag_coefficient: 0.9,
			cross_sectional_area: (72 * units.inch) * (36 * units.inch),
			diff_ratio: 4.1,
			tire_radius: 9 * units.inch,
			rolling_resistance: 200 * units.N
		);
}

private node generated_transmission {
	alias output __out:
		transmission(
			max_clutch_torque: 1000 * units.lb_ft
		)
	.add_gear(2.8)
	.add_gear(2.29)
	.add_gear(1.93)
	.add_gear(1.583)
	.add_gear(1.375)
	.add_gear(1.19);
}

public node main {
	run(
		engine: generated_engine(),
		vehicle: generated_vehicle(),
		transmission: generated_transmission()
	)
}
main()

```

# 成果物

https://paiza.io/projects/oqEfl0hZS-hPflvFstdYcw

以上。