#!/usr/bin/awk -f # estimate when a value will (linearly or exponentially) decay # (or grow) to a given target # # version 0.1 # # Copyright (c) 2005-2021 Francesco Poli # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN { if (strtonum(t1) >= strtonum(t2)) { printf "ERROR: t1,t2 are not in chronological order!\n" \ > "/dev/stderr"; exit 11; } if (strtonum(v1) <= 0 || strtonum(v2) <= 0 || strtonum(target) <= 0) { printf "ERROR: v1,v2,target are not positive values!\n" \ > "/dev/stderr"; exit 12; } printf "Previous values\n--------"; printf "--------------------------------------\n"; printf "%s:%14g\n", strftime("%a, %d %b %Y %T %z", t1), v1; printf "%s:%14g\n\n", strftime("%a, %d %b %Y %T %z", t2), v2; dt = t2 - t1; # time step dv = v2 - v1; # value increment va = v2/v1; # value amplification hour = 3600; # 1 hour is 3600 seconds day = 86400; # 1 day is 86400 seconds dayandahalf = 129600; # 1.5 days is 129600 seconds if (dt > dayandahalf) { altunit = day; altname = "day"; } else { altunit = hour; altname = "hour"; } text_dt = dt/altunit; text_dt = sprintf("%.1f s (about %.0f %ss)", dt, text_dt, altname); if (dv < 0) { printf "Value has decreased by %g (%.1f %%) in %s\n", -1*dv, 100*(1-va), text_dt; } else { printf "Value has increased by %g (%.1f %%) in %s\n", dv, 100*(va-1), text_dt; } # linear extrapolation: v = v2 + slope*(t - t2) slope = dv/dt; printf "\nSlope: %g / s (%g / %s)\n", slope, slope*altunit, altname; if (v2 == target) { eta = 0; } else if (slope == 0) { eta = "+infinity"; } else { eta = (target - v2)/slope; if (eta < 0) eta = "+infinity"; } printf "Estimated (linear) time to %g: ", target; if (eta == "+infinity") { printf "+infinity\nValue will never reach %g\n", target; } else { printf "%.1f s (about %.0f %ss)\n", eta, eta/altunit, altname; printf "Value will reach %g on %s\n", target, strftime("%a, %d %b %Y %T %z", t2 + eta); } # exponential extrapolation: v = v2*2^((t - t2)/tau) # beta = 1/tau beta = log(va)/(log(2)*dt) if (beta == 0) { printf "\nHalf-life: +infinity\n"; } else if (beta > 0) { tau = 1/beta; printf "\nDoubling time: %g s (about %.0f %ss)\n", tau, tau/altunit, altname; } else { tau = 1/beta; printf "\nHalf-life: %g s (about %.0f %ss)\n", -1*tau, -1*tau/altunit, altname; } if (v2 == target) { eta = 0; } else if (beta == 0) { eta = "+infinity"; } else { needed = target/v2; eta = log(needed)/(log(2)*beta); if (eta < 0) eta = "+infinity"; } printf "Estimated (exponential) time to %g: ", target; if (eta == "+infinity") { printf "+infinity\nValue will never reach %g\n", target; } else { printf "%.1f s (about %.0f %ss)\n", eta, eta/altunit, altname; printf "Value will reach %g on %s\n", target, strftime("%a, %d %b %Y %T %z", t2 + eta); } printf "\nForecast "; printf " (lin) (exp)\n--------"; printf "----------------------------------------------------\n"; for (i = 1; i <= 5; ++i) { t = t2 + i*dt; printf "%s:%14g%14g\n", strftime("%a, %d %b %Y %T %z", t), v2 + slope*(t - t2), v2*2^(beta*(t - t2)); } }