Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/emissions/HelpersMMPEVEM.cpp
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2002-2025 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 HelpersMMPEVEM.cpp
15
/// @author Kevin Badalian ([email protected])
16
/// @date 2021-10
17
///
18
// The MMP's emission model for electric vehicles.
19
// If you use this model for academic research, you are highly encouraged to
20
// cite our paper "Accurate physics-based modeling of electric vehicle energy
21
// consumption in the SUMO traffic microsimulator"
22
// (DOI: 10.1109/ITSC48978.2021.9564463).
23
// Teaching and Research Area Mechatronics in Mobile Propulsion (MMP), RWTH Aachen
24
/****************************************************************************/
25
#include <config.h>
26
27
#include <utils/common/SUMOTime.h>
28
#include <utils/common/StringUtils.h>
29
#include <utils/geom/GeomHelper.h>
30
#include <utils/emissions/CharacteristicMap.h>
31
#include <utils/emissions/HelpersMMPEVEM.h>
32
33
34
// ===========================================================================
35
// method definitions
36
// ===========================================================================
37
/**
38
* \brief Compute the power consumption of an EV powertrain in a certain state.
39
*
40
* The model assumes that the driver recuperates as much energy as possible,
41
* meaning that he perfectly employs the mechanical brakes such that only what
42
* lies beyond the motor's capabilities is dissipated. If the new state is
43
* invalid, that is the demanded acceleration exceeds what the electric motor
44
* can manage or the power loss map is not defined for a given point, the torque
45
* and/or power are capped to the motor's limits or the power loss is set to
46
* zero.
47
*
48
* \param[in] m Vehicle mass [kg]
49
* \param[in] r_wheel Wheel radius [m]
50
* \param[in] Theta Moment of inertia [kg*m^2]
51
* \param[in] c_rr Rolling resistance coefficient [1]
52
* \param[in] c_d Drag coefficient [1]
53
* \param[in] A_front Cross-sectional area of the front of the car [m^2]
54
* \param[in] i_gear Gear ratio (i_gear = n_motor/n_wheel) [1]
55
* \param[in] eta_gear Gear efficiency [1]
56
* \param[in] M_max Maximum torque of the EM [Nm]
57
* \param[in] P_max Maximum power of the EM [W]
58
* \param[in] M_recup_max Maximum recuperation torque [Nm]
59
* \param[in] P_recup_max Maximum recuperation power [W]
60
* \param[in] R_battery Internal battery resistance [Ohm]
61
* \param[in] U_battery_0 Nominal battery voltage [V]
62
* \param[in] P_const Constant power consumption of ancillary devices [W]
63
* \param[in] ref_powerLossMap Power loss map of the EM + inverter
64
* \param[in] dt Simulation timestep [s]
65
* \param[in] v Vehicle speed at the end of a timestep [m/s]
66
* \param[in] a Constant acceleration during a timestep [m/s^2]
67
* \param[in] alpha Constant incline during a timestep [deg]
68
* \param[out] ref_powerConsumption Power consumption during the last timestep
69
* [W]
70
* \returns true if the new state is valid, else false
71
*/
72
bool calcPowerConsumption(double m, double r_wheel, double Theta, double c_rr,
73
double c_d, double A_front, double i_gear, double eta_gear, double M_max,
74
double P_max, double M_recup_max, double P_recup_max, double R_battery,
75
double U_battery_0, double P_const,
76
const CharacteristicMap& ref_powerLossMap, double dt, double v, double a,
77
double alpha, double& ref_powerConsumption) {
78
const double EPS = 1e-6;
79
const double RHO_AIR = 1.204; // Air density [kg/m^3]
80
bool b_stateValid = true;
81
82
// Mass factor [1]
83
const double e_i = 1.0 + Theta / (m * r_wheel * r_wheel);
84
// Average speed during the previous timestep
85
const double v_mean = v - 0.5 * a * dt;
86
87
// Force required for the desired acceleration [N]
88
double F_a = m * a * e_i;
89
// Grade resistance [N]
90
double F_gr = m * GRAVITY * std::sin(DEG2RAD(alpha));
91
// Rolling resistance [N]
92
double F_rr = m * GRAVITY * std::cos(DEG2RAD(alpha)) * c_rr;
93
if (std::abs(v_mean) <= EPS) {
94
F_rr = 0;
95
}
96
// Drag [N]
97
double F_d = 0.5 * c_d * A_front * RHO_AIR * v_mean * v_mean;
98
// Tractive force [N]
99
const double F_tractive = F_a + F_gr + F_rr + F_d;
100
101
// Speed of the motor [rpm]
102
const double n_motor = v_mean / (2 * M_PI * r_wheel) * 60 * i_gear;
103
// Angular velocity of the motor [1/s]
104
double omega_motor = 2 * M_PI * n_motor / 60;
105
if (omega_motor == 0) {
106
omega_motor = EPS;
107
}
108
109
// Torque at the motor [Nm]. Please note that this model, like most real EVs,
110
// utilizes the EM to hold the vehicle on an incline rather than the brakes.
111
double M_motor = F_tractive * r_wheel / i_gear;
112
if (F_tractive < 0) {
113
M_motor *= eta_gear;
114
} else {
115
M_motor /= eta_gear;
116
}
117
// Engine power [W]
118
double P_motor = M_motor * omega_motor;
119
120
// Cap torque or power if necessary
121
// Accelerating
122
if (M_motor >= 0) {
123
if (M_motor > M_max) {
124
M_motor = M_max;
125
P_motor = M_motor * omega_motor;
126
b_stateValid = false;
127
}
128
if (P_motor > P_max) {
129
P_motor = P_max;
130
M_motor = P_motor / omega_motor;
131
b_stateValid = false;
132
}
133
}
134
// Recuperating
135
else {
136
// Even when capping, the state is still valid here because the extra energy
137
// is assumed to go to the brakes
138
if (M_motor < -M_recup_max) {
139
M_motor = -M_recup_max;
140
P_motor = M_motor * omega_motor;
141
}
142
if (P_motor < -P_recup_max) {
143
P_motor = -P_recup_max;
144
M_motor = P_motor / omega_motor;
145
}
146
}
147
148
// Power loss in the electric motor + inverter [W]
149
double P_loss_motor =
150
ref_powerLossMap.eval(std::vector<double> {n_motor, M_motor})[0];
151
if (std::isnan(P_loss_motor)) {
152
P_loss_motor = 0.0;
153
b_stateValid = false;
154
}
155
156
// Power demand at the battery [W]
157
double P_battery = P_motor + P_loss_motor + P_const;
158
// Total power demand (including the power loss in the battery) [W]
159
double P_total = (U_battery_0 * U_battery_0) / (2.0 * R_battery)
160
- U_battery_0 * std::sqrt((U_battery_0 * U_battery_0
161
- 4.0 * R_battery * P_battery) / (4.0 * R_battery * R_battery));
162
163
ref_powerConsumption = P_total;
164
return b_stateValid;
165
}
166
167
168
/**
169
* \brief Constructor
170
*/
171
HelpersMMPEVEM::HelpersMMPEVEM()
172
: PollutantsInterface::Helper("MMPEVEM", MMPEVEM_BASE, MMPEVEM_BASE + 1)
173
{ }
174
175
176
/**
177
* \brief Compute the amount of emitted pollutants for an emission class in a
178
* given state.
179
*
180
* This method returns 0 for all emission types but electric power consumption.
181
*
182
* \param[in] c An emission class
183
* \param[in] e An emission type
184
* \param[in] v Current vehicle velocity [m/s]
185
* \param[in] a Current acceleration of the vehicle [m/s^2]
186
* \param[in] slope Slope of the road at the vehicle's current position [deg]
187
* \param[in] ptr_energyParams Vehicle parameters
188
*
189
* \returns The electric power consumption [Wh/s] or 0 for all other emission
190
* types
191
*/
192
double HelpersMMPEVEM::compute(const SUMOEmissionClass c,
193
const PollutantsInterface::EmissionType e, const double v, const double a,
194
const double slope, const EnergyParams* ptr_energyParams) const {
195
if (e != PollutantsInterface::ELEC) {
196
return 0.0;
197
}
198
199
// Extract all required parameters, default values taken from the VW_ID3
200
// Vehicle mass [kg]
201
const double m = ptr_energyParams->getTotalMass(getWeight(c), 0.);
202
// Wheel radius [m]
203
const double r_wheel = ptr_energyParams->getDoubleOptional(SUMO_ATTR_WHEELRADIUS, 0.3588);
204
// Internal moment of inertia [kgm^2]
205
const double Theta = ptr_energyParams->getDoubleOptional(SUMO_ATTR_INTERNALMOMENTOFINERTIA, 12.5);
206
// Rolling resistance coefficient
207
const double c_rr = ptr_energyParams->getDoubleOptional(SUMO_ATTR_ROLLDRAGCOEFFICIENT, 0.007);
208
// Air drag coefficient
209
const double c_d = ptr_energyParams->getDoubleOptional(SUMO_ATTR_AIRDRAGCOEFFICIENT, 0.26);
210
// Cross-sectional area of the front of the car [m^2]
211
const double A_front = ptr_energyParams->getDoubleOptional(SUMO_ATTR_FRONTSURFACEAREA, 2.36);
212
// Gear ratio [1]
213
const double i_gear = ptr_energyParams->getDoubleOptional(SUMO_ATTR_GEARRATIO, 10.);
214
// Gearbox efficiency [1]
215
const double eta_gear = ptr_energyParams->getDoubleOptional(SUMO_ATTR_GEAREFFICIENCY, 0.96);
216
// Maximum torque [Nm]
217
const double M_max = ptr_energyParams->getDoubleOptional(SUMO_ATTR_MAXIMUMTORQUE, 310.);
218
// Maximum power [W]
219
const double P_max = ptr_energyParams->getDoubleOptional(SUMO_ATTR_MAXIMUMPOWER, 107000.);
220
// Maximum recuperation torque [Nm]
221
const double M_recup_max = ptr_energyParams->getDoubleOptional(SUMO_ATTR_MAXIMUMRECUPERATIONTORQUE, 95.5);
222
// Maximum recuperation power [W]
223
const double P_recup_max = ptr_energyParams->getDoubleOptional(SUMO_ATTR_MAXIMUMRECUPERATIONPOWER, 42800.);
224
// Internal battery resistance [Ohm]
225
const double R_battery = ptr_energyParams->getDoubleOptional(SUMO_ATTR_INTERNALBATTERYRESISTANCE, 0.1142);
226
// Nominal battery voltage [V]
227
const double U_battery_0 = ptr_energyParams->getDoubleOptional(SUMO_ATTR_NOMINALBATTERYVOLTAGE, 396.);
228
// Constant power consumption [W]
229
const double P_const = ptr_energyParams->getDoubleOptional(SUMO_ATTR_CONSTANTPOWERINTAKE, 360.);
230
// Power loss map
231
const CharacteristicMap& ref_powerLossMap = ptr_energyParams->getCharacteristicMap(SUMO_ATTR_POWERLOSSMAP);
232
233
double P = 0.0; // [W]
234
bool b_stateValid = calcPowerConsumption(m, r_wheel, Theta, c_rr, c_d,
235
A_front, i_gear, eta_gear, M_max, P_max, M_recup_max, P_recup_max,
236
R_battery, U_battery_0, P_const, ref_powerLossMap, TS, v, a, slope, P);
237
P /= 3600.0; // [Wh/s]
238
239
if (b_stateValid) {
240
return P;
241
} else {
242
return std::nan("");
243
}
244
}
245
246