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