Setting

I bought my trusty ASUS N46VB (https://www.asus.com/Notebooks/N46VB/ ) at the end of 2013. On 2014, I created a little ruby script to record the battery status, to track its discharge rate.

ARCHIVO="bateria.log"
def bateria
  porcentaje=`upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep -E "percentage"`
  porcentaje =~ /(\d+)\%/
  porcentaje=$1.to_i
  tiempo=Time.now.to_i
  "#{tiempo}\t#{porcentaje}"
end


open(ARCHIVO, 'a') { |f|
  f.puts bateria
}

I added that script to cron via crontab -e, to run it every 5 minutes.

*/5 * * * * ruby ~/bateria.rb

Analysis

There are 85226 records, the first record dated 2014-08-14 16:24:10 and the last one on 2017-02-08 03:45:01. To test the decline of battery, I diff the whole series, both time and charge. I just keep consecutive readings, looking for diff of exactly 300 seconds, with negative values. If we lookup the data, we can see a clear outlier (62), and some suspicious numbers (35,33).

pandoc.table(table(-(b$db[b$dt==300 & b$db<0])),"Discharge distribution")
Discharge distribution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 26 27 33 35 62
683 3856 3447 957 243 77 37 18 15 6 7 6 7 6 8 1 1 1 1 1 1 1

If we plot the discharge vs time, we can see that discharges higher that 30 are clearly outliers, so we discard them.

plot(bb$t,-bb$db,type="l")
abline(h=30,col=2)

Now, we have 9375 records to analyze. If \(d\) is the discharge rate per 5 minutes, the equation of charge at \(x\) minutes will be

\[ y=100-\frac{dx}{5} \]

And the time on minutes to full discharge will be \[ 0=100-\frac{dx}{5}\\ \frac{dx}{5}=100\\ x=\frac{500}{d} \]

If we graph it, we obtain a very rugged one, because of 1% change rates caused by computer on standy.

plot(500/tiempo.est.b, ylab="time to full discharge",xlab="time on days")

Using moving averages, we could obtain a better visualization of data. The maximum time without charging on the new computers was nearly tree hours, so a window of 36 blocks should be a good starting point.

plot(500/rollmean(tiempo.est.b,36),ylab="time to full discharge",xlab="time on days",ylim=c(0,400))

To have a better look at the trend, we could use a 360 window. We could see that the average time to full discharge now is almost the half than at the beggining.

plot(500/rollmean(tiempo.est.b,360),ylab="time to full discharge",xlab="time on days",ylim=c(0,300))

An alternative way is just aggregate the information. We could take the mean every 30 days and plot it.

scatterplot(500/as.numeric(ag.tiempo)~as.numeric(index(ag.tiempo)),ylab="time to full discharge",xlab="blocks of 30 days",ylim=c(0,250))

Testing some linear models, a cuadratic model on the logs of discharge rate is not perfect, but is relatively linear and control the variance.

lm.1<-lm(log(as.numeric(ag.tiempo))~poly(block.n,2))
summary(lm.1)
## 
## Call:
## lm(formula = log(as.numeric(ag.tiempo)) ~ poly(block.n, 2))
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.103203 -0.029835  0.002486  0.026801  0.085896 
## 
## Coefficients:
##                   Estimate Std. Error t value Pr(>|t|)    
## (Intercept)       0.998999   0.009191 108.689  < 2e-16 ***
## poly(block.n, 2)1 1.046792   0.050343  20.793  < 2e-16 ***
## poly(block.n, 2)2 0.358815   0.050343   7.127 1.15e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.05034 on 27 degrees of freedom
## Multiple R-squared:  0.9471, Adjusted R-squared:  0.9432 
## F-statistic: 241.6 on 2 and 27 DF,  p-value: < 2.2e-16
plot(lm.1)

The original data, the prediction curve and the interval for new predictions

plot(500/as.numeric(ag.tiempo),ylim=c(0,250),xlab="block of 30 days",ylab="time until full discharge")
lines(500/exp(pr.1[,1]),col=2)
lines(500/exp(pr.1[,2]),lty=2,col=2)
lines(500/exp(pr.1[,3]),lty=2,col=2)