Skip to content

Instantly share code, notes, and snippets.

@hrishioa
Created December 5, 2020 03:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hrishioa/d087ec51c8c5949e6746fe24343ea5d3 to your computer and use it in GitHub Desktop.
Save hrishioa/d087ec51c8c5949e6746fe24343ea5d3 to your computer and use it in GitHub Desktop.
Simple visualisation tool for Gnome battery bench results, with an option to extrapolate data to find the total battery life.
<!DOCTYPE html>
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/regression/2.0.1/regression.min.js"></script>
<meta charset="utf-8">
</head>
<div id="batteryPlot" style="width:1000px;height:500px;"></div>
<input type="file" id="file-selector" accept=".json">
<br>
<div>
<input type="checkbox" id="calcFit" name="calcFit"
checked>
<label for="scales">Extrapolate Graph</label>
</div>
<script>
const fileSelector = document.getElementById('file-selector');
fileSelector.addEventListener('change', (event) => {
const fileList = event.target.files;
loadJSON(event.target.files[0]);
console.log(fileList);
});
function loadJSON(file) {
if(file.type !== 'application/json')
return alert("Please select a json file");
const reader = new FileReader();
reader.addEventListener('load', (event) => {
try {
let jsonData = JSON.parse(event.target.result);
displayJSON(jsonData);
} catch(err) {
return alert("Could not read JSON file");
}
});
reader.readAsText(file);
}
let jd;
function displayJSON(jsonData) {
jd = jsonData;
let requiredFields = ["test-name", "log"];
if(!requiredFields.every(requiredKey => !!jsonData[requiredKey]))
return alert("JSON file missing required keys.");
let chargeDelta = jsonData["log"].map(point => parseFloat(point["charge"]+(jsonData["log"][0]["charge-full"]-jsonData["log"][0]["charge"]))/parseFloat(jsonData["log"][0]["charge-full"])*100.0);
let xData = jsonData["log"].map(point => +point["time-ms"]/parseFloat(1000*60));
let fitData = null;
if(document.getElementById('calcFit').checked)
fitData = getFit(jsonData);
if(fitData) {
xData.push(fitData.endTimeMs/parseFloat(1000*60));
chargeDelta.push(0);
}
plotData.push({
x: xData,
y: chargeDelta,
text: jsonData["test-name"]+" "+(fitData ? getTimeStr(fitData.endTimeMs): "(no fit data)"),
name: jsonData["test-name"]+" "+(fitData ? getTimeStr(fitData.endTimeMs): "(no fit data)"),
mode: 'lines+markers',
marker: {
size: 3,
}
});
Plotly.redraw(batteryPlot);
console.log("Done");
}
function getTimeStr(durationMillis) {
let timeStrs = [];
if(Math.floor(durationMillis/parseFloat(1000*60*60)) > 0)
timeStrs.push(`${Math.floor(durationMillis/parseFloat(1000*60*60))} hours`);
let remainingMinutes = durationMillis-Math.floor(durationMillis/parseFloat(1000*60*60))*(1000*60*60);
if(Math.floor(remainingMinutes/parseFloat(1000*60)) > 0)
timeStrs.push(`${Math.floor(remainingMinutes/parseFloat(1000*60))} minutes`);
if(!timeStrs.length) {
let remainingSeconds = remainingMinutes-Math.floor(remainingMinutes/parseFloat(1000*60));
if(Math.floor(remainingSeconds/parseFloat(1000)) > 0)
timeStrs.push(`${Math.floor(remainingSeconds/parseFloat(1000))} seconds`);
}
return timeStrs.join(", ");
}
function getFit(jsonData) {
let finalPoints = 25; // this is approximately five minutes
try {
let regResult = regression.linear(jsonData["log"].slice(-25).map(point => [+point["time-ms"],+point["charge"]]));
if(regResult && regResult.equation && regResult.equation.length && !isNaN(regResult.equation[0]) && !isNaN(regResult.equation[1])) {
return {
endTimeMs: (-regResult.equation[1]) / regResult.equation[0],
regressionResult: regResult,
}
}
} catch(err) {
console.log("Error calculating fit: ",err);
}
return null;
}
</script>
<script>
let batteryPlot = document.getElementById('batteryPlot');
let plotData = [];
Plotly.newPlot( batteryPlot, plotData,
{
margin: { t: 0 },
showlegend: true,
xaxis: {
title: {
text: 'Minutes'
}
},
yaxis: {
title: {
text: 'Normalized Battery percentage'
}
}
} );
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment