1 /****************************************************************************/ 2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo 3 // Copyright (C) 2016-2019 German Aerospace Center (DLR) and others. 4 // PHEMlight module 5 // Copyright (C) 2016-2017 Technische Universitaet Graz, https://www.tugraz.at/ 6 // This program and the accompanying materials 7 // are made available under the terms of the Eclipse Public License v2.0 8 // which accompanies this distribution, and is available at 9 // http://www.eclipse.org/legal/epl-v20.html 10 // SPDX-License-Identifier: EPL-2.0 11 /****************************************************************************/ 12 /// @file CEP.cpp 13 /// @author Martin Dippold 14 /// @author Michael Behrisch 15 /// @date July 2016 16 /// @version $Id$ 17 /// 18 // 19 /****************************************************************************/ 20 21 22 #include "CEP.h" 23 #include "Constants.h" 24 #include "Helpers.h" 25 26 27 namespace PHEMlightdll { 28 CEP(bool heavyVehicle,double vehicleMass,double vehicleLoading,double vehicleMassRot,double crossArea,double cWValue,double f0,double f1,double f2,double f3,double f4,double axleRatio,std::vector<double> & transmissionGearRatios,double auxPower,double ratedPower,double engineIdlingSpeed,double engineRatedSpeed,double effictiveWheelDiameter,double pNormV0,double pNormP0,double pNormV1,double pNormP1,const std::string & vehicelFuelType,std::vector<std::vector<double>> & matrixFC,std::vector<std::string> & headerLinePollutants,std::vector<std::vector<double>> & matrixPollutants,std::vector<std::vector<double>> & matrixSpeedRotational,std::vector<std::vector<double>> & normedDragTable,double idlingFC,std::vector<double> & idlingPollutants)29 CEP::CEP(bool heavyVehicle, double vehicleMass, double vehicleLoading, double vehicleMassRot, double crossArea, double cWValue, double f0, double f1, double f2, double f3, double f4, double axleRatio, std::vector<double>& transmissionGearRatios, double auxPower, double ratedPower, double engineIdlingSpeed, double engineRatedSpeed, double effictiveWheelDiameter, double pNormV0, double pNormP0, double pNormV1, double pNormP1, const std::string& vehicelFuelType, std::vector<std::vector<double> >& matrixFC, std::vector<std::string>& headerLinePollutants, std::vector<std::vector<double> >& matrixPollutants, std::vector<std::vector<double> >& matrixSpeedRotational, std::vector<std::vector<double> >& normedDragTable, double idlingFC, std::vector<double>& idlingPollutants) { 30 transmissionGearRatios.size(); // just to make the compiler happy about the unused parameter 31 InitializeInstanceFields(); 32 _resistanceF0 = f0; 33 _resistanceF1 = f1; 34 _resistanceF2 = f2; 35 _resistanceF3 = f3; 36 _resistanceF4 = f4; 37 _cWValue = cWValue; 38 _crossSectionalArea = crossArea; 39 _massVehicle = vehicleMass; 40 _vehicleLoading = vehicleLoading; 41 _vehicleMassRot = vehicleMassRot; 42 _ratedPower = ratedPower; 43 _engineIdlingSpeed = engineIdlingSpeed; 44 _engineRatedSpeed = engineRatedSpeed; 45 _effectiveWheelDiameter = effictiveWheelDiameter; 46 _heavyVehicle = heavyVehicle; 47 _fuelType = vehicelFuelType; 48 _axleRatio = axleRatio; 49 _auxPower = auxPower; 50 51 _pNormV0 = pNormV0 / 3.6; 52 _pNormP0 = pNormP0; 53 _pNormV1 = pNormV1 / 3.6; 54 _pNormP1 = pNormP1; 55 56 std::vector<std::string> pollutantIdentifier; 57 std::vector<std::vector<double> > pollutantMeasures; 58 std::vector<std::vector<double> > normalizedPollutantMeasures; 59 60 // init pollutant identifiers 61 for (int i = 0; i < (int)headerLinePollutants.size(); i++) { 62 pollutantIdentifier.push_back(headerLinePollutants[i]); 63 } 64 65 // initialize measures 66 for (int i = 0; i < (int)headerLinePollutants.size(); i++) { 67 pollutantMeasures.push_back(std::vector<double>()); 68 normalizedPollutantMeasures.push_back(std::vector<double>()); 69 } 70 71 // looping through matrix and assigning values for speed rotational table 72 _speedCurveRotational = std::vector<double>(); 73 _speedPatternRotational = std::vector<double>(); 74 _gearTransmissionCurve = std::vector<double>(); 75 for (int i = 0; i < (int)matrixSpeedRotational.size(); i++) { 76 if (matrixSpeedRotational[i].size() != 3) { 77 return; 78 } 79 80 _speedPatternRotational.push_back(matrixSpeedRotational[i][0] / 3.6); 81 _gearTransmissionCurve.push_back(matrixSpeedRotational[i][1]); 82 _speedCurveRotational.push_back(matrixSpeedRotational[i][2]); 83 } 84 85 // looping through matrix and assigning values for drag table 86 _nNormTable = std::vector<double>(); 87 _dragNormTable = std::vector<double>(); 88 for (int i = 0; i < (int)normedDragTable.size(); i++) { 89 if (normedDragTable[i].size() != 2) { 90 return; 91 } 92 93 _nNormTable.push_back(normedDragTable[i][0]); 94 _dragNormTable.push_back(normedDragTable[i][1]); 95 } 96 97 // looping through matrix and assigning values for Fuel consumption 98 _cepCurveFC = std::vector<double>(); 99 _normedCepCurveFC = std::vector<double>(); 100 _powerPatternFC = std::vector<double>(); 101 _normalizedPowerPatternFC = std::vector<double>(); 102 for (int i = 0; i < (int)matrixFC.size(); i++) { 103 if (matrixFC[i].size() != 2) { 104 return; 105 } 106 107 _powerPatternFC.push_back(matrixFC[i][0] * _ratedPower); 108 _normalizedPowerPatternFC.push_back(matrixFC[i][0]); 109 _cepCurveFC.push_back(matrixFC[i][1] * _ratedPower); 110 _normedCepCurveFC.push_back(matrixFC[i][1]); 111 112 } 113 114 _powerPatternPollutants = std::vector<double>(); 115 116 double pollutantMultiplyer = 1; 117 118 _drivingPower = _normalizingPower = CalcPower(Constants::NORMALIZING_SPEED, Constants::NORMALIZING_ACCELARATION, 0); 119 120 // looping through matrix and assigning values for pollutants 121 if (heavyVehicle) { 122 _normalizingPower = _ratedPower; 123 _normalizingType = NormalizingType_RatedPower; 124 pollutantMultiplyer = _ratedPower; 125 } 126 else { 127 _normalizingPower = _drivingPower; 128 _normalizingType = NormalizingType_DrivingPower; 129 } 130 131 _normailzedPowerPatternPollutants = std::vector<double>(); 132 133 _cepNormalizedCurvePollutants = std::map<std::string, std::vector<double> >(); 134 135 int headerCount = (int)headerLinePollutants.size(); 136 for (int i = 0; i < (int)matrixPollutants.size(); i++) { 137 for (int j = 0; j < (int)matrixPollutants[i].size(); j++) { 138 if ((int)matrixPollutants[i].size() != headerCount + 1) { 139 return; 140 } 141 142 if (j == 0) { 143 _normailzedPowerPatternPollutants.push_back(matrixPollutants[i][j]); 144 _powerPatternPollutants.push_back(matrixPollutants[i][j] * getNormalizingPower()); 145 } 146 else { 147 pollutantMeasures[j - 1].push_back(matrixPollutants[i][j] * pollutantMultiplyer); 148 normalizedPollutantMeasures[j - 1].push_back(matrixPollutants[i][j]); 149 } 150 } 151 } 152 153 _cepCurvePollutants = std::map<std::string, std::vector<double> >(); 154 _idlingValuesPollutants = std::map<std::string, double>(); 155 156 for (int i = 0; i < (int)headerLinePollutants.size(); i++) { 157 _cepCurvePollutants.insert(std::make_pair(pollutantIdentifier[i], pollutantMeasures[i])); 158 _cepNormalizedCurvePollutants.insert(std::make_pair(pollutantIdentifier[i], normalizedPollutantMeasures[i])); 159 _idlingValuesPollutants.insert(std::make_pair(pollutantIdentifier[i], idlingPollutants[i] * pollutantMultiplyer)); 160 } 161 162 _idlingValueFC = idlingFC * _ratedPower; 163 } 164 getHeavyVehicle() const165 const bool& CEP::getHeavyVehicle() const { 166 return _heavyVehicle; 167 } 168 getFuelType() const169 const std::string& CEP::getFuelType() const { 170 return _fuelType; 171 } 172 getNormalizingTypeX() const173 const CEP::NormalizingType& CEP::getNormalizingTypeX() const { 174 return _normalizingType; 175 } 176 getRatedPower() const177 const double& CEP::getRatedPower() const { 178 return _ratedPower; 179 } 180 setRatedPower(const double & value)181 void CEP::setRatedPower(const double& value) { 182 _ratedPower = value; 183 } 184 getNormalizingPower() const185 const double& CEP::getNormalizingPower() const { 186 return _normalizingPower; 187 } 188 getDrivingPower() const189 const double& CEP::getDrivingPower() const { 190 return _drivingPower; 191 } 192 setDrivingPower(const double & value)193 void CEP::setDrivingPower(const double& value) { 194 _drivingPower = value; 195 } 196 CalcPower(double speed,double acc,double gradient)197 double CEP::CalcPower(double speed, double acc, double gradient) { 198 //Declaration 199 double power = 0; 200 double rotFactor = GetRotationalCoeffecient(speed); 201 double powerAux = (_auxPower * _ratedPower); 202 203 //Calculate the power 204 power += (_massVehicle + _vehicleLoading) * Constants::GRAVITY_CONST * (_resistanceF0 + _resistanceF1 * speed + _resistanceF4 * std::pow(speed, 4)) * speed; 205 power += (_crossSectionalArea * _cWValue * Constants::AIR_DENSITY_CONST / 2) * std::pow(speed, 3); 206 power += (_massVehicle * rotFactor + _vehicleMassRot + _vehicleLoading) * acc * speed; 207 power += (_massVehicle + _vehicleLoading) * Constants::GRAVITY_CONST * gradient * 0.01 * speed; 208 power /= 1000; 209 power /= Constants::_DRIVE_TRAIN_EFFICIENCY; 210 power += powerAux; 211 212 //Return result 213 return power; 214 } 215 CalcEngPower(double power)216 double CEP::CalcEngPower(double power) { 217 if (power < _powerPatternFC.front()) { 218 return _powerPatternFC.front(); 219 } 220 if (power > _powerPatternFC.back()) { 221 return _powerPatternFC.back(); 222 } 223 224 return power; 225 } 226 GetEmission(const std::string & pollutant,double power,double speed,Helpers * VehicleClass)227 double CEP::GetEmission(const std::string& pollutant, double power, double speed, Helpers* VehicleClass) { 228 //Declaration 229 std::vector<double> emissionCurve; 230 std::vector<double> powerPattern; 231 232 // bisection search to find correct position in power pattern 233 int upperIndex; 234 int lowerIndex; 235 236 if (_fuelType != Constants::strBEV) { 237 if (std::abs(speed) <= Constants::ZERO_SPEED_ACCURACY) { 238 if (pollutant == "FC") { 239 return _idlingValueFC; 240 } 241 else { 242 if (_cepCurvePollutants.find(pollutant) == _cepCurvePollutants.end()) { 243 VehicleClass->setErrMsg(std::string("Emission pollutant ") + pollutant + std::string(" not found!")); 244 return 0; 245 } 246 247 return _idlingValuesPollutants[pollutant]; 248 } 249 } 250 } 251 252 if (pollutant == "FC") { 253 emissionCurve = _cepCurveFC; 254 powerPattern = _powerPatternFC; 255 } 256 else { 257 if (_cepCurvePollutants.find(pollutant) == _cepCurvePollutants.end()) { 258 VehicleClass->setErrMsg(std::string("Emission pollutant ") + pollutant + std::string(" not found!")); 259 return 0; 260 } 261 262 emissionCurve = _cepCurvePollutants[pollutant]; 263 powerPattern = _powerPatternPollutants; 264 } 265 266 if (emissionCurve.empty()) { 267 VehicleClass->setErrMsg(std::string("Empty emission curve for ") + pollutant + std::string(" found!")); 268 return 0; 269 } 270 if (emissionCurve.size() == 1) { 271 return emissionCurve[0]; 272 } 273 274 // in case that the demanded power is smaller than the first entry (smallest) in the power pattern the first is returned (should never happen) 275 if (power <= powerPattern.front()) { 276 return emissionCurve[0]; 277 } 278 279 // if power bigger than all entries in power pattern return the last (should never happen) 280 if (power >= powerPattern.back()) { 281 return emissionCurve.back(); 282 } 283 284 FindLowerUpperInPattern(lowerIndex, upperIndex, powerPattern, power); 285 return Interpolate(power, powerPattern[lowerIndex], powerPattern[upperIndex], emissionCurve[lowerIndex], emissionCurve[upperIndex]); 286 } 287 GetCO2Emission(double _FC,double _CO,double _HC,Helpers * VehicleClass)288 double CEP::GetCO2Emission(double _FC, double _CO, double _HC, Helpers* VehicleClass) { 289 //Declaration 290 double fCBr; 291 double fCHC = 0.866; 292 double fCCO = 0.429; 293 double fCCO2 = 0.273; 294 295 //C# TO C++ CONVERTER NOTE: The following 'switch' operated on a string variable and was converted to C++ 'if-else' logic: 296 // switch (_fuelType) 297 //ORIGINAL LINE: case Constants.strGasoline: 298 if (_fuelType == Constants::strGasoline) { 299 fCBr = 0.865; 300 } 301 //ORIGINAL LINE: case Constants.strDiesel: 302 else if (_fuelType == Constants::strDiesel) { 303 fCBr = 0.863; 304 } 305 //ORIGINAL LINE: case Constants.strCNG: 306 else if (_fuelType == Constants::strCNG) { 307 fCBr = 0.693; 308 fCHC = 0.803; 309 } 310 //ORIGINAL LINE: case Constants.strLPG: 311 else if (_fuelType == Constants::strLPG) { 312 fCBr = 0.825; 313 fCHC = 0.825; 314 } 315 else { 316 VehicleClass->setErrMsg(std::string("The propolsion type is not known! (") + _fuelType + std::string(")")); 317 return 0; 318 } 319 320 return (_FC * fCBr - _CO * fCCO - _HC * fCHC) / fCCO2; 321 } 322 GetDecelCoast(double speed,double acc,double gradient)323 double CEP::GetDecelCoast(double speed, double acc, double gradient) { 324 //Declaration 325 int upperIndex; 326 int lowerIndex; 327 328 if (speed < Constants::SPEED_DCEL_MIN) { 329 return speed / Constants::SPEED_DCEL_MIN * GetDecelCoast(Constants::SPEED_DCEL_MIN, acc, gradient); 330 } 331 332 double rotCoeff = GetRotationalCoeffecient(speed); 333 FindLowerUpperInPattern(lowerIndex, upperIndex, _speedPatternRotational, speed); 334 double iGear = Interpolate(speed, _speedPatternRotational[lowerIndex], _speedPatternRotational[upperIndex], _gearTransmissionCurve[lowerIndex], _gearTransmissionCurve[upperIndex]); 335 336 double iTot = iGear * _axleRatio; 337 338 double n = (30 * speed * iTot) / ((_effectiveWheelDiameter / 2) * M_PI); 339 double nNorm = (n - _engineIdlingSpeed) / (_engineRatedSpeed - _engineIdlingSpeed); 340 341 FindLowerUpperInPattern(lowerIndex, upperIndex, _nNormTable, nNorm); 342 343 double fMot = 0; 344 345 if (speed >= 10e-2) { 346 fMot = (-Interpolate(nNorm, _nNormTable[lowerIndex], _nNormTable[upperIndex], _dragNormTable[lowerIndex], _dragNormTable[upperIndex]) * _ratedPower * 1000 / speed) / 0.9; 347 } 348 349 double fRoll = (_resistanceF0 + _resistanceF1 * speed + std::pow(_resistanceF2 * speed, 2) + std::pow(_resistanceF3 * speed, 3) + std::pow(_resistanceF4 * speed, 4)) * (_massVehicle + _vehicleLoading) * Constants::GRAVITY_CONST; 350 351 double fAir = _cWValue * _crossSectionalArea * 1.2 * 0.5 * std::pow(speed, 2); 352 353 double fGrad = (_massVehicle + _vehicleLoading) * Constants::GRAVITY_CONST * gradient / 100; 354 355 return -(fMot + fRoll + fAir + fGrad) / ((_massVehicle + _vehicleLoading) * rotCoeff); 356 } 357 GetRotationalCoeffecient(double speed)358 double CEP::GetRotationalCoeffecient(double speed) { 359 //Declaration 360 int upperIndex; 361 int lowerIndex; 362 363 FindLowerUpperInPattern(lowerIndex, upperIndex, _speedPatternRotational, speed); 364 return Interpolate(speed, _speedPatternRotational[lowerIndex], _speedPatternRotational[upperIndex], _speedCurveRotational[lowerIndex], _speedCurveRotational[upperIndex]); 365 } 366 FindLowerUpperInPattern(int & lowerIndex,int & upperIndex,std::vector<double> & pattern,double value)367 void CEP::FindLowerUpperInPattern(int& lowerIndex, int& upperIndex, std::vector<double>& pattern, double value) { 368 lowerIndex = 0; 369 upperIndex = 0; 370 371 if (value <= pattern.front()) { 372 lowerIndex = 0; 373 upperIndex = 0; 374 return; 375 } 376 377 if (value >= pattern.back()) { 378 lowerIndex = (int)pattern.size() - 1; 379 upperIndex = (int)pattern.size() - 1; 380 return; 381 } 382 383 // bisection search to find correct position in power pattern 384 int middleIndex = ((int)pattern.size() - 1) / 2; 385 upperIndex = (int)pattern.size() - 1; 386 lowerIndex = 0; 387 388 while (upperIndex - lowerIndex > 1) { 389 if (pattern[middleIndex] == value) { 390 lowerIndex = middleIndex; 391 upperIndex = middleIndex; 392 return; 393 } 394 else if (pattern[middleIndex] < value) { 395 lowerIndex = middleIndex; 396 middleIndex = (upperIndex - lowerIndex) / 2 + lowerIndex; 397 } 398 else { 399 upperIndex = middleIndex; 400 middleIndex = (upperIndex - lowerIndex) / 2 + lowerIndex; 401 } 402 } 403 404 if (pattern[lowerIndex] <= value && value < pattern[upperIndex]) { 405 return; 406 } 407 } 408 Interpolate(double px,double p1,double p2,double e1,double e2)409 double CEP::Interpolate(double px, double p1, double p2, double e1, double e2) { 410 if (p2 == p1) { 411 return e1; 412 } 413 414 return e1 + (px - p1) / (p2 - p1) * (e2 - e1); 415 } 416 GetMaxAccel(double speed,double gradient)417 double CEP::GetMaxAccel(double speed, double gradient) { 418 double rotFactor = GetRotationalCoeffecient(speed); 419 double pMaxForAcc = GetPMaxNorm(speed) * _ratedPower - CalcPower(speed, 0, gradient); 420 421 return (pMaxForAcc * 1000) / ((_massVehicle * rotFactor + _vehicleMassRot + _vehicleLoading) * speed); 422 } 423 GetPMaxNorm(double speed)424 double CEP::GetPMaxNorm(double speed) { 425 // Linear function between v0 and v1, constant elsewhere 426 if (speed <= _pNormV0) { 427 return _pNormP0; 428 } 429 else if (speed >= _pNormV1) { 430 return _pNormP1; 431 } 432 else { 433 return Interpolate(speed, _pNormV0, _pNormV1, _pNormP0, _pNormP1); 434 } 435 } 436 InitializeInstanceFields()437 void CEP::InitializeInstanceFields() { 438 _heavyVehicle = false; 439 _normalizingType = static_cast<NormalizingType>(0); 440 _ratedPower = 0; 441 _normalizingPower = 0; 442 _drivingPower = 0; 443 _massVehicle = 0; 444 _vehicleLoading = 0; 445 _vehicleMassRot = 0; 446 _crossSectionalArea = 0; 447 _cWValue = 0; 448 _resistanceF0 = 0; 449 _resistanceF1 = 0; 450 _resistanceF2 = 0; 451 _resistanceF3 = 0; 452 _resistanceF4 = 0; 453 _axleRatio = 0; 454 _auxPower = 0; 455 _pNormV0 = 0; 456 _pNormP0 = 0; 457 _pNormV1 = 0; 458 _pNormP1 = 0; 459 _engineRatedSpeed = 0; 460 _engineIdlingSpeed = 0; 461 _effectiveWheelDiameter = 0; 462 _idlingValueFC = 0; 463 } 464 } 465