f15ac69925
Includes: - package/ GL-XE3000 kit-busrouter (opkg) - scripts/provision.sh (GL) and provision-synology.sh (Synology) - syno-balance/ — new WAN balancer replacing aiwanbal (SmartWAN adapter) - kit-connect/ — unified connectivity SPK (Tailscale + reverse SSH) - docs/deployment/synology-rt2600ac-checklist.md — 62-point checklist - docs/provisioning/device-identity.md — fleet identity spec - docs/pilot/checklist.md — field pilot validation - x4078_20260721.dss — reference config backup Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
52 lines
2.3 KiB
Bash
Executable File
52 lines
2.3 KiB
Bash
Executable File
#!/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<ARGC;i++) s+=ARGV[i]; printf "%d",(s/n+0.5) }' "$@"
|
|
}
|