void CARENGINEINFO::SetTorqueCurve( const btScalar redline, const std::vector<std::pair<btScalar, btScalar> > & torque) { torque_curve.Clear(); //this value accounts for the fact that the torque curves are usually measured // on a dyno, but we're interested in the actual crankshaft power const btScalar dyno_correction_factor = 1.0;//1.14; assert(torque.size() > 1); //ensure we have a smooth curve down to 0 RPM if (torque[0].first != 0) torque_curve.AddPoint(0,0); for (std::vector<std::pair<btScalar, btScalar> >::const_iterator i = torque.begin(); i != torque.end(); ++i) { torque_curve.AddPoint(i->first, i->second * dyno_correction_factor); } //ensure we have a smooth curve for over-revs torque_curve.AddPoint(torque[torque.size()-1].first + 10000, 0); //write out a debug torque curve file /*std::ofstream f("out.dat"); for (btScalar i = 0; i < curve[curve.size()-1].first+1000; i+= 20) f << i << " " << torque_curve.Interpolate(i) << std::endl;*/ //for (unsigned int i = 0; i < curve.size(); i++) f << curve[i].first << " " << curve[i].second << std::endl; //calculate engine friction btScalar max_power_angvel = redline*3.14153/30.0; btScalar max_power = torque_curve.Interpolate(redline) * max_power_angvel; friction = max_power / (max_power_angvel*max_power_angvel*max_power_angvel); //calculate idle throttle position for (idle = 0; idle < 1.0; idle += 0.01) { if (GetTorque(idle, start_rpm) > -GetFrictionTorque(start_rpm*3.141593/30.0, 1.0, idle)) { //std::cout << "Found idle throttle: " << idle << ", " << GetTorqueCurve(idle, start_rpm) << ", " << friction_torque << std::endl; break; } } }
bool CarEngineInfo::Load(const PTree & cfg, std::ostream & error_output) { std::vector<btScalar> pos(3, 0.0f); if (!cfg.get("displacement", displacement, error_output)) return false; if (!cfg.get("max-power", maxpower, error_output)) return false; if (!cfg.get("peak-engine-rpm", redline, error_output)) return false; if (!cfg.get("rpm-limit", rpm_limit, error_output)) return false; if (!cfg.get("inertia", inertia, error_output)) return false; if (!cfg.get("start-rpm", start_rpm, error_output)) return false; if (!cfg.get("stall-rpm", stall_rpm, error_output)) return false; if (!cfg.get("position", pos, error_output)) return false; if (!cfg.get("mass", mass, error_output)) return false; position.setValue(pos[0], pos[1], pos[2]); // fuel consumption btScalar fuel_heating_value = 4.5E7; // Ws/kg btScalar engine_efficiency = 0.35; cfg.get("fuel-heating-value", fuel_heating_value); cfg.get("efficiency", engine_efficiency); fuel_rate = 1 / (engine_efficiency * fuel_heating_value); // nos parameters cfg.get("nos-mass", nos_mass); cfg.get("nos-boost", nos_boost); cfg.get("nos-ratio", nos_fuel_ratio); // friction (Heywood 1988 tfmep) friction[0] = btScalar(97000 / (4 * M_PI)) * displacement; friction[1] = btScalar(15000 / (4 * M_PI)) * displacement; friction[2] = btScalar(5000 / (4 * M_PI)) * displacement; std::vector<btScalar> f(3, 0); if (cfg.get("torque-friction", f)) { friction[0] = f[0]; friction[1] = f[1]; friction[2] = f[2]; } // torque int curve_num = 0; std::vector<btScalar> torque_point(2); std::string torque_str("torque-curve-00"); std::vector<std::pair<btScalar, btScalar> > torque; while (cfg.get(torque_str, torque_point)) { torque.push_back(std::pair<btScalar, btScalar>(torque_point[0], torque_point[1])); curve_num++; std::ostringstream s; s << "torque-curve-"; s.width(2); s.fill('0'); s << curve_num; torque_str = s.str(); } if (torque.size() <= 1) { error_output << "You must define at least 2 torque curve points." << std::endl; return false; } // set torque curve torque_curve.Clear(); if (torque[0].first > stall_rpm) { btScalar dx = torque[1].first - torque[0].first; btScalar dy = torque[1].second - torque[0].second; btScalar stall_torque = dy / dx * (stall_rpm - torque[0].first) + torque[0].second; torque_curve.AddPoint(stall_rpm, stall_torque); error_output << "Torque curve begins above stall rpm.\n" << "Extrapolating to " << stall_rpm << ", " << stall_torque << std::endl; } for (const auto & tp : torque) { torque_curve.AddPoint(tp.first, tp.second); } if (torque[torque.size() - 1].first < rpm_limit) { btScalar r = torque[torque.size() - 1].first + 10000.0f; btScalar t = 0.0f; torque_curve.AddPoint(r , t); error_output << "Torque curve ends below rpm limit.\n" << "Extrapolating to " << r << ", " << t << std::endl; } // calculate idle throttle position for (idle_throttle = 0.0f; idle_throttle < 1.0f; idle_throttle += 0.01f) { if (GetTorque(idle_throttle, start_rpm) > -GetFrictionTorque(idle_throttle, start_rpm)) break; } // calculate idle throttle slope btScalar stall_throttle; for (stall_throttle = idle_throttle; stall_throttle < 1.0f; stall_throttle += 0.01f) { if (GetTorque(stall_throttle, stall_rpm) > -GetFrictionTorque(stall_throttle, stall_rpm)) break; } idle_throttle_slope = 1.5f * (idle_throttle - stall_throttle) / (start_rpm - stall_rpm); return true; }