0
0

概要

Engine Simulatorの作法を調べてみた。
githubでエンジンジェネレータ見つけた。
練習問題やってみた。

練習問題

90度V型4気筒エンジンを作れ。

写真

image.png

サンプルコード


def generate_v4():
	cylinders0 = []
	cylinders1 = []
	cylinders = []
	for i in range(2):
		cylinders0.append(i * 2)
		cylinders1.append(i * 2 + 1)
		cylinders += [i * 2, i * 2 + 1]
	b0 = Bank(cylinders0, -45)
	b1 = Bank(cylinders1, 45)
	engine = Engine([b0, b1], cylinders)
	engine.engine_name = "V4"
	engine.starter_torque = 400
	engine.crank_mass = 200
	engine.generate()
	engine.write_to_console()


if __name__ == "__main__":
	generate_v4()



実行結果

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();
}

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 + 360.0 * units.deg)
	_intake_cam_0
		.add_lobe(rot360 + exhaust_lobe_center + 0.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 360.0 * units.deg)
	_exhaust_cam_1
		.add_lobe(rot360 - exhaust_lobe_center + 180.0 * units.deg)
		.add_lobe(rot360 - exhaust_lobe_center + 540.0 * units.deg)
	_intake_cam_1
		.add_lobe(rot360 + exhaust_lobe_center + 180.0 * units.deg)
		.add_lobe(rot360 + exhaust_lobe_center + 540.0 * units.deg)
}

public node generated_engine {
	alias output __out: engine;
	engine engine(
		name: "V4",
		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: 270.0 * units.deg)
	rod_journal rj2(angle: 360.0 * units.deg)
	rod_journal rj3(angle: 630.0 * units.deg)
	c0
		.add_rod_journal(rj0)
		.add_rod_journal(rj1)
		.add_rod_journal(rj2)
		.add_rod_journal(rj3)

	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.6587159145903814,
			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.9289523204327862,
			primary_length: 1 * 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.9559828716777936,
			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.6603449645782972,
			primary_length: 1 * 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, 180.0 * units.deg)
			.connect_wire(wires.wire2, 360.0 * units.deg)
			.connect_wire(wires.wire3, 540.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()

成果物

以上。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0