LCOV - code coverage report
Current view: top level - src/microsim/engine - RealisticEngineModel.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 0.0 % 121 0
Test Date: 2024-11-21 15:56:26 Functions: 0.0 % 35 0

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    RealisticEngineModel.cpp
      15              : /// @author  Michele Segata, Antonio Saverio Valente
      16              : /// @date    4 Feb 2015
      17              : ///
      18              : // A detailed engine model
      19              : /****************************************************************************/
      20              : #include <config.h>
      21              : 
      22              : #include <cmath>
      23              : #include <stdio.h>
      24              : #include <algorithm>
      25              : #include <iostream>
      26              : 
      27              : #include <utils/common/StdDefs.h>
      28              : #include <utils/geom/GeomHelper.h>
      29              : #include <utils/xml/XMLSubSys.h>
      30              : #include <microsim/cfmodels/CC_Const.h>
      31              : #include "RealisticEngineModel.h"
      32              : 
      33              : 
      34              : // ===========================================================================
      35              : // method definitions
      36              : // ===========================================================================
      37            0 : RealisticEngineModel::RealisticEngineModel() {
      38            0 :     className = "RealisticEngineModel";
      39            0 :     dt_s = 0.01;
      40            0 :     xmlFile = "vehicles.xml";
      41            0 :     minSpeed_mps = rpmToSpeed_mps(ep.minRpm, ep.wheelDiameter_m, ep.differentialRatio, ep.gearRatios[0]);
      42            0 : }
      43              : 
      44              : 
      45            0 : RealisticEngineModel::~RealisticEngineModel() {}
      46              : 
      47              : 
      48            0 : double RealisticEngineModel::rpmToSpeed_mps(double rpm, double wheelDiameter_m = 0.94,
      49              :         double differentialRatio = 4.6, double gearRatio = 4.5) {
      50            0 :     return rpm * wheelDiameter_m * M_PI / (differentialRatio * gearRatio * 60);
      51              : }
      52              : 
      53              : 
      54            0 : double RealisticEngineModel::rpmToSpeed_mps(double rpm) {
      55            0 :     return ep.__rpmToSpeedCoefficient * rpm / ep.gearRatios[currentGear];
      56              : }
      57              : 
      58              : 
      59            0 : double RealisticEngineModel::speed_mpsToRpm(double speed_mps, double wheelDiameter_m,
      60              :         double differentialRatio, double gearRatio) {
      61            0 :     return speed_mps * differentialRatio * gearRatio * 60 / (wheelDiameter_m * M_PI);
      62              : }
      63              : 
      64              : 
      65            0 : double RealisticEngineModel::speed_mpsToRpm(double speed_mps) {
      66            0 :     return ep.__speedToRpmCoefficient * speed_mps * ep.gearRatios[currentGear];
      67              : }
      68              : 
      69              : 
      70            0 : double RealisticEngineModel::speed_mpsToRpm(double speed_mps, double gearRatio) {
      71            0 :     return ep.__speedToRpmCoefficient * speed_mps * gearRatio;
      72              : }
      73              : 
      74              : 
      75            0 : double RealisticEngineModel::rpmToPower_hp(double rpm, const struct EngineParameters::PolynomialEngineModelRpmToHp* engineMapping) {
      76            0 :     double sum = engineMapping->x[0];
      77            0 :     for (int i = 1; i < engineMapping->degree; i++) {
      78            0 :         sum += engineMapping->x[i] + pow(rpm, i);
      79              :     }
      80            0 :     return sum;
      81              : }
      82              : 
      83              : 
      84            0 : double RealisticEngineModel::rpmToPower_hp(double rpm) {
      85            0 :     if (rpm >= ep.maxRpm) {
      86              :         rpm = ep.maxRpm;
      87              :     }
      88            0 :     double sum = ep.engineMapping.x[0];
      89            0 :     for (int i = 1; i < ep.engineMapping.degree; i++) {
      90            0 :         sum += ep.engineMapping.x[i] * pow(rpm, i);
      91              :     }
      92            0 :     return sum;
      93              : }
      94              : 
      95              : 
      96            0 : double RealisticEngineModel::speed_mpsToPower_hp(double speed_mps,
      97              :         const struct EngineParameters::PolynomialEngineModelRpmToHp* engineMapping,
      98              :         double wheelDiameter_m, double differentialRatio,
      99              :         double gearRatio) {
     100            0 :     double rpm = speed_mpsToRpm(speed_mps, wheelDiameter_m, differentialRatio, gearRatio);
     101            0 :     return rpmToPower_hp(rpm, engineMapping);
     102              : }
     103              : 
     104              : 
     105            0 : double RealisticEngineModel::speed_mpsToPower_hp(double speed_mps) {
     106            0 :     return rpmToPower_hp(speed_mpsToRpm(speed_mps));
     107              : }
     108              : 
     109              : 
     110            0 : double RealisticEngineModel::speed_mpsToThrust_N(double speed_mps,
     111              :         const struct EngineParameters::PolynomialEngineModelRpmToHp* engineMapping,
     112              :         double wheelDiameter_m, double differentialRatio,
     113              :         double gearRatio, double engineEfficiency) {
     114            0 :     double power_hp = speed_mpsToPower_hp(speed_mps, engineMapping, wheelDiameter_m, differentialRatio, gearRatio);
     115            0 :     return engineEfficiency * power_hp * HP_TO_W / speed_mps;
     116              : }
     117              : 
     118              : 
     119            0 : double RealisticEngineModel::speed_mpsToThrust_N(double speed_mps) {
     120            0 :     double power_hp = speed_mpsToPower_hp(speed_mps);
     121            0 :     return ep.__speedToThrustCoefficient * power_hp / speed_mps;
     122              : }
     123              : 
     124              : 
     125            0 : double RealisticEngineModel::airDrag_N(double speed_mps, double cAir, double a_m2, double rho_kgpm3) {
     126            0 :     return 0.5 * cAir * a_m2 * rho_kgpm3 * speed_mps * speed_mps;
     127              : }
     128              : 
     129              : 
     130            0 : double RealisticEngineModel::airDrag_N(double speed_mps) {
     131            0 :     return ep.__airFrictionCoefficient * speed_mps * speed_mps;
     132              : }
     133              : 
     134              : 
     135            0 : double RealisticEngineModel::rollingResistance_N(double speed_mps, double mass_kg, double cr1, double cr2) {
     136            0 :     return mass_kg * GRAVITY_MPS2 * (cr1 + cr2 * speed_mps * speed_mps);
     137              : }
     138              : 
     139              : 
     140            0 : double RealisticEngineModel::rollingResistance_N(double speed_mps) {
     141            0 :     return ep.__cr1 + ep.__cr2 * speed_mps * speed_mps;
     142              : }
     143              : 
     144              : 
     145            0 : double RealisticEngineModel::gravityForce_N(double mass_kg, double slope = 0) {
     146            0 :     return mass_kg * GRAVITY_MPS2 * sin(slope / 180 * M_PI);
     147              : }
     148              : 
     149              : 
     150            0 : double RealisticEngineModel::gravityForce_N() {
     151            0 :     return ep.__gravity;
     152              : }
     153              : 
     154              : 
     155            0 : double RealisticEngineModel::opposingForce_N(double speed_mps, double mass_kg, double slope,
     156              :         double cAir, double a_m2, double rho_kgpm3,
     157              :         double cr1, double cr2) {
     158            0 :     return airDrag_N(speed_mps, cAir, a_m2, rho_kgpm3) +
     159            0 :            rollingResistance_N(speed_mps, mass_kg, cr1, cr2) +
     160            0 :            gravityForce_N(mass_kg, slope);
     161              : }
     162              : 
     163              : 
     164            0 : double RealisticEngineModel::opposingForce_N(double speed_mps) {
     165            0 :     return airDrag_N(speed_mps) + rollingResistance_N(speed_mps) + gravityForce_N();
     166              : }
     167              : 
     168              : 
     169            0 : double RealisticEngineModel::maxNoSlipAcceleration_mps2(double slope, double frictionCoefficient) {
     170            0 :     return frictionCoefficient * GRAVITY_MPS2 * cos(slope / 180 * M_PI);
     171              : }
     172              : 
     173              : 
     174            0 : double RealisticEngineModel::maxNoSlipAcceleration_mps2() {
     175            0 :     return ep.__maxNoSlipAcceleration;
     176              : }
     177              : 
     178              : 
     179            0 : double RealisticEngineModel::thrust_NToAcceleration_mps2(double thrust_N) {
     180            0 :     return thrust_N / ep.__maxAccelerationCoefficient;
     181              : }
     182              : 
     183              : 
     184            0 : int RealisticEngineModel::performGearShifting(double speed_mps, double acceleration_mps2) {
     185              :     int newGear = 0;
     186            0 :     const double delta = acceleration_mps2 >= 0 ? ep.shiftingRule.deltaRpm : -ep.shiftingRule.deltaRpm;
     187            0 :     for (newGear = 0; newGear < ep.nGears - 1; newGear++) {
     188            0 :         const double rpm = speed_mpsToRpm(speed_mps, ep.gearRatios[newGear]);
     189            0 :         if (rpm >= ep.shiftingRule.rpm + delta) {
     190              :             continue;
     191              :         } else {
     192              :             break;
     193              :         }
     194              :     }
     195            0 :     currentGear = newGear;
     196            0 :     return currentGear;
     197              : }
     198              : 
     199              : 
     200            0 : double RealisticEngineModel::maxEngineAcceleration_mps2(double speed_mps) {
     201            0 :     return speed_mpsToThrust_N(speed_mps) / ep.__maxAccelerationCoefficient;
     202              : }
     203              : 
     204              : 
     205            0 : double RealisticEngineModel::getEngineTimeConstant_s(double rpm) {
     206            0 :     if (rpm <= 0) {
     207              :         return TAU_MAX;
     208              :     } else {
     209            0 :         if (ep.fixedTauBurn)
     210              :             //in this case, tau_burn is fixed and is within __engineTauDe_s
     211              :         {
     212            0 :             return std::min(TAU_MAX, ep.__engineTau2 / rpm + ep.__engineTauDe_s);
     213              :         } else
     214              :             //in this case, tau_burn is dynamic and is within __engineTau1
     215              :         {
     216            0 :             return std::min(TAU_MAX, ep.__engineTau1 / rpm + ep.tauEx_s);
     217              :         }
     218              :     }
     219              : }
     220              : 
     221              : 
     222            0 : double RealisticEngineModel::getRealAcceleration(double speed_mps, double accel_mps2, double reqAccel_mps2, SUMOTime timeStep) {
     223              :     double realAccel_mps2;
     224              :     //perform gear shifting, if needed
     225            0 :     performGearShifting(speed_mps, accel_mps2);
     226              :     //since we consider no clutch (clutch always engaged), 0 speed would mean 0 rpm, and thus
     227              :     //0 available power. thus, the car could never start from a complete stop. so we assume
     228              :     //a minimum speed of 1 m/s to compute engine power
     229            0 :     double correctedSpeed = std::max(speed_mps, minSpeed_mps);
     230            0 :     if (reqAccel_mps2 >= 0) {
     231              :         //the system wants to accelerate
     232              :         //compute what is the maximum acceleration that can be delivered by the engine
     233            0 :         double engineAccel = maxEngineAcceleration_mps2(correctedSpeed);
     234              :         //the maximum acceleration is given by the maximum acceleration the engine can provide minus friction forces
     235            0 :         double maxAccel = engineAccel - thrust_NToAcceleration_mps2(opposingForce_N(speed_mps));
     236              :         //now we need to computed delayed acceleration due to actuation lag
     237            0 :         double tau = getEngineTimeConstant_s(speed_mpsToRpm(correctedSpeed));
     238            0 :         double alpha = ep.dt / (tau + ep.dt);
     239              :         //use standard first order lag with time constant depending on engine rpm
     240            0 :         realAccel_mps2 = alpha * reqAccel_mps2 + (1 - alpha) * accel_mps2;
     241              :         //limit the actual acceleration by considering friction forces and the maximum acceleration considering tyres
     242            0 :         realAccel_mps2 = std::min(std::min(realAccel_mps2, maxAccel), maxNoSlipAcceleration_mps2());
     243              :     } else {
     244            0 :         realAccel_mps2 = getRealBrakingAcceleration(speed_mps, accel_mps2, reqAccel_mps2, timeStep);
     245              :     }
     246            0 :     return realAccel_mps2;
     247              : }
     248              : 
     249              : 
     250            0 : void RealisticEngineModel::getEngineData(double speed_mps, int& gear, double& rpm) {
     251            0 :     gear = currentGear;
     252            0 :     rpm = speed_mpsToRpm(speed_mps);
     253            0 : }
     254              : 
     255              : 
     256            0 : double RealisticEngineModel::getRealBrakingAcceleration(double speed_mps, double accel_mps2, double reqAccel_mps2, SUMOTime t) {
     257              :     UNUSED_PARAMETER(t);
     258              :     //compute which part of the deceleration is currently done by frictions
     259            0 :     double frictionDeceleration = thrust_NToAcceleration_mps2(opposingForce_N(speed_mps));
     260              :     //the maximum deceleration is what the vehicle can do given the tyres plus the friction forces (friction can make the vehicle brake stronger)
     261            0 :     double maxDeceleration = -maxNoSlipAcceleration_mps2() - frictionDeceleration;
     262              :     //compute the new brakes deceleration
     263            0 :     double newBrakesAccel_mps2 = ep.__brakesAlpha * reqAccel_mps2 + ep.__brakesOneMinusAlpha * accel_mps2;
     264              :     //keep actual deceleration within physical limits (considering that wind force can help us slowing down)
     265            0 :     return std::max(maxDeceleration, newBrakesAccel_mps2);
     266              : 
     267              : }
     268              : 
     269              : 
     270            0 : void RealisticEngineModel::loadParameters() {
     271            0 :     VehicleEngineHandler engineHandler(vehicleType);
     272            0 :     if (!XMLSubSys::runParser(engineHandler, xmlFile)) {
     273            0 :         throw ProcessError();
     274              :     }
     275              :     //copy loaded parameters into our engine parameters
     276            0 :     ep = engineHandler.getEngineParameters();
     277            0 :     ep.dt = dt_s;
     278            0 :     ep.computeCoefficients();
     279              :     //compute "minimum speed" to be used when computing maximum acceleration at speeds close to 0
     280            0 :     minSpeed_mps = rpmToSpeed_mps(ep.minRpm, ep.wheelDiameter_m, ep.differentialRatio, ep.gearRatios[0]);
     281            0 : }
     282              : 
     283              : 
     284            0 : void RealisticEngineModel::setParameter(const std::string parameter, const std::string& value) {
     285            0 :     if (parameter == ENGINE_PAR_XMLFILE) {
     286            0 :         xmlFile = value;
     287              :     }
     288            0 :     if (parameter == ENGINE_PAR_VEHICLE) {
     289            0 :         vehicleType = value;
     290            0 :         if (xmlFile != "") {
     291            0 :             loadParameters();
     292              :         }
     293              :     }
     294            0 : }
     295              : 
     296              : 
     297            0 : void RealisticEngineModel::setParameter(const std::string parameter, double value) {
     298            0 :     if (parameter == ENGINE_PAR_DT) {
     299            0 :         dt_s = value;
     300              :     }
     301            0 : }
     302              : 
     303              : 
     304            0 : void RealisticEngineModel::setParameter(const std::string parameter, int value) {
     305              :     UNUSED_PARAMETER(parameter);
     306              :     UNUSED_PARAMETER(value);
     307            0 : }
        

Generated by: LCOV version 2.0-1