import "engine_sim.mr" // TVR Cerbera Speed Eight AJP8 by GearheadLydia // with support from /u/pdm8 // revision 2 | 2022-11-03 units units() constants constants() impulse_response_library ir_lib() label cycle(2 * 360 * units.deg) // firing order: 14527638 (deduced from engine rebuild manual) label rot15(15 * units.deg) public node tvr_ajp8_distributor { input wires; input timing_curve; input rev_limit: 8250 * units.rpm; input limiter_duration: 0.06; alias output __out: ignition_module(timing_curve: timing_curve, rev_limit: rev_limit, limiter_duration: limiter_duration) .connect_wire(wires.wire1, (0.0 / 8.0) * cycle) .connect_wire(wires.wire4, (1.0 / 8.0) * cycle + rot15) .connect_wire(wires.wire5, (2.0 / 8.0) * cycle) .connect_wire(wires.wire2, (3.0 / 8.0) * cycle + rot15) .connect_wire(wires.wire7, (4.0 / 8.0) * cycle) .connect_wire(wires.wire6, (5.0 / 8.0) * cycle + rot15) .connect_wire(wires.wire3, (6.0 / 8.0) * cycle) .connect_wire(wires.wire8, (7.0 / 8.0) * cycle + rot15); } private node wires { output wire2: ignition_wire(); output wire4: ignition_wire(); output wire6: ignition_wire(); output wire8: ignition_wire(); output wire7: ignition_wire(); output wire5: ignition_wire(); output wire3: ignition_wire(); output wire1: ignition_wire(); } public node tvr_ajp8_lobe_profile_int { alias output __out: harmonic_cam_lobe( duration_at_50_thou: 240 * units.deg, gamma: 1.0, lift: 12.0 * units.mm, steps: 100 ); } public node tvr_ajp8_lobe_profile_exh { alias output __out: harmonic_cam_lobe( duration_at_50_thou: 240 * units.deg, gamma: 1.0, lift: 12.0 * units.mm, steps: 100 ); } public node tvr_ajp8_camshaft_builder { input in_lobe_profile: tvr_ajp8_lobe_profile_int(); input ex_lobe_profile: tvr_ajp8_lobe_profile_exh(); input intake_lobe_profile: in_lobe_profile; input exhaust_lobe_profile: ex_lobe_profile; input lobe_separation: 80.0 * units.deg; input intake_lobe_center: lobe_separation; input exhaust_lobe_center: lobe_separation; input advance: 0.0 * units.deg; input base_radius: 15 * units.mm; 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 rot90(90 * units.deg) label rot360(360 * units.deg) // firing order: 14527638 (deduced from engine rebuild manual) _intake_cam_0 .add_lobe(rot360 + intake_lobe_center + 0 * rot90) .add_lobe(rot360 + intake_lobe_center + 6 * rot90) .add_lobe(rot360 + intake_lobe_center + 2 * rot90) .add_lobe(rot360 + intake_lobe_center + 4 * rot90) _intake_cam_1 .add_lobe(rot360 + intake_lobe_center + 3 * rot90 + rot15) .add_lobe(rot360 + intake_lobe_center + 1 * rot90 + rot15) .add_lobe(rot360 + intake_lobe_center + 5 * rot90 + rot15) .add_lobe(rot360 + intake_lobe_center + 7 * rot90 + rot15) _exhaust_cam_0 .add_lobe(rot360 - exhaust_lobe_center + 0 * rot90) .add_lobe(rot360 - exhaust_lobe_center + 6 * rot90) .add_lobe(rot360 - exhaust_lobe_center + 2 * rot90) .add_lobe(rot360 - exhaust_lobe_center + 4 * rot90) _exhaust_cam_1 .add_lobe(rot360 - exhaust_lobe_center + 3 * rot90 + rot15) .add_lobe(rot360 - exhaust_lobe_center + 1 * rot90 + rot15) .add_lobe(rot360 - exhaust_lobe_center + 5 * rot90 + rot15) .add_lobe(rot360 - exhaust_lobe_center + 7 * rot90 + rot15) } private node add_flow_sample { input lift; input flow; input this; alias output __out: this; this.add_sample(lift * units.thou, k_28inH2O(flow)) } public node tvr_ajp8_head { input intake_camshaft; input exhaust_camshaft; input chamber_volume: 57.0 * units.cc; input flip_display: false; input flow_attenuation_in: 0.74; input flow_attenuation_ex: 0.74; input lift_scale: 50.0; alias output __out: head; function intake_flow(1.0 * units.mm) intake_flow .add_flow_sample( 0 * lift_scale, 0 * flow_attenuation_in) .add_flow_sample( 1 * lift_scale, 30 * flow_attenuation_in) .add_flow_sample( 2 * lift_scale, 60 * flow_attenuation_in) .add_flow_sample( 3 * lift_scale, 90 * flow_attenuation_in) .add_flow_sample( 4 * lift_scale, 125 * flow_attenuation_in) .add_flow_sample( 5 * lift_scale, 160 * flow_attenuation_in) .add_flow_sample( 6 * lift_scale, 195 * flow_attenuation_in) .add_flow_sample( 7 * lift_scale, 210 * flow_attenuation_in) .add_flow_sample( 8 * lift_scale, 235 * flow_attenuation_in) .add_flow_sample( 9 * lift_scale, 270 * flow_attenuation_in) .add_flow_sample(10 * lift_scale, 305 * flow_attenuation_in) .add_flow_sample(11 * lift_scale, 320 * flow_attenuation_in) .add_flow_sample(12 * lift_scale, 335 * flow_attenuation_in) function exhaust_flow(1.0 * units.mm) exhaust_flow .add_flow_sample( 0 * lift_scale, 0 * flow_attenuation_ex) .add_flow_sample( 1 * lift_scale, 30 * flow_attenuation_ex) .add_flow_sample( 2 * lift_scale, 55 * flow_attenuation_ex) .add_flow_sample( 3 * lift_scale, 85 * flow_attenuation_ex) .add_flow_sample( 4 * lift_scale, 115 * flow_attenuation_ex) .add_flow_sample( 5 * lift_scale, 140 * flow_attenuation_ex) .add_flow_sample( 6 * lift_scale, 160 * flow_attenuation_ex) .add_flow_sample( 7 * lift_scale, 180 * flow_attenuation_ex) .add_flow_sample( 8 * lift_scale, 205 * flow_attenuation_ex) .add_flow_sample( 9 * lift_scale, 220 * flow_attenuation_ex) .add_flow_sample(10 * lift_scale, 240 * flow_attenuation_ex) .add_flow_sample(11 * lift_scale, 260 * flow_attenuation_ex) .add_flow_sample(12 * lift_scale, 280 * flow_attenuation_ex) cylinder_head head( chamber_volume: chamber_volume, intake_runner_volume: circle_area(0.9 * units.inch) * 9 * units.inch, intake_runner_cross_section_area: circle_area(0.9 * units.inch), exhaust_runner_volume: circle_area(0.9 * units.inch) * 6 * units.inch, exhaust_runner_cross_section_area: circle_area(0.9 * units.inch), intake_port_flow: intake_flow, exhaust_port_flow: exhaust_flow, intake_camshaft: intake_camshaft, exhaust_camshaft: exhaust_camshaft, flip_display: flip_display ) } public node ajp8 { alias output __out: engine; wires wires() engine engine( name: "TVR AJP8", starter_torque: 400 * units.lb_ft, starter_speed: 800 * units.rpm, redline: 8000 * units.rpm, fuel: fuel( max_turbulence_effect: 4.0, burning_efficiency_randomness: 0.2, max_burning_efficiency: 0.85), throttle_gamma: 1.0, hf_gain: 0.2, jitter: 0.5 ) label bore(91.0 * units.mm) label stroke(86.0 * units.mm) label rod_length(144.0 * units.mm) label rod_mass(621.5 * units.g) label piston_mass(400 * units.g) label compression_height(25.00 * units.mm) label piston_dome(5.00 * units.cc) label deck_clearance(0.5 * units.mm) label crank_mass(41 * units.lb) label flywheel_mass(29 * 2 * units.lb) label flywheel_radius(6 * units.inch) label crank_moment( disk_moment_of_inertia(mass: crank_mass, radius: stroke / 2) ) 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: 20 * units.kg, radius: 8.0 * units.cm) ) crankshaft c0( throw: stroke / 2, flywheel_mass: flywheel_mass, mass: crank_mass, friction_torque: 5.0 * units.lb_ft, moment_of_inertia: crank_moment + flywheel_moment + other_moment, position_x: 0.0, position_y: 0.0, tdc: 52.5 * units.deg // -37.5 degrees ) rod_journal rj0(angle: 0.0 * units.deg) rod_journal rj1(angle: 180.0 * units.deg) rod_journal rj2(angle: 180.0 * units.deg) rod_journal rj3(angle: 0.0 * units.deg) c0 .add_rod_journal(rj0) .add_rod_journal(rj1) .add_rod_journal(rj2) .add_rod_journal(rj3) // piston specs are guesses piston_parameters piston_params( mass: piston_mass, //blowby: 0, compression_height: compression_height, wrist_pin_position: 0 * units.mm, displacement: piston_dome ) 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 ) cylinder_bank_parameters bank_params( bore: bore, deck_height: stroke / 2 + rod_length + compression_height + deck_clearance ) intake intake( plenum_volume: 2.0 * units.L, plenum_cross_section_area: 100.0 * units.cm2, intake_flow_rate: k_carb(800), idle_flow_rate: k_carb(0.001), idle_throttle_plate_position: 0.996, throttle_gamma: 1.0, runner_flow_rate: k_carb(550.0), runner_length: 9 * units.inch, velocity_decay: 0.1 ) label exhaust_radius((3.5 * units.inch)/2) exhaust_system_parameters es_params_L( outlet_flow_rate: k_carb(600.0), primary_tube_length: 5.0 * units.inch, primary_flow_rate: k_carb(450.0), velocity_decay: 1.0, //0.5 collector_cross_section_area: circle_area(exhaust_radius), length: 550 * units.mm, volume: 550 * units.mm * circle_area(exhaust_radius) ) exhaust_system_parameters es_params_R( outlet_flow_rate: k_carb(600.0), primary_tube_length: 5.0 * units.inch, primary_flow_rate: k_carb(450.0), velocity_decay: 1.0, //0.5 collector_cross_section_area: circle_area(exhaust_radius), length: 400 * units.mm, volume: 400 * units.mm * circle_area(exhaust_radius) ) exhaust_system exhaustL(es_params_L, audio_volume: 1.0 * 0.01, impulse_response: ir_lib.default_0) exhaust_system exhaustR(es_params_R, audio_volume: 1.0 * 0.01, impulse_response: ir_lib.default_0) cylinder_bank b0(bank_params, angle: -27.5 * units.deg) // R (first) b0 .add_cylinder( piston: piston(piston_params, blowby: k_28inH2O(0.1)), connecting_rod: connecting_rod(cr_params), rod_journal: rj0, ignition_wire: wires.wire1, intake: intake, exhaust_system: exhaustR, primary_length: 5.0 * units.inch, sound_attenuation: 0.4 ) .add_cylinder( piston: piston(piston_params, blowby: k_28inH2O(0.1)), connecting_rod: connecting_rod(cr_params), rod_journal: rj1, ignition_wire: wires.wire3, intake: intake, exhaust_system: exhaustR, primary_length: 3.5 * units.inch, sound_attenuation: 0.6 ) .add_cylinder( piston: piston(piston_params, blowby: k_28inH2O(0.1)), connecting_rod: connecting_rod(cr_params), rod_journal: rj2, ignition_wire: wires.wire5, intake: intake, exhaust_system: exhaustR, primary_length: 2.2 * units.inch, sound_attenuation: 0.6 ) .add_cylinder( piston: piston(piston_params, blowby: k_28inH2O(0.1)), connecting_rod: connecting_rod(cr_params), rod_journal: rj3, ignition_wire: wires.wire7, intake: intake, exhaust_system: exhaustR, primary_length: 2.0 * units.inch, sound_attenuation: 0.4 ) cylinder_bank b1(bank_params, angle: 27.5 * units.deg) // L (second) b1 .add_cylinder( piston: piston(piston_params, blowby: k_28inH2O(0.1)), connecting_rod: connecting_rod(cr_params), rod_journal: rj0, ignition_wire: wires.wire2, intake: intake, exhaust_system: exhaustL, primary_length: 3.0 * units.inch, sound_attenuation: 0.3 ) .add_cylinder( piston: piston(piston_params, blowby: k_28inH2O(0.1)), connecting_rod: connecting_rod(cr_params), rod_journal: rj1, ignition_wire: wires.wire4, intake: intake, exhaust_system: exhaustL, primary_length: 1.5 * units.inch, sound_attenuation: 1.0 ) .add_cylinder( piston: piston(piston_params, blowby: k_28inH2O(0.1)), connecting_rod: connecting_rod(cr_params), rod_journal: rj2, ignition_wire: wires.wire6, intake: intake, exhaust_system: exhaustL, primary_length: 0.2 * units.inch, sound_attenuation: 1.0 ) .add_cylinder( piston: piston(piston_params, blowby: k_28inH2O(0.1)), connecting_rod: connecting_rod(cr_params), rod_journal: rj3, ignition_wire: wires.wire8, intake: intake, exhaust_system: exhaustL, primary_length: 0.0 * units.inch, sound_attenuation: 0.3 ) engine .add_cylinder_bank(b0) .add_cylinder_bank(b1) engine.add_crankshaft(c0) tvr_ajp8_camshaft_builder camshaft( in_lobe_profile: tvr_ajp8_lobe_profile_int(), ex_lobe_profile: tvr_ajp8_lobe_profile_exh() ) b0.set_cylinder_head ( tvr_ajp8_head( intake_camshaft: camshaft.intake_cam_0, exhaust_camshaft: camshaft.exhaust_cam_0, flip_display: false ) ) b1.set_cylinder_head ( tvr_ajp8_head( intake_camshaft: camshaft.intake_cam_1, exhaust_camshaft: camshaft.exhaust_cam_1, flip_display: true ) ) function timing_curve(1000 * units.rpm) timing_curve .add_sample(0000 * units.rpm, 20 * units.deg) .add_sample(1000 * units.rpm, 40 * units.deg) .add_sample(2000 * units.rpm, 45 * units.deg) .add_sample(3000 * units.rpm, 50 * units.deg) .add_sample(4000 * units.rpm, 55 * units.deg) .add_sample(5000 * units.rpm, 60 * units.deg) .add_sample(6000 * units.rpm, 65 * units.deg) .add_sample(7000 * units.rpm, 70 * units.deg) .add_sample(8000 * units.rpm, 72 * units.deg) .add_sample(9000 * units.rpm, 72 * units.deg) engine.add_ignition_module( tvr_ajp8_distributor( wires: wires, timing_curve: timing_curve, rev_limit: 8250 * units.rpm ) ) } // 2000 TVR Cerbera Speed Eight public node tvr_cerbera_speed_eight_vehicle { alias output __out: vehicle( mass: 1100 * units.kg, drag_coefficient: 0.35, cross_sectional_area: 2.25 * (units.m * units.m), diff_ratio: 3.45, tire_radius: 317.5 * units.mm, // 255/35R18 rolling_resistance: 500 * units.N ); } public node tvr_cerbera_speed_eight_transmission { alias output __out: transmission( max_clutch_torque: 700 * units.lb_ft ) .add_gear(2.95) .add_gear(1.95) .add_gear(1.34) .add_gear(1.00) .add_gear(0.80); } public node main { set_engine(ajp8()) set_vehicle(tvr_cerbera_speed_eight_vehicle()) set_transmission(tvr_cerbera_speed_eight_transmission()) }