So i started out simply trying to shave cycles out of onBatteryChanged., mainly by avoiding loops and conversion between number -> string -> number, and ended up completely rewriting it instead to show 101 points of precision in 1% increments, from 0% to 100%. I followed the voltage range "clamps", and wrote a script which calculates the voltage range for each percentage, then generates the code to be placed in onBatteryChanged.
I do not have a cutiepi yet to test this on, so i was hoping the dev team might be willing to test it on a device and ensure it works properly. It should, based on everything i read about QT javascript support
Pros:
Calculate battery percent without excessively wasting resources
95% more efficient (300k ops/s vs 13k ops/s)
101 points of precision vs 21 - full 0% to 100% can be displayed.
Cons:
My math skills are poor, I probably misunderstood how voltage decay works. i know its exponential but wasn't sure. I tried various "factors" until it looked right to me
Extremely verbose (500 LOC)
Wanted to create a jsbench test suite, but the code exceeds the maximum allowed size for a test case.
Here's the script i used to generate the code:
const fs = require('fs');
var batteryVoltages = [
"3.89",
"3.88",
"3.86",
"3.82",
"3.80",
"3.76",
"3.73",
"3.69",
"3.67",
"3.65",
"3.63",
"3.61",
"3.60",
"3.59",
"3.56",
"3.55",
"3.53",
"3.51",
"3.49",
"3.48",
"3.00",
].map(v=>parseFloat(v)*1000);
var batteryPercentages = [
100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10,
5, 0,
];
function generateRange(arr,baseVal) {
let res = [];
for(let i=arr.length-1;i>0;i--){
let a = arr[i]+1;
let b = arr[i-1]
if(i===arr.length-1) {
a=baseVal;
}
res.push([b,a]);
}
return res.reverse();
}
function getNums(n,f,tot){
let x=1;
const arr=[...new Array(n)]
.map(c=>x*=f);
const mul=tot/arr.reduce((a,c)=>a+c);
return arr.map(v=>mul*v)
}
function expandRanges( pctRanges, voltRanges ) {
return pctRanges.map((pr,i)=>{
let n = pr[0]-pr[1]+1;// number of elements
let prFinal = [];
for(let i=pr[1];i<=pr[0];i++) {
prFinal.push(i)
}
let vr = voltRanges[i];
let vrFinal = [];
let total = vr[0]-vr[1]
let chunks = getNums(n,1.12359,total).reverse().map(v=>Math.round(v));
let start = vr[1];
for(let i=0;i<chunks.length;i++){
vrFinal.push(start);
start+=chunks[i];
if(i==chunks.length-1){
vrFinal[i]=vr[0];
}
}
return { pct: prFinal.reverse(), voltage: vrFinal.reverse() };
});
}
const batteryPercentageRanges = generateRange(batteryPercentages,0);
const batteryVoltageRanges = generateRange(batteryVoltages,3000);
console.log(batteryPercentageRanges,batteryVoltageRanges);
const crossMap = expandRanges( batteryPercentageRanges, batteryVoltageRanges );
console.log(crossMap);
const flattenedMap = [
[],//voltages
[]//percentage
];
crossMap.forEach( item => {
flattenedMap[0].push(...item.voltage);
flattenedMap[1].push(...item.pct);
})
console.log(flattenedMap);
console.log(flattenedMap[0].length,flattenedMap[1].length);
let code = [];
code.push(
`
view.queue.push(battery);// there is no need to divide to get value volts, just use raw mv
if (view.queue.length > 15) {
view.queue.shift();
}
var sum = 0;
var nSum = view.queue.length;
`);
for(let i=0;i<15;i++) {
code.push(
`if(view.queue[${i}]!==undefined) {
sum += view.queue[${i}];
}`
);
}
code.push(`var meanVol=~~(sum/nSum);//strip decimal bits (round to integer)`);
code.push('switch(true){');
for(let i=0;i<flattenedMap[0].length;i++){
if(i===0){
//special case high voltage
code.push(`case(meanVol>${flattenedMap[0][i+1]}):
batteryPercentage=${flattenedMap[1][i]};
break;
`);
}
else if(i===flattenedMap[0].length-2) {
//special case 1%
code.push(`case(meanVol>${flattenedMap[0][i]}):
batteryPercentage=${flattenedMap[1][i]};
break;
`);
}
else if(i===flattenedMap[0].length-1) {
//special case low voltage
code.push(`case(meanVol>${flattenedMap[0][i]}):
//fall through to default case
`);
}else{
// all other case
code.push(`case(meanVol>${flattenedMap[0][i+1]}&&meanVol<=${flattenedMap[0][i]}):
batteryPercentage=${flattenedMap[1][i]};
break;
`);
}
}
code.push(`
default:
// doesnt seem possible but just in case something weird happened
batteryPercentage=0;
break;
`)
code.push('}');
code.push('view.stableVol=Math.floor((meanVol/1000)*100)/100;');
code.push(`
if (!batteryCharging) {
if (view.queue.length < 5) {
batteryText.text = "Checking..";
} else {
batteryText.text = batteryPercentage + "%";
}
}
`);
const finalGeneratedCode = code.join("\r\n");
fs.writeFileSync('./onBatteryChanged.js',finalGeneratedCode,'utf-8');
So i started out simply trying to shave cycles out of
onBatteryChanged
., mainly by avoiding loops and conversion between number -> string -> number, and ended up completely rewriting it instead to show 101 points of precision in 1% increments, from 0% to 100%. I followed the voltage range "clamps", and wrote a script which calculates the voltage range for each percentage, then generates the code to be placed inonBatteryChanged
.I do not have a cutiepi yet to test this on, so i was hoping the dev team might be willing to test it on a device and ensure it works properly. It should, based on everything i read about QT javascript support
Pros:
Cons:
Wanted to create a jsbench test suite, but the code exceeds the maximum allowed size for a test case.
Here's the script i used to generate the code: