Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2013-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 MSDevice_Battery.cpp
15 : /// @author Tamas Kurczveil
16 : /// @author Pablo Alvarez Lopez
17 : /// @author Mirko Barthauer
18 : /// @date 20.12.2013
19 : ///
20 : // The Battery parameters for the vehicle
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <algorithm>
25 : #include <utils/common/StringUtils.h>
26 : #include <utils/options/OptionsCont.h>
27 : #include <utils/iodevices/OutputDevice.h>
28 : #include <utils/common/SUMOTime.h>
29 : #include <utils/geom/GeomHelper.h>
30 : #include <utils/emissions/HelpersEnergy.h>
31 : #include <utils/xml/SUMOSAXAttributes.h>
32 : #include <microsim/MSNet.h>
33 : #include <microsim/MSLane.h>
34 : #include <microsim/MSEdge.h>
35 : #include <microsim/MSVehicle.h>
36 : #include "MSDevice_StationFinder.h"
37 : #include "MSDevice_Emissions.h"
38 : #include "MSDevice_Battery.h"
39 :
40 : #define DEFAULT_MAX_CAPACITY 35000
41 : #define DEFAULT_CHARGE_RATIO 0.5
42 :
43 :
44 : // ===========================================================================
45 : // method definitions
46 : // ===========================================================================
47 : // ---------------------------------------------------------------------------
48 : // static initialisation methods
49 : // ---------------------------------------------------------------------------
50 : void
51 43644 : MSDevice_Battery::insertOptions(OptionsCont& oc) {
52 87288 : insertDefaultAssignmentOptions("battery", "Battery", oc);
53 : // custom options
54 43644 : oc.doRegister("device.battery.track-fuel", new Option_Bool(false));
55 87288 : oc.addDescription("device.battery.track-fuel", "Battery", TL("Track fuel consumption for non-electric vehicles"));
56 43644 : }
57 :
58 :
59 : void
60 5104373 : MSDevice_Battery::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, MSDevice_StationFinder* sf) {
61 : // Check if vehicle should get a battery
62 10208678 : if (sf != nullptr || equippedByDefaultAssignmentOptions(OptionsCont::getOptions(), "battery", v, false)) {
63 : // obtain parameter values
64 1637 : const double maximumBatteryCapacity = readParameterValue(v, SUMO_ATTR_MAXIMUMBATTERYCAPACITY, "battery.capacity", DEFAULT_MAX_CAPACITY);
65 1637 : const double actualBatteryCapacity = readParameterValue(v, SUMO_ATTR_ACTUALBATTERYCAPACITY, "battery.chargeLevel", maximumBatteryCapacity * DEFAULT_CHARGE_RATIO);
66 1637 : const double stoppingThreshold = readParameterValue(v, SUMO_ATTR_STOPPINGTHRESHOLD, "battery.stoppingThreshold", 0.1);
67 1637 : const double maximumChargeRate = readParameterValue(v, SUMO_ATTR_MAXIMUMCHARGERATE, "battery.maximumChargeRate", 150000.);
68 3274 : const std::string chargeLevelTable = v.getStringParam("device.battery.chargeLevelTable");
69 3274 : const std::string chargeCurveTable = v.getStringParam("device.battery.chargeCurveTable");
70 :
71 : // battery constructor
72 1637 : MSDevice_Battery* device = new MSDevice_Battery(v, "battery_" + v.getID(),
73 3274 : actualBatteryCapacity, maximumBatteryCapacity, stoppingThreshold, maximumChargeRate, chargeLevelTable, chargeCurveTable);
74 :
75 : // Add device to vehicle
76 1637 : into.push_back(device);
77 :
78 1637 : if (sf != nullptr) {
79 : sf->setBattery(device);
80 : }
81 : }
82 5104373 : }
83 :
84 :
85 : double
86 6548 : MSDevice_Battery::readParameterValue(SUMOVehicle& v, const SumoXMLAttr& attr, const std::string& paramName, double defaultVal) {
87 6548 : const std::string& oldParam = toString(attr);
88 6548 : const SUMOVTypeParameter& typeParams = v.getVehicleType().getParameter();
89 6548 : if (v.getParameter().hasParameter(oldParam) || typeParams.hasParameter(oldParam)) {
90 0 : WRITE_WARNINGF(TL("Battery device in vehicle '%' still uses old parameter '%'. Please update to 'device.%'."), v.getID(), oldParam, paramName);
91 0 : if (v.getParameter().getParameter(oldParam, "-") == "-") {
92 0 : return typeParams.getDouble(oldParam, defaultVal);
93 : }
94 0 : return StringUtils::toDouble(v.getParameter().getParameter(oldParam, "0"));
95 : }
96 13096 : return v.getFloatParam("device." + paramName, false, defaultVal);
97 : }
98 :
99 :
100 : // ---------------------------------------------------------------------------
101 : // MSDevice_Battery-methods
102 : // ---------------------------------------------------------------------------
103 1637 : MSDevice_Battery::MSDevice_Battery(SUMOVehicle& holder, const std::string& id, const double actualBatteryCapacity, const double maximumBatteryCapacity,
104 1637 : const double stoppingThreshold, const double maximumChargeRate, const std::string& chargeLevelTable, const std::string& chargeCurveTable) :
105 : MSVehicleDevice(holder, id),
106 1637 : myActualBatteryCapacity(0), // [actualBatteryCapacity <= maximumBatteryCapacity]
107 1637 : myMaximumBatteryCapacity(0), // [maximumBatteryCapacity >= 0]
108 1637 : myStoppingThreshold(0), // [stoppingThreshold >= 0]
109 1637 : myMaximumChargeRate(0),
110 1637 : myChargeLimit(-1),
111 1637 : myLastAngle(std::numeric_limits<double>::infinity()),
112 1637 : myChargingStopped(false), // Initially vehicle don't charge stopped
113 1637 : myChargingInTransit(false), // Initially vehicle don't charge in transit
114 1637 : myChargingStartTime(0), // Initially charging start time (must be if the vehicle was launched at the charging station)
115 1637 : myConsum(0), // Initially the vehicle is stopped and therefore the consum is zero.
116 1637 : myTotalConsumption(0.0),
117 1637 : myTotalRegenerated(0.0),
118 1637 : myActChargingStation(nullptr), // Initially the vehicle isn't over a Charging Station
119 1637 : myPreviousNeighbouringChargingStation(nullptr), // Initially the vehicle wasn't over a Charging Station
120 1637 : myEnergyCharged(0), // Initially the energy charged is zero
121 1637 : myVehicleStopped(0),
122 1637 : myDepletedCount(0) {
123 : // Initially the vehicle is stopped and the corresponding variable is 0
124 :
125 1637 : if (maximumBatteryCapacity < 0) {
126 0 : WRITE_WARNINGF(TL("Battery builder: Vehicle '%' doesn't have a valid value for parameter % (%)."), getID(), toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY), toString(maximumBatteryCapacity));
127 : } else {
128 1637 : myMaximumBatteryCapacity = maximumBatteryCapacity;
129 : }
130 :
131 1637 : if (actualBatteryCapacity > maximumBatteryCapacity) {
132 0 : WRITE_WARNINGF(TL("Battery builder: Vehicle '%' has a % (%) greater than its % (%). A max battery capacity value will be assigned."),
133 : getID(), toString(SUMO_ATTR_ACTUALBATTERYCAPACITY), toString(actualBatteryCapacity), toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY), toString(maximumBatteryCapacity));
134 0 : myActualBatteryCapacity = myMaximumBatteryCapacity;
135 : } else {
136 1637 : myActualBatteryCapacity = actualBatteryCapacity;
137 : }
138 :
139 1637 : if (stoppingThreshold < 0) {
140 0 : WRITE_WARNINGF(TL("Battery builder: Vehicle '%' doesn't have a valid value for parameter % (%)."), getID(), toString(SUMO_ATTR_STOPPINGTHRESHOLD), toString(stoppingThreshold));
141 : } else {
142 1637 : myStoppingThreshold = stoppingThreshold;
143 : }
144 :
145 1673 : myTrackFuel = PollutantsInterface::getFuel(holder.getVehicleType().getEmissionClass()) != "Electricity" && OptionsCont::getOptions().getBool("device.battery.track-fuel");
146 1637 : if (!myTrackFuel && !holder.getVehicleType().getParameter().wasSet(VTYPEPARS_EMISSIONCLASS_SET)) {
147 72 : WRITE_WARNINGF(TL("The battery device is active for vehicle '%' but no emission class is set. "
148 : "Please consider setting an explicit emission class or battery outputs might be inconsistent with emission outputs!"),
149 : holder.getID());
150 : }
151 :
152 1637 : if (maximumChargeRate < 0) {
153 0 : WRITE_WARNINGF(TL("Battery builder: Vehicle '%' doesn't have a valid value for parameter % (%)."), getID(), toString(SUMO_ATTR_MAXIMUMCHARGERATE), toString(maximumChargeRate));
154 : } else {
155 1637 : if (!chargeLevelTable.empty() && !chargeCurveTable.empty()) {
156 0 : LinearApproxHelpers::setPoints(myChargeCurve, chargeLevelTable, chargeCurveTable);
157 0 : if (!myTrackFuel) {
158 0 : LinearApproxHelpers::scaleValues(myChargeCurve, 1. / 3600);
159 : }
160 0 : myMaximumChargeRate = LinearApproxHelpers::getMaximumValue(myChargeCurve);
161 : } else {
162 1637 : myMaximumChargeRate = maximumChargeRate;
163 1637 : if (!myTrackFuel) {
164 1625 : myMaximumChargeRate /= 3600.;
165 : }
166 : }
167 : }
168 1637 : }
169 :
170 :
171 3274 : MSDevice_Battery::~MSDevice_Battery() {
172 3274 : }
173 :
174 :
175 373298 : bool MSDevice_Battery::notifyMove(SUMOTrafficObject& tObject, double /* oldPos */, double /* newPos */, double /* newSpeed */) {
176 373298 : if (!tObject.isVehicle()) {
177 : return false;
178 : }
179 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
180 : // Start vehicleStoppedTimer if the vehicle is stopped. In other case reset timer
181 373298 : if (veh.getSpeed() < myStoppingThreshold) {
182 : // Increase vehicle stopped timer
183 133932 : increaseVehicleStoppedTimer();
184 : } else {
185 : // Reset vehicle Stopped
186 239366 : resetVehicleStoppedTimer();
187 : }
188 :
189 : // Update Energy from the battery
190 373298 : EnergyParams* const params = myHolder.getEmissionParameters();
191 373298 : if (getMaximumBatteryCapacity() != 0) {
192 373298 : params->setDouble(SUMO_ATTR_ANGLE, myLastAngle == std::numeric_limits<double>::infinity() ? 0. : GeomHelper::angleDiff(myLastAngle, veh.getAngle()));
193 373298 : if (!myTrackFuel && !veh.getVehicleType().getParameter().wasSet(VTYPEPARS_EMISSIONCLASS_SET)) {
194 : // no explicit emission class, we fall back to the energy model; a warning has been issued on creation
195 890 : myConsum = PollutantsInterface::getEnergyHelper().compute(0, PollutantsInterface::ELEC, veh.getSpeed(), veh.getAcceleration(),
196 890 : veh.getSlope(), params) * TS;
197 : } else {
198 372853 : myConsum = PollutantsInterface::compute(veh.getVehicleType().getEmissionClass(),
199 372853 : myTrackFuel ? PollutantsInterface::FUEL : PollutantsInterface::ELEC,
200 372853 : veh.getSpeed(), veh.getAcceleration(),
201 745706 : veh.getSlope(), params) * TS;
202 : }
203 373298 : if (veh.isParking()) {
204 : // recuperation from last braking step is ok but further consumption should cease
205 848 : myConsum = MIN2(myConsum, 0.0);
206 : }
207 :
208 : // saturate between 0 and myMaximumBatteryCapacity [Wh]
209 373298 : if (myConsum > getActualBatteryCapacity() && getActualBatteryCapacity() > 0 && getMaximumBatteryCapacity() > 0) {
210 44 : myDepletedCount++;
211 44 : if (myDepletedCount == 1) {
212 84 : WRITE_WARNINGF(TL("Battery of vehicle '%' is depleted, time=%."), veh.getID(), time2string(SIMSTEP));
213 : }
214 : }
215 :
216 : // Energy lost/gained from vehicle movement (via vehicle energy model) [Wh]
217 373298 : setActualBatteryCapacity(getActualBatteryCapacity() - myConsum);
218 :
219 : // Track total energy consumption and regeneration
220 373298 : if (myConsum > 0.0) {
221 341538 : myTotalConsumption += myConsum;
222 : } else {
223 31760 : myTotalRegenerated -= myConsum;
224 : }
225 :
226 373298 : myLastAngle = veh.getAngle();
227 : }
228 :
229 : // Check if vehicle has under their position one charge Station
230 373298 : const std::string chargingStationID = MSNet::getInstance()->getStoppingPlaceID(veh.getLane(), veh.getPositionOnLane(), SUMO_TAG_CHARGING_STATION);
231 :
232 : // If vehicle is over a charging station
233 373298 : if (chargingStationID != "") {
234 : // if the vehicle is almost stopped, or charge in transit is enabled, then charge vehicle
235 34694 : MSChargingStation* const cs = static_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(chargingStationID, SUMO_TAG_CHARGING_STATION));
236 34694 : const MSParkingArea* pa = cs->getParkingArea();
237 34694 : if (((veh.getSpeed() < myStoppingThreshold) || cs->getChargeInTransit()) && (pa == nullptr || veh.isParking())) {
238 : // Set Flags Stopped/intransit to
239 32698 : if (veh.getSpeed() < myStoppingThreshold) {
240 : // vehicle ist almost stopped, then is charging stopped
241 31583 : myChargingStopped = true;
242 :
243 : // therefore isn't charging in transit
244 31583 : myChargingInTransit = false;
245 : } else {
246 : // vehicle is moving, and the Charging station allow charge in transit
247 1115 : myChargingStopped = false;
248 :
249 : // Therefore charge in transit
250 1115 : myChargingInTransit = true;
251 : }
252 :
253 : // get pointer to charging station
254 32698 : myActChargingStation = cs;
255 :
256 : // Only update charging start time if vehicle allow charge in transit, or in other case
257 : // if the vehicle not allow charge in transit but it's stopped.
258 32698 : if ((myActChargingStation->getChargeInTransit()) || (veh.getSpeed() < myStoppingThreshold)) {
259 : // Update Charging start time
260 32698 : increaseChargingStartTime();
261 : }
262 :
263 : // time it takes the vehicle at the station < charging station time delay?
264 32698 : if (getChargingStartTime() > myActChargingStation->getChargeDelay()) {
265 : // Enable charging vehicle
266 31787 : myActChargingStation->setChargingVehicle(true);
267 :
268 : // Calulate energy charged
269 35003 : myEnergyCharged = MIN2(MIN2(myActChargingStation->getChargingPower(myTrackFuel) * myActChargingStation->getEfficency(), getMaximumChargeRate()) * TS, getMaximumBatteryCapacity() - getActualBatteryCapacity());
270 :
271 : // Update Battery charge
272 31787 : setActualBatteryCapacity(getActualBatteryCapacity() + myEnergyCharged);
273 : }
274 : // add charge value for output to myActChargingStation
275 32698 : myActChargingStation->addChargeValueForOutput(myEnergyCharged, this);
276 : }
277 : // else disable charging vehicle
278 : else {
279 1996 : cs->setChargingVehicle(false);
280 : }
281 : // disable charging vehicle from previous (not current) ChargingStation (reason: if there is no gap between two different chargingStations = the vehicle switches from used charging station to other one in a single timestap)
282 34694 : if (myPreviousNeighbouringChargingStation != nullptr && myPreviousNeighbouringChargingStation != cs) {
283 452 : myPreviousNeighbouringChargingStation->setChargingVehicle(false);
284 : }
285 34694 : myPreviousNeighbouringChargingStation = cs;
286 : }
287 : // In other case, vehicle will be not charged
288 : else {
289 : // Disable flags
290 338604 : myChargingInTransit = false;
291 338604 : myChargingStopped = false;
292 :
293 : // Disable charging vehicle
294 338604 : if (myActChargingStation != nullptr) {
295 504 : myActChargingStation->setChargingVehicle(false);
296 : }
297 :
298 : // Set charging station pointer to NULL
299 338604 : myActChargingStation = nullptr;
300 :
301 : // Set energy charged to 0
302 338604 : myEnergyCharged = 0.00;
303 :
304 : // Reset timer
305 338604 : resetChargingStartTime();
306 : }
307 :
308 : // Always return true.
309 : return true;
310 : }
311 :
312 :
313 : void
314 0 : MSDevice_Battery::saveState(OutputDevice& out) const {
315 0 : out.openTag(SUMO_TAG_DEVICE);
316 : out.writeAttr(SUMO_ATTR_ID, getID());
317 : std::vector<std::string> internals;
318 0 : internals.push_back(toString(myActualBatteryCapacity));
319 0 : internals.push_back(toString(myLastAngle));
320 0 : internals.push_back(toString(myChargingStopped));
321 0 : internals.push_back(toString(myChargingInTransit));
322 0 : internals.push_back(toString(myChargingStartTime));
323 0 : internals.push_back(toString(myTotalConsumption));
324 0 : internals.push_back(toString(myTotalRegenerated));
325 0 : internals.push_back(toString(myEnergyCharged));
326 0 : internals.push_back(toString(myVehicleStopped));
327 0 : internals.push_back(getChargingStationID());
328 0 : std::string prevChargingID = (myPreviousNeighbouringChargingStation == nullptr) ? "NULL" : myPreviousNeighbouringChargingStation->getID();
329 0 : internals.push_back(prevChargingID);
330 0 : internals.push_back(toString(myMaximumChargeRate));
331 0 : out.writeAttr(SUMO_ATTR_STATE, toString(internals));
332 0 : out.closeTag();
333 0 : }
334 :
335 :
336 : void
337 0 : MSDevice_Battery::loadState(const SUMOSAXAttributes& attrs) {
338 0 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
339 0 : bis >> myActualBatteryCapacity;
340 0 : bis >> myLastAngle;
341 0 : bis >> myChargingStopped;
342 0 : bis >> myChargingInTransit;
343 0 : bis >> myChargingStartTime;
344 0 : bis >> myTotalConsumption;
345 0 : bis >> myTotalRegenerated;
346 0 : bis >> myEnergyCharged;
347 0 : bis >> myVehicleStopped;
348 : std::string chargingID;
349 0 : bis >> chargingID;
350 0 : if (chargingID != "NULL") {
351 0 : myActChargingStation = dynamic_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(chargingID, SUMO_TAG_CHARGING_STATION));
352 : }
353 : std::string prevChargingID;
354 0 : bis >> prevChargingID;
355 0 : if (prevChargingID != "NULL") {
356 0 : myPreviousNeighbouringChargingStation = dynamic_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(prevChargingID, SUMO_TAG_CHARGING_STATION));
357 : }
358 0 : bis >> myMaximumChargeRate;
359 0 : }
360 :
361 :
362 : void
363 405085 : MSDevice_Battery::setActualBatteryCapacity(const double actualBatteryCapacity) {
364 405085 : if (actualBatteryCapacity < 0) {
365 1418 : myActualBatteryCapacity = 0;
366 403667 : } else if (actualBatteryCapacity > myMaximumBatteryCapacity) {
367 4 : myActualBatteryCapacity = myMaximumBatteryCapacity;
368 : } else {
369 403663 : myActualBatteryCapacity = actualBatteryCapacity;
370 : }
371 405085 : }
372 :
373 :
374 : void
375 9 : MSDevice_Battery::setMaximumBatteryCapacity(const double maximumBatteryCapacity) {
376 9 : if (myMaximumBatteryCapacity < 0) {
377 0 : WRITE_WARNINGF(TL("Trying to set into the battery device of vehicle '%' an invalid % (%)."), getID(), toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY), toString(maximumBatteryCapacity));
378 : } else {
379 9 : myMaximumBatteryCapacity = maximumBatteryCapacity;
380 : }
381 9 : }
382 :
383 :
384 : void
385 0 : MSDevice_Battery::setStoppingThreshold(const double stoppingThreshold) {
386 0 : if (stoppingThreshold < 0) {
387 0 : WRITE_WARNINGF(TL("Trying to set into the battery device of vehicle '%' an invalid % (%)."), getID(), toString(SUMO_ATTR_STOPPINGTHRESHOLD), toString(stoppingThreshold));
388 : } else {
389 0 : myStoppingThreshold = stoppingThreshold;
390 : }
391 0 : }
392 :
393 :
394 : void
395 0 : MSDevice_Battery::setMaximumChargeRate(const double chargeRate) {
396 0 : if (chargeRate < 0) {
397 0 : WRITE_WARNINGF(TL("Trying to set into the battery device of vehicle '%' an invalid % (%)."), getID(), toString(SUMO_ATTR_MAXIMUMCHARGERATE), toString(chargeRate));
398 : } else {
399 0 : myMaximumChargeRate = chargeRate;
400 : }
401 0 : }
402 :
403 :
404 : void
405 8 : MSDevice_Battery::setChargeLimit(const double limit) {
406 8 : myChargeLimit = limit;
407 8 : }
408 :
409 :
410 : void
411 338604 : MSDevice_Battery::resetChargingStartTime() {
412 338604 : myChargingStartTime = 0;
413 338604 : }
414 :
415 :
416 : void
417 32698 : MSDevice_Battery::increaseChargingStartTime() {
418 32698 : myChargingStartTime += DELTA_T;
419 32698 : }
420 :
421 :
422 : void
423 239366 : MSDevice_Battery::resetVehicleStoppedTimer() {
424 239366 : myVehicleStopped = 0;
425 239366 : }
426 :
427 :
428 : void
429 133932 : MSDevice_Battery::increaseVehicleStoppedTimer() {
430 133932 : myVehicleStopped++;
431 133932 : }
432 :
433 :
434 : double
435 1173700 : MSDevice_Battery::getActualBatteryCapacity() const {
436 1173700 : return myActualBatteryCapacity;
437 : }
438 :
439 :
440 : double
441 1083011 : MSDevice_Battery::getMaximumBatteryCapacity() const {
442 1083011 : return myMaximumBatteryCapacity;
443 : }
444 :
445 :
446 : double
447 315839 : MSDevice_Battery::getConsum() const {
448 315839 : return myConsum;
449 : }
450 :
451 : double
452 315919 : MSDevice_Battery::getTotalConsumption() const {
453 315919 : return myTotalConsumption;
454 : }
455 :
456 :
457 : double
458 315839 : MSDevice_Battery::getTotalRegenerated() const {
459 315839 : return myTotalRegenerated;
460 : }
461 :
462 :
463 : bool
464 315749 : MSDevice_Battery::isChargingStopped() const {
465 315749 : return myChargingStopped;
466 : }
467 :
468 :
469 : bool
470 315749 : MSDevice_Battery::isChargingInTransit() const {
471 315749 : return myChargingInTransit;
472 : }
473 :
474 :
475 : SUMOTime
476 63733 : MSDevice_Battery::getChargingStartTime() const {
477 63733 : return myChargingStartTime;
478 : }
479 :
480 :
481 : SUMOTime
482 0 : MSDevice_Battery::estimateChargingDuration(const double toCharge, const double csPower) const {
483 : //if (!myChargeCurve.empty()) {
484 : // // TODO: integrate charge curve
485 : //}
486 0 : return TIME2STEPS(toCharge / MIN2(csPower, myMaximumChargeRate));
487 : }
488 :
489 :
490 : std::string
491 353859 : MSDevice_Battery::getChargingStationID() const {
492 353859 : if (myActChargingStation != nullptr) {
493 : return myActChargingStation->getID();
494 : } else {
495 301562 : return "NULL";
496 : }
497 : }
498 :
499 : double
500 395752 : MSDevice_Battery::getEnergyCharged() const {
501 395752 : return myEnergyCharged;
502 : }
503 :
504 :
505 : int
506 315749 : MSDevice_Battery::getVehicleStopped() const {
507 315749 : return myVehicleStopped;
508 : }
509 :
510 :
511 : double
512 30695 : MSDevice_Battery::getStoppingThreshold() const {
513 30695 : return myStoppingThreshold;
514 : }
515 :
516 :
517 : double
518 31787 : MSDevice_Battery::getMaximumChargeRate() const {
519 31787 : double baseVal = (myChargeCurve.empty()) ? myMaximumChargeRate : LinearApproxHelpers::getInterpolatedValue(myChargeCurve, myActualBatteryCapacity / myMaximumBatteryCapacity);
520 31787 : return (myChargeLimit < 0) ? baseVal : MIN2(myChargeLimit, baseVal);
521 : }
522 :
523 :
524 : std::string
525 738 : MSDevice_Battery::getParameter(const std::string& key) const {
526 1476 : if (key == toString(SUMO_ATTR_ACTUALBATTERYCAPACITY)
527 1476 : || key == toString(SUMO_ATTR_CHARGELEVEL)) {
528 90 : return toString(getActualBatteryCapacity());
529 648 : } else if (key == toString(SUMO_ATTR_ENERGYCONSUMED)) {
530 90 : return toString(getConsum());
531 558 : } else if (key == toString(SUMO_ATTR_TOTALENERGYCONSUMED)) {
532 90 : return toString(getTotalConsumption());
533 468 : } else if (key == toString(SUMO_ATTR_TOTALENERGYREGENERATED)) {
534 90 : return toString(getTotalRegenerated());
535 378 : } else if (key == toString(SUMO_ATTR_ENERGYCHARGED)) {
536 90 : return toString(getEnergyCharged());
537 576 : } else if (key == toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY) || key == "capacity") {
538 99 : return toString(getMaximumBatteryCapacity());
539 189 : } else if (key == toString(SUMO_ATTR_MAXIMUMCHARGERATE)) {
540 0 : return toString(getMaximumChargeRate());
541 189 : } else if (key == toString(SUMO_ATTR_CHARGINGSTATIONID)) {
542 90 : return getChargingStationID();
543 99 : } else if (key == toString(SUMO_ATTR_VEHICLEMASS)) {
544 90 : WRITE_WARNING(TL("Getting the vehicle mass via parameters is deprecated, please use getMass for the vehicle or its type."));
545 90 : return toString(myHolder.getEmissionParameters()->getDouble(SUMO_ATTR_MASS));
546 : }
547 18 : throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
548 : }
549 :
550 :
551 : void
552 18 : MSDevice_Battery::setParameter(const std::string& key, const std::string& value) {
553 : double doubleValue;
554 : try {
555 18 : doubleValue = StringUtils::toDouble(value);
556 0 : } catch (NumberFormatException&) {
557 0 : throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
558 0 : }
559 36 : if (key == toString(SUMO_ATTR_ACTUALBATTERYCAPACITY) || key == toString(SUMO_ATTR_CHARGELEVEL)) {
560 0 : setActualBatteryCapacity(doubleValue);
561 36 : } else if (key == toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY) || key == "capacity") {
562 9 : setMaximumBatteryCapacity(doubleValue);
563 9 : } else if (key == toString(SUMO_ATTR_MAXIMUMCHARGERATE)) {
564 0 : setMaximumChargeRate(doubleValue);
565 9 : } else if (key == toString(SUMO_ATTR_VEHICLEMASS)) {
566 9 : WRITE_WARNING(TL("Setting the vehicle mass via parameters is deprecated, please use setMass for the vehicle or its type."));
567 9 : myHolder.getEmissionParameters()->setDouble(SUMO_ATTR_MASS, doubleValue);
568 : } else {
569 0 : throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
570 : }
571 18 : }
572 :
573 :
574 : void
575 400 : MSDevice_Battery::notifyParking() {
576 : // @note: only charing is performed but no energy is consumed
577 400 : notifyMove(myHolder, myHolder.getPositionOnLane(), myHolder.getPositionOnLane(), myHolder.getSpeed());
578 400 : myConsum = 0;
579 400 : }
580 :
581 :
582 : void
583 1577 : MSDevice_Battery::generateOutput(OutputDevice* tripinfoOut) const {
584 1577 : if (tripinfoOut != nullptr) {
585 167 : tripinfoOut->openTag("battery");
586 334 : tripinfoOut->writeAttr("depleted", toString(myDepletedCount));
587 334 : tripinfoOut->closeTag();
588 : }
589 1577 : }
590 :
591 :
592 : /****************************************************************************/
|