Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2013-2026 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 42243 : MSDevice_Battery::insertOptions(OptionsCont& oc) {
52 84486 : insertDefaultAssignmentOptions("battery", "Battery", oc);
53 : // custom options
54 42243 : oc.doRegister("device.battery.track-fuel", new Option_Bool(false));
55 84486 : oc.addDescription("device.battery.track-fuel", "Battery", TL("Track fuel consumption for non-electric vehicles"));
56 42243 : }
57 :
58 :
59 : void
60 5537923 : MSDevice_Battery::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, MSDevice_StationFinder* sf) {
61 : // Check if vehicle should get a battery
62 11075738 : 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 5537923 : }
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 447939 : notifyMoveInternal(tObject, 0., TS, 0., newSpeed, 0., 0., 0.);
177 447939 : return true;
178 : }
179 :
180 :
181 : void
182 456811 : MSDevice_Battery::notifyMoveInternal(const SUMOTrafficObject& tObject,
183 : const double /* frontOnLane */,
184 : const double timeOnLane,
185 : const double /* meanSpeedFrontOnLane */,
186 : const double meanSpeedVehicleOnLane,
187 : const double /* travelledDistanceFrontOnLane */,
188 : const double /* travelledDistanceVehicleOnLane */,
189 : const double /* meanLengthOnLane */) {
190 : const SUMOVehicle& veh = static_cast<const SUMOVehicle&>(tObject);
191 : // Start vehicleStoppedTimer if the vehicle is stopped. In other case reset timer
192 456811 : if (meanSpeedVehicleOnLane < myStoppingThreshold) {
193 : // Increase vehicle stopped timer
194 206541 : increaseVehicleStoppedTimer();
195 : } else {
196 : // Reset vehicle Stopped
197 250270 : resetVehicleStoppedTimer();
198 : }
199 :
200 : // Update Energy from the battery
201 456811 : EnergyParams* const params = myHolder.getEmissionParameters();
202 456811 : if (getMaximumBatteryCapacity() != 0) {
203 456811 : if (!myTrackFuel && !veh.getVehicleType().getParameter().wasSet(VTYPEPARS_EMISSIONCLASS_SET)) {
204 : // no explicit emission class, we fall back to the energy model; a warning has been issued on creation
205 1066 : myConsum = PollutantsInterface::getEnergyHelper().compute(0, PollutantsInterface::ELEC, meanSpeedVehicleOnLane, veh.getAcceleration(),
206 1066 : veh.getSlope(), params) * timeOnLane;
207 : } else {
208 456278 : myConsum = PollutantsInterface::compute(veh.getVehicleType().getEmissionClass(),
209 456278 : myTrackFuel ? PollutantsInterface::FUEL : PollutantsInterface::ELEC,
210 456278 : meanSpeedVehicleOnLane, veh.getAcceleration(),
211 912556 : veh.getSlope(), params) * timeOnLane;
212 : }
213 456811 : if (veh.isParking()) {
214 : // recuperation from last braking step is ok but further consumption should cease
215 1184 : myConsum = MIN2(myConsum, 0.0);
216 : }
217 :
218 : // saturate between 0 and myMaximumBatteryCapacity [Wh]
219 456811 : if (myConsum > getActualBatteryCapacity() && getActualBatteryCapacity() > 0 && getMaximumBatteryCapacity() > 0) {
220 32 : myDepletedCount++;
221 32 : if (myDepletedCount == 1) {
222 48 : WRITE_WARNINGF(TL("Battery of vehicle '%' is depleted, time=%."), veh.getID(), time2string(SIMSTEP));
223 : }
224 : }
225 :
226 : // Energy lost/gained from vehicle movement (via vehicle energy model) [Wh]
227 456811 : setActualBatteryCapacity(getActualBatteryCapacity() - myConsum);
228 :
229 : // Track total energy consumption and regeneration
230 456811 : if (myConsum > 0.0) {
231 333254 : myTotalConsumption += myConsum;
232 : } else {
233 123557 : myTotalRegenerated -= myConsum;
234 : }
235 :
236 456811 : myLastAngle = veh.getAngle();
237 : }
238 :
239 : // Check if vehicle has under their position one charge Station
240 456811 : const std::string chargingStationID = MSNet::getInstance()->getStoppingPlaceID(veh.getLane(), veh.getPositionOnLane(), SUMO_TAG_CHARGING_STATION);
241 :
242 : // If vehicle is over a charging station
243 456811 : if (chargingStationID != "") {
244 : // if the vehicle is almost stopped, or charge in transit is enabled, then charge vehicle
245 103550 : MSChargingStation* const cs = static_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(chargingStationID, SUMO_TAG_CHARGING_STATION));
246 103550 : const MSParkingArea* pa = cs->getParkingArea();
247 103550 : if (((meanSpeedVehicleOnLane < myStoppingThreshold) || cs->getChargeInTransit()) && (pa == nullptr || veh.isParking()) && cs->getChargeType() == myChargeType) {
248 : // Set Flags Stopped/intransit to
249 101336 : if (meanSpeedVehicleOnLane < myStoppingThreshold) {
250 : // vehicle ist almost stopped, then is charging stopped
251 100005 : myChargingStopped = true;
252 :
253 : // therefore isn't charging in transit
254 100005 : myChargingInTransit = false;
255 : } else {
256 : // vehicle is moving, and the Charging station allow charge in transit
257 1331 : myChargingStopped = false;
258 :
259 : // Therefore charge in transit
260 1331 : myChargingInTransit = true;
261 : }
262 :
263 : // get pointer to charging station
264 101336 : myActChargingStation = cs;
265 :
266 : // Only update charging start time if vehicle allow charge in transit, or in other case
267 : // if the vehicle not allow charge in transit but it's stopped.
268 101336 : if ((myActChargingStation->getChargeInTransit()) || (meanSpeedVehicleOnLane < myStoppingThreshold)) {
269 : // Update Charging start time
270 101336 : increaseChargingStartTime();
271 : }
272 :
273 : // time it takes the vehicle at the station < charging station time delay?
274 101336 : if (getChargingStartTime() > myActChargingStation->getChargeDelay()) {
275 : // Enable charging vehicle
276 100381 : myActChargingStation->setChargingVehicle(true);
277 :
278 : // Calulate energy charged
279 203634 : myEnergyCharged = MIN2(MIN2(myActChargingStation->getChargingPower(myTrackFuel) * myActChargingStation->getEfficency(), getMaximumChargeRate() * (myTrackFuel ? 1 : 1. / 3600.)) * timeOnLane, getMaximumBatteryCapacity() - getActualBatteryCapacity());
280 :
281 : // Update Battery charge
282 100381 : setActualBatteryCapacity(getActualBatteryCapacity() + myEnergyCharged);
283 : }
284 : // add charge value for output to myActChargingStation
285 101336 : myActChargingStation->addChargeValueForOutput(myEnergyCharged, this);
286 : }
287 : // else disable charging vehicle
288 : else {
289 2214 : cs->setChargingVehicle(false);
290 : }
291 : // 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)
292 103550 : if (myPreviousNeighbouringChargingStation != nullptr && myPreviousNeighbouringChargingStation != cs) {
293 485 : myPreviousNeighbouringChargingStation->setChargingVehicle(false);
294 : }
295 103550 : myPreviousNeighbouringChargingStation = cs;
296 : }
297 : // In other case, vehicle will be not charged
298 : else {
299 : // Disable flags
300 353261 : myChargingInTransit = false;
301 353261 : myChargingStopped = false;
302 :
303 : // Disable charging vehicle
304 353261 : if (myActChargingStation != nullptr) {
305 556 : myActChargingStation->setChargingVehicle(false);
306 : }
307 :
308 : // Set charging station pointer to NULL
309 353261 : myActChargingStation = nullptr;
310 :
311 : // Set energy charged to 0
312 353261 : myEnergyCharged = 0;
313 :
314 : // Reset timer
315 353261 : resetChargingStartTime();
316 : }
317 456811 : }
318 :
319 :
320 : void
321 0 : MSDevice_Battery::saveState(OutputDevice& out) const {
322 0 : out.openTag(SUMO_TAG_DEVICE);
323 0 : out.writeAttr(SUMO_ATTR_ID, getID());
324 : std::vector<std::string> internals;
325 0 : internals.push_back(toString(myActualBatteryCapacity));
326 0 : internals.push_back(toString(myLastAngle));
327 0 : internals.push_back(toString(myChargingStopped));
328 0 : internals.push_back(toString(myChargingInTransit));
329 0 : internals.push_back(toString(myChargingStartTime));
330 0 : internals.push_back(toString(myTotalConsumption));
331 0 : internals.push_back(toString(myTotalRegenerated));
332 0 : internals.push_back(toString(myEnergyCharged));
333 0 : internals.push_back(toString(myVehicleStopped));
334 0 : internals.push_back(getChargingStationID());
335 0 : std::string prevChargingID = (myPreviousNeighbouringChargingStation == nullptr) ? "NULL" : myPreviousNeighbouringChargingStation->getID();
336 0 : internals.push_back(prevChargingID);
337 0 : internals.push_back(toString(myMaximumChargeRate));
338 0 : out.writeAttr(SUMO_ATTR_STATE, toString(internals));
339 0 : out.closeTag();
340 0 : }
341 :
342 :
343 : void
344 0 : MSDevice_Battery::loadState(const SUMOSAXAttributes& attrs) {
345 0 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
346 0 : bis >> myActualBatteryCapacity;
347 0 : bis >> myLastAngle;
348 0 : bis >> myChargingStopped;
349 0 : bis >> myChargingInTransit;
350 0 : bis >> myChargingStartTime;
351 0 : bis >> myTotalConsumption;
352 0 : bis >> myTotalRegenerated;
353 0 : bis >> myEnergyCharged;
354 0 : bis >> myVehicleStopped;
355 : std::string chargingID;
356 0 : bis >> chargingID;
357 0 : if (chargingID != "NULL") {
358 0 : myActChargingStation = dynamic_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(chargingID, SUMO_TAG_CHARGING_STATION));
359 : }
360 : std::string prevChargingID;
361 0 : bis >> prevChargingID;
362 0 : if (prevChargingID != "NULL") {
363 0 : myPreviousNeighbouringChargingStation = dynamic_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(prevChargingID, SUMO_TAG_CHARGING_STATION));
364 : }
365 0 : bis >> myMaximumChargeRate;
366 0 : }
367 :
368 :
369 : void
370 557392 : MSDevice_Battery::setActualBatteryCapacity(const double actualBatteryCapacity) {
371 557392 : if (actualBatteryCapacity < 0) {
372 1340 : myActualBatteryCapacity = 0;
373 556052 : } else if (actualBatteryCapacity > myMaximumBatteryCapacity) {
374 4 : myActualBatteryCapacity = myMaximumBatteryCapacity;
375 : } else {
376 556048 : myActualBatteryCapacity = actualBatteryCapacity;
377 : }
378 557392 : }
379 :
380 :
381 : void
382 9 : MSDevice_Battery::setMaximumBatteryCapacity(const double maximumBatteryCapacity) {
383 9 : if (myMaximumBatteryCapacity < 0) {
384 0 : WRITE_WARNINGF(TL("Trying to set into the battery device of vehicle '%' an invalid % (%)."), getID(), toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY), toString(maximumBatteryCapacity));
385 : } else {
386 9 : myMaximumBatteryCapacity = maximumBatteryCapacity;
387 : }
388 9 : }
389 :
390 :
391 : void
392 0 : MSDevice_Battery::setStoppingThreshold(const double stoppingThreshold) {
393 0 : if (stoppingThreshold < 0) {
394 0 : WRITE_WARNINGF(TL("Trying to set into the battery device of vehicle '%' an invalid % (%)."), getID(), toString(SUMO_ATTR_STOPPINGTHRESHOLD), toString(stoppingThreshold));
395 : } else {
396 0 : myStoppingThreshold = stoppingThreshold;
397 : }
398 0 : }
399 :
400 :
401 : void
402 0 : MSDevice_Battery::setMaximumChargeRate(const double chargeRate) {
403 0 : if (chargeRate < 0) {
404 0 : WRITE_WARNINGF(TL("Trying to set into the battery device of vehicle '%' an invalid % (%)."), getID(), toString(SUMO_ATTR_MAXIMUMCHARGERATE), toString(chargeRate));
405 : } else {
406 0 : myMaximumChargeRate = chargeRate;
407 : }
408 0 : }
409 :
410 :
411 : void
412 8 : MSDevice_Battery::setChargeLimit(const double limit) {
413 8 : myChargeLimit = limit;
414 8 : }
415 :
416 :
417 : void
418 353261 : MSDevice_Battery::resetChargingStartTime() {
419 353261 : myChargingStartTime = 0;
420 353261 : }
421 :
422 :
423 : void
424 101336 : MSDevice_Battery::increaseChargingStartTime() {
425 101336 : myChargingStartTime += DELTA_T;
426 101336 : }
427 :
428 :
429 : void
430 250270 : MSDevice_Battery::resetVehicleStoppedTimer() {
431 250270 : myVehicleStopped = 0;
432 250270 : }
433 :
434 :
435 : void
436 206541 : MSDevice_Battery::increaseVehicleStoppedTimer() {
437 206541 : myVehicleStopped++;
438 206541 : }
439 :
440 :
441 : void
442 200 : MSDevice_Battery::setEnergyCharged(const double energyCharged) {
443 200 : myEnergyCharged = energyCharged;
444 200 : }
445 :
446 :
447 : double
448 1385777 : MSDevice_Battery::getActualBatteryCapacity() const {
449 1385777 : return myActualBatteryCapacity;
450 : }
451 :
452 :
453 : double
454 947365 : MSDevice_Battery::getMaximumBatteryCapacity() const {
455 947365 : return myMaximumBatteryCapacity;
456 : }
457 :
458 :
459 : double
460 119416 : MSDevice_Battery::getConsum() const {
461 119416 : return myConsum;
462 : }
463 :
464 : double
465 120473 : MSDevice_Battery::getTotalConsumption() const {
466 120473 : return myTotalConsumption;
467 : }
468 :
469 :
470 : double
471 119416 : MSDevice_Battery::getTotalRegenerated() const {
472 119416 : return myTotalRegenerated;
473 : }
474 :
475 :
476 : bool
477 119326 : MSDevice_Battery::isChargingStopped() const {
478 119326 : return myChargingStopped;
479 : }
480 :
481 :
482 : bool
483 119326 : MSDevice_Battery::isChargingInTransit() const {
484 119326 : return myChargingInTransit;
485 : }
486 :
487 :
488 : SUMOTime
489 200945 : MSDevice_Battery::getChargingStartTime() const {
490 200945 : return myChargingStartTime;
491 : }
492 :
493 :
494 : SUMOTime
495 0 : MSDevice_Battery::estimateChargingDuration(const double toCharge, const double csPower) const {
496 : //if (!myChargeCurve.empty()) {
497 : // // TODO: integrate charge curve
498 : //}
499 0 : return TIME2STEPS(toCharge / MIN2(csPower, myMaximumChargeRate));
500 : }
501 :
502 :
503 : std::string
504 119416 : MSDevice_Battery::getChargingStationID() const {
505 119416 : if (myActChargingStation != nullptr) {
506 : return myActChargingStation->getID();
507 : } else {
508 90580 : return "NULL";
509 : }
510 : }
511 :
512 : double
513 287626 : MSDevice_Battery::getEnergyCharged() const {
514 287626 : return myEnergyCharged;
515 : }
516 :
517 :
518 : int
519 119326 : MSDevice_Battery::getVehicleStopped() const {
520 119326 : return myVehicleStopped;
521 : }
522 :
523 :
524 : double
525 99241 : MSDevice_Battery::getStoppingThreshold() const {
526 99241 : return myStoppingThreshold;
527 : }
528 :
529 :
530 : double
531 100381 : MSDevice_Battery::getMaximumChargeRate() const {
532 100381 : double baseVal = (myChargeCurve.empty()) ? myMaximumChargeRate : LinearApproxHelpers::getInterpolatedValue(myChargeCurve, myActualBatteryCapacity / myMaximumBatteryCapacity);
533 100381 : return (myChargeLimit < 0) ? baseVal : MIN2(myChargeLimit, baseVal);
534 : }
535 :
536 :
537 : bool
538 108 : MSDevice_Battery::tracksFuel() const {
539 108 : return myTrackFuel;
540 : }
541 :
542 :
543 : MSChargingStation::ChargeType
544 504 : MSDevice_Battery::getChargeType() const {
545 504 : return myChargeType;
546 : }
547 :
548 :
549 : std::string
550 768 : MSDevice_Battery::getParameter(const std::string& key) const {
551 1536 : if (key == toString(SUMO_ATTR_ACTUALBATTERYCAPACITY)
552 1536 : || key == toString(SUMO_ATTR_CHARGELEVEL)) {
553 90 : return toString(getActualBatteryCapacity());
554 678 : } else if (key == toString(SUMO_ATTR_ENERGYCONSUMED)) {
555 90 : return toString(getConsum());
556 588 : } else if (key == "chargePower") {
557 60 : return toString(getEnergyCharged() * 3600.);
558 528 : } else if (key == "usedAverage") {
559 60 : return toString(getTotalConsumption() * 3600 / STEPS2TIME(SIMSTEP - myHolder.getDeparture()));
560 468 : } else if (key == toString(SUMO_ATTR_TOTALENERGYCONSUMED)) {
561 90 : return toString(getTotalConsumption());
562 378 : } else if (key == toString(SUMO_ATTR_TOTALENERGYREGENERATED)) {
563 90 : return toString(getTotalRegenerated());
564 288 : } else if (key == toString(SUMO_ATTR_ENERGYCHARGED)) {
565 90 : return toString(getEnergyCharged());
566 396 : } else if (key == toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY) || key == "capacity") {
567 99 : return toString(getMaximumBatteryCapacity());
568 99 : } else if (key == toString(SUMO_ATTR_MAXIMUMCHARGERATE)) {
569 0 : return toString(getMaximumChargeRate());
570 99 : } else if (key == toString(SUMO_ATTR_CHARGINGSTATIONID)) {
571 90 : return getChargingStationID();
572 : }
573 27 : throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
574 : }
575 :
576 :
577 : void
578 9 : MSDevice_Battery::setParameter(const std::string& key, const std::string& value) {
579 : double doubleValue;
580 : try {
581 9 : doubleValue = StringUtils::toDouble(value);
582 0 : } catch (NumberFormatException&) {
583 0 : throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
584 0 : }
585 18 : if (key == toString(SUMO_ATTR_ACTUALBATTERYCAPACITY) || key == toString(SUMO_ATTR_CHARGELEVEL)) {
586 0 : setActualBatteryCapacity(doubleValue);
587 18 : } else if (key == toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY) || key == "capacity") {
588 9 : setMaximumBatteryCapacity(doubleValue);
589 0 : } else if (key == toString(SUMO_ATTR_MAXIMUMCHARGERATE)) {
590 0 : setMaximumChargeRate(doubleValue);
591 : } else {
592 0 : throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
593 : }
594 9 : }
595 :
596 :
597 : void
598 560 : MSDevice_Battery::notifyParking() {
599 : // @note: only charing is performed but no energy is consumed
600 560 : notifyMove(myHolder, myHolder.getPositionOnLane(), myHolder.getPositionOnLane(), myHolder.getSpeed());
601 560 : myConsum = 0;
602 560 : }
603 :
604 :
605 : void
606 1619 : MSDevice_Battery::generateOutput(OutputDevice* tripinfoOut) const {
607 1619 : if (tripinfoOut != nullptr) {
608 209 : tripinfoOut->openTag("battery");
609 418 : tripinfoOut->writeAttr("depleted", toString(myDepletedCount));
610 418 : tripinfoOut->writeAttr("actualBatteryCapacity", toString(myActualBatteryCapacity));
611 418 : tripinfoOut->writeAttr("totalEnergyConsumed", toString(myTotalConsumption));
612 418 : tripinfoOut->writeAttr("totalEnergyRegenerated", toString(myTotalRegenerated));
613 418 : tripinfoOut->closeTag();
614 : }
615 1619 : }
616 :
617 :
618 : /****************************************************************************/
|