Improved statistics display
- fixed bug in solar recharge percentage computation - added recharge at the end of the year to have the same battery level at the start and end of the year - added battery and charger efficiency simulation - using kWh price (without counting subscription)
This commit is contained in:
parent
030a95095e
commit
54a9d49d83
@ -21,11 +21,6 @@ function runSimulation(parameters: SimulationParameters): Simulator.SimulationRe
|
|||||||
//console.log(solarIrradiance);
|
//console.log(solarIrradiance);
|
||||||
//console.log(simulationResult);
|
//console.log(simulationResult);
|
||||||
|
|
||||||
//let averageKwhCost = 0.192; // in €/kWh TODO: to verify, this price seems too high
|
|
||||||
//console.log('Grid recharge cost: ' + (Math.round(simulationResult.gridChargeCount*(vehicle.batteryCapacity/1000)*averageKwhCost*100)/100) + '€');
|
|
||||||
|
|
||||||
//console.log('Solar energy ratio: ' + Math.round(100*(simulationResult.cumulatedMotorConsumption-(simulationResult.gridChargeCount+1)*vehicle.batteryCapacity)/simulationResult.cumulatedMotorConsumption) + '%');
|
|
||||||
|
|
||||||
return simulationResult;
|
return simulationResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,12 +71,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
let resultsContainer = container.querySelector('.simulation-results');
|
let resultsContainer = container.querySelector('.simulation-results');
|
||||||
|
|
||||||
let averageKwhCost = 0.192; // in €/kWh TODO: to verify, this price seems too high
|
let averageKwhCost = 0.1558; // in €/kWh
|
||||||
|
let totalConsumedGridPower = simulationResult.cumulatedGridRechargeEnergy / simulationResult.vehicle.batteryEfficiency / simulationResult.vehicle.gridTransformerEfficiency;
|
||||||
|
|
||||||
|
let solarRechargeRatio = Math.round(100*(simulationResult.cumulatedSolarRechargeEnergy/(simulationResult.cumulatedSolarRechargeEnergy + simulationResult.cumulatedGridRechargeEnergy)));
|
||||||
resultsContainer.querySelector('.result-info').innerHTML = `
|
resultsContainer.querySelector('.result-info').innerHTML = `
|
||||||
<p>Il faudra recharger le vhélio sur secteur environ ${simulationResult.gridChargeCount} fois sur l'année</p>
|
<p>Il faudra recharger le vhélio sur secteur environ ${simulationResult.gridChargeCount} fois sur l'année.</p>
|
||||||
<p>Cela coûtera ${Math.round(simulationResult.gridChargeCount*(parameters.batteryCapacity/1000)*averageKwhCost*100)/100}€ sur l'année</p>
|
<p>Cela coûtera ${Math.round(totalConsumedGridPower/1000*averageKwhCost*100)/100}€ sur l'année.</p>
|
||||||
<p>La couverture solaire du vhélio est de ${Math.round(100*(simulationResult.cumulatedMotorConsumption-(simulationResult.gridChargeCount+1)*parameters.batteryCapacity)/simulationResult.cumulatedMotorConsumption)}%</p>
|
<p>Le vhélio sera rechargé à ${solarRechargeRatio}% par le soleil, ${100-solarRechargeRatio}% sur secteur.</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'));
|
let batteryChargeGraph = new SvgDrawing.SvgElement(resultsContainer.querySelector('.battery-charge-graph svg'));
|
||||||
|
|
||||||
@ -100,7 +99,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
batteryChargeGraph.viewport.setData({ x: 0, y: 0, width: 365*24, height: parameters.batteryCapacity });
|
batteryChargeGraph.viewport.setData({ x: 0, y: 0, width: 365*24, height: parameters.batteryCapacity });
|
||||||
batteryChargeGraph.viewport.setView({ x: marginLeft, y: batteryChargeGraph.height - marginBottom, width: batteryChargeGraph.width - (marginLeft+marginRight), height: -batteryChargeGraph.height+(marginTop+marginBottom) });
|
batteryChargeGraph.viewport.setView({ x: marginLeft, y: batteryChargeGraph.height - marginBottom, width: batteryChargeGraph.width - (marginLeft+marginRight), height: -batteryChargeGraph.height+(marginTop+marginBottom) });
|
||||||
batteryChargeGraph.graph(simulationResult.batteryLevel, simulationResult.batteryLevel.map(x => x == 0 ? 1 : 0), [{className: ''}, {className: 'grid-recharge'}]);
|
batteryChargeGraph.graph(simulationResult.batteryLevel, simulationResult.batteryLevel.map((x, idx) => x == 0 || idx == simulationResult.batteryLevel.length - 2 ? 1 : 0), [{className: ''}, {className: 'grid-recharge'}]);
|
||||||
let months = ['Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Jui', 'Jui', 'Aou', 'Sep', 'Oct', 'Nov', 'Dec'];
|
let months = ['Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Jui', 'Jui', 'Aou', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||||
let monthWidth = 365*24/12
|
let monthWidth = 365*24/12
|
||||||
for(let month = 0; month < 12; ++month) {
|
for(let month = 0; month < 12; ++month) {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
namespace Simulator {
|
namespace Simulator {
|
||||||
export class Vehicle {
|
export class Vehicle {
|
||||||
batteryCapacity: number;
|
batteryCapacity: number;
|
||||||
batteryEfficiency: number = 1.0; // TODO: typical efficiency of a Li-ion battery (round-trip) is 90%
|
batteryEfficiency: number = 0.9;
|
||||||
|
gridTransformerEfficiency: number = 0.85;
|
||||||
|
|
||||||
solarPanelEfficiency: number = 0.15;
|
solarPanelEfficiency: number = 0.15;
|
||||||
solarPanelArea: number = 1.0; // in square meters
|
solarPanelArea: number = 1.0; // in square meters
|
||||||
@ -59,19 +60,25 @@ namespace Simulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SimulationResult {
|
export interface SimulationResult {
|
||||||
|
vehicle: Vehicle;
|
||||||
|
|
||||||
batteryLevel: number[]; // Remaining energy in the battery over time (one entry per hour), in Wh
|
batteryLevel: number[]; // Remaining energy in the battery over time (one entry per hour), in Wh
|
||||||
gridChargeCount: number;
|
gridChargeCount: number;
|
||||||
cumulatedGridRechargeEnergy: number; // Cumulated energy added to the battery from the power grid, in Wh of battery charge (actual power grid consumption will be slightly higer due to losses)
|
cumulatedGridRechargeEnergy: number; // Cumulated energy added to the battery from the power grid, in Wh of battery charge (actual power grid consumption will be slightly higer due to losses)
|
||||||
cumulatedSolarRechargeEnergy: number; // Cumulated energy added to the battery from the solar panel, in Wh of battery charge (actual generated power is slightly higher due to losses)
|
cumulatedSolarRechargeEnergy: number; // Cumulated energy added to the battery from the solar panel, in Wh of battery charge (actual generated power is slightly higher due to losses)
|
||||||
|
totalProducedSolarEnergy: number; // Cumulated energy produced (used or unused), before accounting for the battery recharge efficiency.
|
||||||
cumulatedMotorConsumption: number; // Cumulated energy consumed by the motor, in Wh. In this simulation, this is equal to the energy drawn from the battery.
|
cumulatedMotorConsumption: number; // Cumulated energy consumed by the motor, in Wh. In this simulation, this is equal to the energy drawn from the battery.
|
||||||
}
|
}
|
||||||
|
|
||||||
export function simulate(vehicle: Vehicle, solarIrradiance: number[], planning: OutingPlanning): SimulationResult {
|
export function simulate(vehicle: Vehicle, solarIrradiance: number[], planning: OutingPlanning): SimulationResult {
|
||||||
let result: SimulationResult = {
|
let result: SimulationResult = {
|
||||||
|
vehicle: vehicle,
|
||||||
|
|
||||||
batteryLevel: [],
|
batteryLevel: [],
|
||||||
gridChargeCount: 0,
|
gridChargeCount: 0,
|
||||||
cumulatedGridRechargeEnergy: 0,
|
cumulatedGridRechargeEnergy: 0,
|
||||||
cumulatedSolarRechargeEnergy: 0,
|
cumulatedSolarRechargeEnergy: 0,
|
||||||
|
totalProducedSolarEnergy: 0,
|
||||||
cumulatedMotorConsumption: 0
|
cumulatedMotorConsumption: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,19 +95,20 @@ namespace Simulator {
|
|||||||
let consumption = vehicle.motorConsumption(outing.distance, outing.ascendingElevation);
|
let consumption = vehicle.motorConsumption(outing.distance, outing.ascendingElevation);
|
||||||
let production = vehicle.solarPower(solarIrradiance[hourIdx]) * 1.0; // produced energy in Wh is equal to power (W) multiplied by time (h)
|
let production = vehicle.solarPower(solarIrradiance[hourIdx]) * 1.0; // produced energy in Wh is equal to power (W) multiplied by time (h)
|
||||||
|
|
||||||
|
result.totalProducedSolarEnergy += production;
|
||||||
let solarCharge = production * vehicle.batteryEfficiency;
|
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
|
// TODO: we should keep a margin because real users will recharge before they reach the bare minimum required for an outing
|
||||||
remainingBatteryCharge += solarCharge - consumption;
|
remainingBatteryCharge += solarCharge - consumption;
|
||||||
|
|
||||||
let gridRecharge = false;
|
let fullGridRecharge = false;
|
||||||
if(remainingBatteryCharge > vehicle.batteryCapacity) {
|
if(remainingBatteryCharge > vehicle.batteryCapacity) {
|
||||||
solarCharge -= remainingBatteryCharge - vehicle.batteryCapacity;
|
solarCharge -= remainingBatteryCharge - vehicle.batteryCapacity;
|
||||||
remainingBatteryCharge = vehicle.batteryCapacity;
|
remainingBatteryCharge = vehicle.batteryCapacity;
|
||||||
}
|
}
|
||||||
else if(remainingBatteryCharge <= 0) {
|
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
|
// TODO: detect if battery capacity is too low for a single outing, abort simulation and display an explanation for the user
|
||||||
gridRecharge = true;
|
fullGridRecharge = remainingBatteryCharge <= 0;
|
||||||
let rechargeEnergy = vehicle.batteryCapacity - remainingBatteryCharge;
|
let rechargeEnergy = vehicle.batteryCapacity - remainingBatteryCharge;
|
||||||
remainingBatteryCharge += rechargeEnergy;
|
remainingBatteryCharge += rechargeEnergy;
|
||||||
result.cumulatedGridRechargeEnergy += rechargeEnergy;
|
result.cumulatedGridRechargeEnergy += rechargeEnergy;
|
||||||
@ -110,7 +118,7 @@ namespace Simulator {
|
|||||||
result.cumulatedMotorConsumption += consumption;
|
result.cumulatedMotorConsumption += consumption;
|
||||||
result.cumulatedSolarRechargeEnergy += solarCharge;
|
result.cumulatedSolarRechargeEnergy += solarCharge;
|
||||||
|
|
||||||
result.batteryLevel[hourIdx] = gridRecharge ? 0 : remainingBatteryCharge;
|
result.batteryLevel[hourIdx] = fullGridRecharge ? 0 : remainingBatteryCharge;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user