Improved battery recharge logic
Added warning if battery capacity is not sufficient
This commit is contained in:
parent
ed3e9f7dc4
commit
1b14a62f6e
@ -6,6 +6,10 @@ input[type=number] {
|
||||
flex-grow: 2.5;
|
||||
}
|
||||
|
||||
.simulation-warning {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.dropdown.is-fullwidth {
|
||||
display: flex;
|
||||
}
|
||||
|
@ -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'));
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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…
Reference in New Issue
Block a user