Browse Source

Improved battery recharge logic

Added warning if battery capacity is not sufficient
master
Youen Toupin 3 years ago
parent
commit
1b14a62f6e
  1. 4
      simulator/src/app.scss
  2. 5
      simulator/src/simulator-ui.ts
  3. 40
      simulator/src/simulator.ts
  4. 2
      simulator/tools/purify.js

4
simulator/src/app.scss

@ -6,6 +6,10 @@ input[type=number] {
flex-grow: 2.5;
}
.simulation-warning {
color: red;
}
.dropdown.is-fullwidth {
display: flex;
}

5
simulator/src/simulator-ui.ts

@ -95,8 +95,9 @@ function initializeSimulator(container: HTMLElement) {
<p>Cela coûtera ${Math.round(totalConsumedGridPower/1000*averageKwhCost*100)/100} sur l'année. Le vhélio sera rechargé à ${solarRechargeRatio}% par le soleil, ${100-solarRechargeRatio}% sur secteur.</p>
<p><br/></p>
<p>Vitesse moyenne : ${Math.round(simulationResult.averageSpeed*10.0)/10.0} km/h (${Math.round(simulationResult.flatTerrainSpeed*10.0)/10.0} km/h sur plat, ${Math.round(simulationResult.uphillSpeed*10.0)/10.0} km/h en côte à ${Math.round((parameters.dailyAscendingElevation/1000.0)/(parameters.dailyDistance*(1.0-parameters.flatTerrainRatio)*0.5)*100.0)}%, ${Math.round(simulationResult.downhillSpeed*10.0)/10.0} km/h en descente)</p>
<p>Durée de trajet quotidien : ${dailyDurationHours}h ${dailyDurationMinutes}min. Distance annuelle : ${Math.round(simulationResult.cumulatedDistance)} km.</p>
`;
<p>Durée de trajet quotidienne : ${dailyDurationHours}h ${dailyDurationMinutes}min. Distance annuelle : ${Math.round(simulationResult.cumulatedDistance)} km.</p>
`
+ (simulationResult.outOfBatteryDistance >= 1 ? `<p><br/></p><p class="simulation-warning">/!\\ En raison d'une capacité de batterie insuffisante, il faudra faire ${Math.round(simulationResult.outOfBatteryDistance)}km/an sans assistance électrique</p>` : "");
//<p>${Math.round(100*(simulationResult.cumulatedSolarRechargeEnergy/simulationResult.vehicle.batteryEfficiency) / simulationResult.totalProducedSolarEnergy)}% de l'énergie produite par le panneau photovoltaïque sera utilisée pour recharger le vhélio.</p>
let batteryChargeGraph = new SvgDrawing.SvgElement(resultsContainer.querySelector('.battery-charge-graph svg'));

40
simulator/src/simulator.ts

@ -9,6 +9,7 @@ namespace Simulator {
batteryCapacity: number;
batteryEfficiency: number = 0.9;
gridTransformerEfficiency: number = 0.85;
rechargeMargin: number = 0.15; // We recharge the battery before an outing if it would otherwise go below this charge ratio
solarPanelEfficiency: number = 0.15;
solarPanelArea: number = 1.0; // in square meters
@ -117,6 +118,8 @@ namespace Simulator {
uphillSpeed: number;
downhillSpeed: number;
averageSpeed: number;
outOfBatteryDistance: number; // distance, in km, that the driver had to pedal without assistance, because the battery was empty
}
export function simulate(vehicle: Vehicle, solarIrradiance: number[], planning: OutingPlanning): SimulationResult {
@ -136,7 +139,9 @@ namespace Simulator {
flatTerrainSpeed: 0,
uphillSpeed: 0,
downhillSpeed: 0,
averageSpeed: 0
averageSpeed: 0,
outOfBatteryDistance: 0
};
let remainingBatteryCharge = vehicle.batteryCapacity;
@ -144,7 +149,7 @@ namespace Simulator {
let outing: Outing = { distance: 0, ascendingElevation: 0 };
let consumption: ConsumptionData = { motorEnergy: 0, humanEnergy: 0, averageSpeed: 0 };
let resetConsumption = function(outConsumption: ConsumptionData) {
consumption.motorEnergy = 0; consumption.humanEnergy = 0; consumption.averageSpeed = 0;
outConsumption.motorEnergy = 0; outConsumption.humanEnergy = 0; outConsumption.averageSpeed = 0;
};
let flatTerrainRatio = MathUtils.clamp(planning.flatTerrainRatio, 0.0, 1.0);
@ -188,27 +193,44 @@ namespace Simulator {
result.totalProducedSolarEnergy += production;
let solarCharge = production * vehicle.batteryEfficiency;
// TODO: we should keep a margin because real users will recharge before they reach the bare minimum required for an outing
let remainingBatteryChargeBeforeOuting = remainingBatteryCharge;
remainingBatteryCharge += solarCharge - consumption.motorEnergy;
let fullGridRecharge = false;
let gridRechargeFrom = -1;
let lowBatteryThreshold = vehicle.rechargeMargin * vehicle.batteryCapacity;
if(remainingBatteryCharge > vehicle.batteryCapacity) {
solarCharge -= remainingBatteryCharge - vehicle.batteryCapacity;
remainingBatteryCharge = vehicle.batteryCapacity;
}
else if(remainingBatteryCharge <= 0 || (day==364 && hour==23)) {
// TODO: detect if battery capacity is too low for a single outing, abort simulation and display an explanation for the user
fullGridRecharge = remainingBatteryCharge <= 0;
let rechargeEnergy = vehicle.batteryCapacity - remainingBatteryCharge;
else if(remainingBatteryCharge <= lowBatteryThreshold || (day==364 && hour==23)) {
gridRechargeFrom = remainingBatteryChargeBeforeOuting;
let rechargeEnergy = vehicle.batteryCapacity - remainingBatteryChargeBeforeOuting;
remainingBatteryCharge += rechargeEnergy;
result.cumulatedGridRechargeEnergy += rechargeEnergy;
result.gridChargeCount += 1;
if(remainingBatteryCharge < 0)
{
// battery was exhausted during outing
let missingEnergy = -remainingBatteryCharge;
result.outOfBatteryDistance += outing.distance * missingEnergy / consumption.motorEnergy;
consumption.motorEnergy -= missingEnergy;
consumption.humanEnergy += missingEnergy;
// charge battery again after outing
let secondRechargeEnergy = vehicle.batteryCapacity;
remainingBatteryCharge = vehicle.batteryCapacity;
result.cumulatedGridRechargeEnergy += secondRechargeEnergy;
result.gridChargeCount += 1;
gridRechargeFrom = 0;
}
}
result.cumulatedMotorConsumption += consumption.motorEnergy;
result.cumulatedSolarRechargeEnergy += solarCharge;
result.batteryLevel[hourIdx] = fullGridRecharge ? 0 : remainingBatteryCharge;
result.batteryLevel[hourIdx] = gridRechargeFrom >= 0 ? gridRechargeFrom : remainingBatteryCharge;
}
}

2
simulator/tools/purify.js

@ -8,7 +8,7 @@ let css = ['../.intermediate/simulator.css'];
let options = {
output: '../.intermediate/simulator.css',
whitelist: ['is-multiple', 'is-loading', 'is-narrow', 'is-active', 'climate-zone', 'grid-recharge', 'is-max-desktop', 'is-max-widescreen', 'line', 'page'],
whitelist: ['is-multiple', 'is-loading', 'is-narrow', 'is-active', 'climate-zone', 'grid-recharge', 'is-max-desktop', 'is-max-widescreen', 'line', 'page', 'simulation-warning'],
minify: false,
info: false
};

Loading…
Cancel
Save