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