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 39900 : MSDevice_Battery::insertOptions(OptionsCont& oc) {
52 79800 : insertDefaultAssignmentOptions("battery", "Battery", oc);
53 : // custom options
54 39900 : oc.doRegister("device.battery.track-fuel", new Option_Bool(false));
55 79800 : oc.addDescription("device.battery.track-fuel", "Battery", TL("Track fuel consumption for non-electric vehicles"));
56 39900 : }
57 :
58 :
59 : void
60 5382009 : MSDevice_Battery::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, MSDevice_StationFinder* sf) {
61 : // Check if vehicle should get a battery
62 10763910 : if (sf != nullptr || equippedByDefaultAssignmentOptions(OptionsCont::getOptions(), "battery", v, false)) {
63 : // obtain parameter values
64 1701 : const double maximumBatteryCapacity = readParameterValue(v, SUMO_ATTR_MAXIMUMBATTERYCAPACITY, "battery.capacity", DEFAULT_MAX_CAPACITY);
65 1701 : const double actualBatteryCapacity = readParameterValue(v, SUMO_ATTR_ACTUALBATTERYCAPACITY, "battery.chargeLevel", maximumBatteryCapacity * DEFAULT_CHARGE_RATIO);
66 1701 : const double stoppingThreshold = readParameterValue(v, SUMO_ATTR_STOPPINGTHRESHOLD, "battery.stoppingThreshold", 0.1);
67 1701 : const double maximumChargeRate = readParameterValue(v, SUMO_ATTR_MAXIMUMCHARGERATE, "battery.maximumChargeRate", 150000.);
68 3402 : const std::string chargeLevelTable = v.getStringParam("device.battery.chargeLevelTable");
69 3402 : const std::string chargeCurveTable = v.getStringParam("device.battery.chargeCurveTable");
70 :
71 : // battery constructor
72 1701 : MSDevice_Battery* device = new MSDevice_Battery(v, "battery_" + v.getID(),
73 3402 : actualBatteryCapacity, maximumBatteryCapacity, stoppingThreshold, maximumChargeRate, chargeLevelTable, chargeCurveTable);
74 :
75 : // Add device to vehicle
76 1701 : into.push_back(device);
77 :
78 1701 : if (sf != nullptr) {
79 : sf->setBattery(device);
80 : }
81 : // ensure that parameters are initialized
82 1701 : v.getEmissionParameters();
83 : }
84 5382009 : }
85 :
86 :
87 : double
88 6804 : MSDevice_Battery::readParameterValue(SUMOVehicle& v, const SumoXMLAttr& attr, const std::string& paramName, double defaultVal) {
89 6804 : const std::string& oldParam = toString(attr);
90 6804 : const SUMOVTypeParameter& typeParams = v.getVehicleType().getParameter();
91 6804 : 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 13608 : return v.getFloatParam("device." + paramName, false, defaultVal);
99 : }
100 :
101 :
102 : // ---------------------------------------------------------------------------
103 : // MSDevice_Battery-methods
104 : // ---------------------------------------------------------------------------
105 1701 : MSDevice_Battery::MSDevice_Battery(SUMOVehicle& holder, const std::string& id, const double actualBatteryCapacity, const double maximumBatteryCapacity,
106 1701 : const double stoppingThreshold, const double maximumChargeRate, const std::string& chargeLevelTable, const std::string& chargeCurveTable) :
107 : MSVehicleDevice(holder, id),
108 1701 : myActualBatteryCapacity(0), // [actualBatteryCapacity <= maximumBatteryCapacity]
109 1701 : myMaximumBatteryCapacity(0), // [maximumBatteryCapacity >= 0]
110 1701 : myStoppingThreshold(0), // [stoppingThreshold >= 0]
111 1701 : myMaximumChargeRate(0),
112 1701 : myChargeLimit(-1),
113 1701 : myLastAngle(std::numeric_limits<double>::infinity()),
114 1701 : myChargingStopped(false), // Initially vehicle don't charge stopped
115 1701 : myChargingInTransit(false), // Initially vehicle don't charge in transit
116 1701 : myChargingStartTime(0), // Initially charging start time (must be if the vehicle was launched at the charging station)
117 1701 : myConsum(0), // Initially the vehicle is stopped and therefore the consum is zero.
118 1701 : myTotalConsumption(0.0),
119 1701 : myTotalRegenerated(0.0),
120 1701 : myActChargingStation(nullptr), // Initially the vehicle isn't over a Charging Station
121 1701 : myPreviousNeighbouringChargingStation(nullptr), // Initially the vehicle wasn't over a Charging Station
122 1701 : myEnergyCharged(0), // Initially the energy charged is zero
123 1701 : myVehicleStopped(0),
124 1701 : myDepletedCount(0) {
125 : // Initially the vehicle is stopped and the corresponding variable is 0
126 :
127 1701 : 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 1701 : myMaximumBatteryCapacity = maximumBatteryCapacity;
131 : }
132 :
133 1701 : 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 1701 : myActualBatteryCapacity = actualBatteryCapacity;
139 : }
140 :
141 1701 : 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 1701 : myStoppingThreshold = stoppingThreshold;
145 : }
146 :
147 1741 : myTrackFuel = PollutantsInterface::getFuel(holder.getVehicleType().getEmissionClass()) != "Electricity" && OptionsCont::getOptions().getBool("device.battery.track-fuel");
148 1701 : 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 1701 : myChargeType = (myTrackFuel) ? MSChargingStation::ChargeType::CHARGETYPE_FUEL : MSChargingStation::ChargeType::CHARGETYPE_NORMAL;
154 :
155 1701 : 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 1701 : if (!chargeLevelTable.empty() && !chargeCurveTable.empty()) {
159 0 : LinearApproxHelpers::setPoints(myChargeCurve, chargeLevelTable, chargeCurveTable);
160 0 : myMaximumChargeRate = LinearApproxHelpers::getMaximumValue(myChargeCurve);
161 : } else {
162 1701 : myMaximumChargeRate = maximumChargeRate;
163 : }
164 : }
165 1701 : }
166 :
167 :
168 3402 : MSDevice_Battery::~MSDevice_Battery() {
169 3402 : }
170 :
171 :
172 447939 : bool MSDevice_Battery::notifyMove(SUMOTrafficObject& tObject, double /* oldPos */, double /* newPos */, double /* newSpeed */) {
173 447939 : 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 447939 : if (veh.getSpeed() < myStoppingThreshold) {
179 : // Increase vehicle stopped timer
180 206541 : increaseVehicleStoppedTimer();
181 : } else {
182 : // Reset vehicle Stopped
183 241398 : resetVehicleStoppedTimer();
184 : }
185 :
186 : // Update Energy from the battery
187 447939 : EnergyParams* const params = myHolder.getEmissionParameters();
188 447939 : if (getMaximumBatteryCapacity() != 0) {
189 447939 : 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 447494 : myConsum = PollutantsInterface::compute(veh.getVehicleType().getEmissionClass(),
195 447494 : myTrackFuel ? PollutantsInterface::FUEL : PollutantsInterface::ELEC,
196 447494 : veh.getSpeed(), veh.getAcceleration(),
197 894988 : veh.getSlope(), params) * TS;
198 : }
199 447939 : if (veh.isParking()) {
200 : // recuperation from last braking step is ok but further consumption should cease
201 1184 : myConsum = MIN2(myConsum, 0.0);
202 : }
203 :
204 : // saturate between 0 and myMaximumBatteryCapacity [Wh]
205 447939 : if (myConsum > getActualBatteryCapacity() && getActualBatteryCapacity() > 0 && getMaximumBatteryCapacity() > 0) {
206 32 : myDepletedCount++;
207 32 : if (myDepletedCount == 1) {
208 48 : 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 447939 : setActualBatteryCapacity(getActualBatteryCapacity() - myConsum);
214 :
215 : // Track total energy consumption and regeneration
216 447939 : if (myConsum > 0.0) {
217 325182 : myTotalConsumption += myConsum;
218 : } else {
219 122757 : myTotalRegenerated -= myConsum;
220 : }
221 :
222 447939 : myLastAngle = veh.getAngle();
223 : }
224 :
225 : // Check if vehicle has under their position one charge Station
226 447939 : 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 447939 : if (chargingStationID != "") {
230 : // if the vehicle is almost stopped, or charge in transit is enabled, then charge vehicle
231 103550 : MSChargingStation* const cs = static_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(chargingStationID, SUMO_TAG_CHARGING_STATION));
232 103550 : const MSParkingArea* pa = cs->getParkingArea();
233 103550 : if (((veh.getSpeed() < myStoppingThreshold) || cs->getChargeInTransit()) && (pa == nullptr || veh.isParking()) && cs->getChargeType() == myChargeType) {
234 : // Set Flags Stopped/intransit to
235 101336 : if (veh.getSpeed() < myStoppingThreshold) {
236 : // vehicle ist almost stopped, then is charging stopped
237 100005 : myChargingStopped = true;
238 :
239 : // therefore isn't charging in transit
240 100005 : myChargingInTransit = false;
241 : } else {
242 : // vehicle is moving, and the Charging station allow charge in transit
243 1331 : myChargingStopped = false;
244 :
245 : // Therefore charge in transit
246 1331 : myChargingInTransit = true;
247 : }
248 :
249 : // get pointer to charging station
250 101336 : 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 101336 : if ((myActChargingStation->getChargeInTransit()) || (veh.getSpeed() < myStoppingThreshold)) {
255 : // Update Charging start time
256 101336 : increaseChargingStartTime();
257 : }
258 :
259 : // time it takes the vehicle at the station < charging station time delay?
260 101336 : if (getChargingStartTime() > myActChargingStation->getChargeDelay()) {
261 : // Enable charging vehicle
262 100381 : myActChargingStation->setChargingVehicle(true);
263 :
264 : // Calulate energy charged
265 203634 : myEnergyCharged = MIN2(MIN2(myActChargingStation->getChargingPower(myTrackFuel) * myActChargingStation->getEfficency(), getMaximumChargeRate() * (myTrackFuel ? 1 : 1. / 3600.)) * TS, getMaximumBatteryCapacity() - getActualBatteryCapacity());
266 :
267 : // Update Battery charge
268 100381 : setActualBatteryCapacity(getActualBatteryCapacity() + myEnergyCharged);
269 : }
270 : // add charge value for output to myActChargingStation
271 101336 : myActChargingStation->addChargeValueForOutput(myEnergyCharged, this);
272 : }
273 : // else disable charging vehicle
274 : else {
275 2214 : 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 103550 : if (myPreviousNeighbouringChargingStation != nullptr && myPreviousNeighbouringChargingStation != cs) {
279 485 : myPreviousNeighbouringChargingStation->setChargingVehicle(false);
280 : }
281 103550 : myPreviousNeighbouringChargingStation = cs;
282 : }
283 : // In other case, vehicle will be not charged
284 : else {
285 : // Disable flags
286 344389 : myChargingInTransit = false;
287 344389 : myChargingStopped = false;
288 :
289 : // Disable charging vehicle
290 344389 : if (myActChargingStation != nullptr) {
291 556 : myActChargingStation->setChargingVehicle(false);
292 : }
293 :
294 : // Set charging station pointer to NULL
295 344389 : myActChargingStation = nullptr;
296 :
297 : // Set energy charged to 0
298 344389 : myEnergyCharged = 0;
299 :
300 : // Reset timer
301 344389 : 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 548520 : MSDevice_Battery::setActualBatteryCapacity(const double actualBatteryCapacity) {
360 548520 : if (actualBatteryCapacity < 0) {
361 1340 : myActualBatteryCapacity = 0;
362 547180 : } else if (actualBatteryCapacity > myMaximumBatteryCapacity) {
363 4 : myActualBatteryCapacity = myMaximumBatteryCapacity;
364 : } else {
365 547176 : myActualBatteryCapacity = actualBatteryCapacity;
366 : }
367 548520 : }
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 8 : MSDevice_Battery::setChargeLimit(const double limit) {
402 8 : myChargeLimit = limit;
403 8 : }
404 :
405 :
406 : void
407 344389 : MSDevice_Battery::resetChargingStartTime() {
408 344389 : myChargingStartTime = 0;
409 344389 : }
410 :
411 :
412 : void
413 101336 : MSDevice_Battery::increaseChargingStartTime() {
414 101336 : myChargingStartTime += DELTA_T;
415 101336 : }
416 :
417 :
418 : void
419 241398 : MSDevice_Battery::resetVehicleStoppedTimer() {
420 241398 : myVehicleStopped = 0;
421 241398 : }
422 :
423 :
424 : void
425 206541 : MSDevice_Battery::increaseVehicleStoppedTimer() {
426 206541 : myVehicleStopped++;
427 206541 : }
428 :
429 :
430 : void
431 200 : MSDevice_Battery::setEnergyCharged(const double energyCharged) {
432 200 : myEnergyCharged = energyCharged;
433 200 : }
434 :
435 :
436 : double
437 1368033 : MSDevice_Battery::getActualBatteryCapacity() const {
438 1368033 : return myActualBatteryCapacity;
439 : }
440 :
441 :
442 : double
443 938493 : MSDevice_Battery::getMaximumBatteryCapacity() const {
444 938493 : return myMaximumBatteryCapacity;
445 : }
446 :
447 :
448 : double
449 119416 : MSDevice_Battery::getConsum() const {
450 119416 : return myConsum;
451 : }
452 :
453 : double
454 120473 : MSDevice_Battery::getTotalConsumption() const {
455 120473 : return myTotalConsumption;
456 : }
457 :
458 :
459 : double
460 119416 : MSDevice_Battery::getTotalRegenerated() const {
461 119416 : return myTotalRegenerated;
462 : }
463 :
464 :
465 : bool
466 119326 : MSDevice_Battery::isChargingStopped() const {
467 119326 : return myChargingStopped;
468 : }
469 :
470 :
471 : bool
472 119326 : MSDevice_Battery::isChargingInTransit() const {
473 119326 : return myChargingInTransit;
474 : }
475 :
476 :
477 : SUMOTime
478 200945 : MSDevice_Battery::getChargingStartTime() const {
479 200945 : return myChargingStartTime;
480 : }
481 :
482 :
483 : SUMOTime
484 0 : MSDevice_Battery::estimateChargingDuration(const double toCharge, const double csPower) const {
485 : //if (!myChargeCurve.empty()) {
486 : // // TODO: integrate charge curve
487 : //}
488 0 : return TIME2STEPS(toCharge / MIN2(csPower, myMaximumChargeRate));
489 : }
490 :
491 :
492 : std::string
493 119416 : MSDevice_Battery::getChargingStationID() const {
494 119416 : if (myActChargingStation != nullptr) {
495 : return myActChargingStation->getID();
496 : } else {
497 90580 : return "NULL";
498 : }
499 : }
500 :
501 : double
502 287626 : MSDevice_Battery::getEnergyCharged() const {
503 287626 : return myEnergyCharged;
504 : }
505 :
506 :
507 : int
508 119326 : MSDevice_Battery::getVehicleStopped() const {
509 119326 : return myVehicleStopped;
510 : }
511 :
512 :
513 : double
514 99241 : MSDevice_Battery::getStoppingThreshold() const {
515 99241 : return myStoppingThreshold;
516 : }
517 :
518 :
519 : double
520 100381 : MSDevice_Battery::getMaximumChargeRate() const {
521 100381 : double baseVal = (myChargeCurve.empty()) ? myMaximumChargeRate : LinearApproxHelpers::getInterpolatedValue(myChargeCurve, myActualBatteryCapacity / myMaximumBatteryCapacity);
522 100381 : return (myChargeLimit < 0) ? baseVal : MIN2(myChargeLimit, baseVal);
523 : }
524 :
525 :
526 : bool
527 108 : MSDevice_Battery::tracksFuel() const {
528 108 : return myTrackFuel;
529 : }
530 :
531 :
532 : MSChargingStation::ChargeType
533 504 : MSDevice_Battery::getChargeType() const {
534 504 : return myChargeType;
535 : }
536 :
537 :
538 : std::string
539 768 : MSDevice_Battery::getParameter(const std::string& key) const {
540 1536 : if (key == toString(SUMO_ATTR_ACTUALBATTERYCAPACITY)
541 1536 : || key == toString(SUMO_ATTR_CHARGELEVEL)) {
542 90 : return toString(getActualBatteryCapacity());
543 678 : } else if (key == toString(SUMO_ATTR_ENERGYCONSUMED)) {
544 90 : return toString(getConsum());
545 588 : } else if (key == "chargePower") {
546 60 : return toString(getEnergyCharged() * 3600.);
547 528 : } else if (key == "usedAverage") {
548 60 : return toString(getTotalConsumption() * 3600 / STEPS2TIME(SIMSTEP - myHolder.getDeparture()));
549 468 : } else if (key == toString(SUMO_ATTR_TOTALENERGYCONSUMED)) {
550 90 : return toString(getTotalConsumption());
551 378 : } else if (key == toString(SUMO_ATTR_TOTALENERGYREGENERATED)) {
552 90 : return toString(getTotalRegenerated());
553 288 : } else if (key == toString(SUMO_ATTR_ENERGYCHARGED)) {
554 90 : return toString(getEnergyCharged());
555 396 : } else if (key == toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY) || key == "capacity") {
556 99 : return toString(getMaximumBatteryCapacity());
557 99 : } else if (key == toString(SUMO_ATTR_MAXIMUMCHARGERATE)) {
558 0 : return toString(getMaximumChargeRate());
559 99 : } else if (key == toString(SUMO_ATTR_CHARGINGSTATIONID)) {
560 90 : return getChargingStationID();
561 : }
562 27 : throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
563 : }
564 :
565 :
566 : void
567 9 : MSDevice_Battery::setParameter(const std::string& key, const std::string& value) {
568 : double doubleValue;
569 : try {
570 9 : doubleValue = StringUtils::toDouble(value);
571 0 : } catch (NumberFormatException&) {
572 0 : throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
573 0 : }
574 18 : if (key == toString(SUMO_ATTR_ACTUALBATTERYCAPACITY) || key == toString(SUMO_ATTR_CHARGELEVEL)) {
575 0 : setActualBatteryCapacity(doubleValue);
576 18 : } else if (key == toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY) || key == "capacity") {
577 9 : setMaximumBatteryCapacity(doubleValue);
578 0 : } else if (key == toString(SUMO_ATTR_MAXIMUMCHARGERATE)) {
579 0 : setMaximumChargeRate(doubleValue);
580 : } else {
581 0 : throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
582 : }
583 9 : }
584 :
585 :
586 : void
587 560 : MSDevice_Battery::notifyParking() {
588 : // @note: only charing is performed but no energy is consumed
589 560 : notifyMove(myHolder, myHolder.getPositionOnLane(), myHolder.getPositionOnLane(), myHolder.getSpeed());
590 560 : myConsum = 0;
591 560 : }
592 :
593 :
594 : void
595 1619 : MSDevice_Battery::generateOutput(OutputDevice* tripinfoOut) const {
596 1619 : if (tripinfoOut != nullptr) {
597 209 : tripinfoOut->openTag("battery");
598 418 : tripinfoOut->writeAttr("depleted", toString(myDepletedCount));
599 418 : tripinfoOut->writeAttr("actualBatteryCapacity", toString(myActualBatteryCapacity));
600 418 : tripinfoOut->writeAttr("totalEnergyConsumed", toString(myTotalConsumption));
601 418 : tripinfoOut->writeAttr("totalEnergyRegenerated", toString(myTotalRegenerated));
602 418 : tripinfoOut->closeTag();
603 : }
604 1619 : }
605 :
606 :
607 : /****************************************************************************/
|