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