#!/bin/sh # lib-score.sh — PURE per-metric + composite WAN scoring (ported from aiwanbal §2.3). # No side effects: args in, single integer 0..100 on stdout. # POSIX/ash-safe; integer/float math delegated to awk (available on OpenWrt). # # Scoring anchors (spec §2.3): # latency 5ms -> 100 , 200ms -> 0 # download 25 -> 100 , 0.5 -> 0 (MB/s) # upload 12.5 -> 100 , 0.5 -> 0 (MB/s) # jitter 1ms -> 100 , 50ms -> 0 # loss 0% -> 100 , 40% -> 0 # signal -65 -> 100 , -95 -> 0 (dBm) # clamp a numeric value to 0..100 and round half-up to an integer _clamp() { awk -v v="$1" 'BEGIN{ if(v<0)v=0; if(v>100)v=100; printf "%d", (v+0.5) }' } # read one value from stdin and clamp/round it (pipe helper) _pipeclamp() { read v; _clamp "$v"; } score_latency() { awk -v x="$1" 'BEGIN{ print 100*(200-x)/(200-5) }' | _pipeclamp; } score_download() { awk -v x="$1" 'BEGIN{ print 100*(x-0.5)/(25-0.5) }' | _pipeclamp; } score_upload() { awk -v x="$1" 'BEGIN{ print 100*(x-0.5)/(12.5-0.5) }' | _pipeclamp; } score_jitter() { awk -v x="$1" 'BEGIN{ print 100*(50-x)/(50-1) }' | _pipeclamp; } score_loss() { awk -v x="$1" 'BEGIN{ print 100*(40-x)/40 }' | _pipeclamp; } score_signal() { awk -v x="$1" 'BEGIN{ print 100*(x-(-95))/((-65)-(-95)) }' | _pipeclamp; } # Weighted 6-factor composite score. # args: lat dl up jitter loss signal(optional) # weights: latency35 dl25 up10 jit10 loss10 sig10. # When signal is empty (no modem), its 10 points redistribute to latency(+5) # and download(+5) so the remaining weights still total 100. score_composite() { sl=$(score_latency "$1"); sd=$(score_download "$2"); su=$(score_upload "$3") sj=$(score_jitter "$4"); sp=$(score_loss "$5") if [ -n "$6" ]; then ss=$(score_signal "$6"); wsig=10; wlat=35; wdl=25 else ss=0; wsig=0; wlat=40; wdl=30 # redistribute signal weight fi awk -v sl="$sl" -v sd="$sd" -v su="$su" -v sj="$sj" -v sp="$sp" -v ss="$ss" \ -v wlat="$wlat" -v wdl="$wdl" -v wsig="$wsig" 'BEGIN{ t=(sl*wlat + sd*wdl + su*10 + sj*10 + sp*10 + ss*wsig)/100 printf "%d",(t+0.5) }' } # Rolling average of N samples (integer, round half-up). Args: sample... rolling_avg() { awk 'BEGIN{ n=ARGC-1; s=0; for(i=1;i