
// cusum_vs_g2.js// // G2 vs CUSUM 全频谱公平对比// 修复1增加运行最小值更新v0 时 x_est min(x_est, z)// 修复2路径变化时重置 S_pos 和 detected 标志// constSCALE1024;// -------------------- 数学工具 --------------------functiongauss(rng,mean0,std1){constu1rng(),u2rng();returnmeanstd*Math.sqrt(-2*Math.log(u1))*Math.cos(2*Math.PI*u2);}functionseedRandom(seed){returnfunction(){seed(seed*16645251013904223)0xffffffff;return(seed0)/0xffffffff;};}functionavg(arr){returnarr.length?arr.reduce((a,b)ab,0)/arr.length:NaN;}functionmedian(arr){if(!arr.length)returnNaN;consts[...arr].sort((a,b)a-b);constmMath.floor(s.length/2);returns.length%2!0?s[m]:(s[m-1]s[m])/2;}functionpercentile(arr,p){if(!arr.length)returnNaN;consts[...arr].sort((a,b)a-b);constidxMath.max(0,Math.ceil(s.length*p/100)-1);returns[idx];}// CUSUM 检测器 classCUSUMDetector{constructor(T_prop,sigma,deltanull,hnull){this.xT_prop*SCALE;// 定点 x_est现在包含运行最小值更新this.mrT_prop;// min_rtt (µs)this.sigmasigma;// CUSUM 参数this.deltadelta||Math.floor(T_prop*0.05);// 默认漂移敏感度 5% T_propthis.hh||Math.floor(T_prop*SCALE*0.15);// 默认阈值 15% T_propthis.S_pos0;// 正向累积和this.detectedfalse;// 探测逻辑 (与 GeodesicEstimator 保持一致)this.probe0;this.currentTT_prop;}setPathChanged(newT_prop){this.currentTnewT_prop;// 关键修复重置累积状态和检测标志防止预热阶段遗留状态影响检测this.S_pos0;this.detectedfalse;}step(rng,rtt,ql0){this.probe;letactualRTTrtt;// 探测 (与 GeodesicEstimator 一致)if(this.probe2000){this.probe0;if(ql0){actualRTTthis.currentTMath.round(gauss(rng,0,this.sigma));}}// 更新 min_rttif(actualRTTthis.mr)this.mractualRTT;constzactualRTT*SCALE;constvz-this.x;// ----- 增加运行最小值更新与 G2 的 G1 分支一致 -----if(v0){this.xMath.min(this.x,z);// 下降信号出现重置部分累积可选增强抗噪// 这里不重置 S_pos因为 CUSUM 原本设计就是单向累积下降不参与正向累积}else{// CUSUM 正向累积和constdriftthis.delta*SCALE;if(vdrift){constcontributionv-drift;this.S_posMath.max(0,this.S_poscontribution);}}// 检测触发同时更新 this.x 和 this.mrif(this.S_posthis.h!this.detected){this.detectedtrue;this.xMath.max(this.x,z);// 将 x_est 更新为当前观测值this.mrMath.max(this.mr,actualRTT);// 将 min_rtt 更新为当前观测值}}bdp(){constxUsMath.floor(this.x/SCALE);returnxUsthis.mr?xUs:this.mr;}}// 原版 G2 估计器 classGeodesicEstimator{constructor(T_prop,sigma){this.xT_prop*SCALE;this.mrT_prop;this.conf0;this.TT_prop;this.probe0;this.sigmasigma;this.pathGrownfalse;}setPathChanged(newT_prop){this.TnewT_prop;this.pathGrowntrue;}step(rng,rtt,ql0){this.probe;letactualRTTrtt;if(this.probe2000){this.probe0;if(ql0){actualRTTthis.TMath.round(gauss(rng,0,this.sigma));}}if(actualRTTthis.mr)this.mractualRTT;constzactualRTT*SCALE;constvz-this.x;if(v0){this.xMath.min(this.x,z);}else{constgrowthMath.floor((this.x*12)/100);this.xMath.min(this.xgrowth,z);constthresholdMath.floor((this.mr*11*SCALE)/10);if(this.xthreshold){this.conf;}elseif(this.xthis.mr*SCALE){this.conf0;}if(this.conf3){constoldMrthis.mr;this.mrMath.floor(this.x/SCALE);this.conf0;if(this.pathGrownthis.mroldMr){this.Tthis.mr;}}}}bdp(){constxUsMath.floor(this.x/SCALE);returnxUsthis.mr?xUs:this.mr;}}// G2 vs CUSUM 对比测试 functioncompareG2vsCUSUM(){constRTTs[25,50,100,200,500,1000,1400,2000,5000,10000,50000,100000,300000,500000,1000000];constGROWTHS[5,10,25,50,100,200];constSEEDS20;constMAX_STEPS500;console.log(.repeat(180));console.log(G2 (12% GEOMETRIC) vs CUSUM (δ5% T_prop, h15% T_prop) — FINAL FIXED);console.log(.repeat(180));console.log(RTT(µs).padStart(9)Amp%.padStart(6)G2_Det%.padStart(9)G2_Med.padStart(8)G2_P90.padStart(8)CUSUM_Det%.padStart(11)CUSUM_Med.padStart(10)CUSUM_P90.padStart(10)Winner.padStart(8)Note.padStart(15));console.log(-.repeat(180));for(constTofRTTs){constsigmaMath.max(1,Math.floor(T/100));for(constampofGROWTHS){constTnewTMath.floor(T*amp/100);if(TnewT)continue;// G2 测试constg2Delays[];letg2Missed0;for(letseed0;seedSEEDS;seed){constrngseedRandom(T*1000ampseed);constestnewGeodesicEstimator(T,sigma);for(leti0;i2000;i){est.step(rng,Math.max(1,TMath.round(gauss(rng,0,sigma))));}est.setPathChanged(Tnew);letdetectedfalse;for(lets1;sMAX_STEPS;s){est.step(rng,Math.max(1,TnewMath.round(gauss(rng,0,sigma))));if(est.bdp()TMath.floor(T*0.02)){g2Delays.push(s);detectedtrue;break;}}if(!detected)g2Missed;}// CUSUM 测试 (δ5% T_prop, h15% T_prop)constcusumDelays[];letcusumMissed0;for(letseed0;seedSEEDS;seed){constrngseedRandom(T*1000ampseed100000);constestnewCUSUMDetector(T,sigma);for(leti0;i2000;i){est.step(rng,Math.max(1,TMath.round(gauss(rng,0,sigma))));}est.setPathChanged(Tnew);letdetectedfalse;for(lets1;sMAX_STEPS;s){est.step(rng,Math.max(1,TnewMath.round(gauss(rng,0,sigma))));if(est.bdp()TMath.floor(T*0.02)){cusumDelays.push(s);detectedtrue;break;}}if(!detected)cusumMissed;}constg2DetPct(g2Delays.length/SEEDS*100).toFixed(1);constg2Medg2Delays.length?median(g2Delays).toFixed(1):-;constg2P90g2Delays.length?String(percentile(g2Delays,90)):-;constcsDetPct(cusumDelays.length/SEEDS*100).toFixed(1);constcsMedcusumDelays.length?median(cusumDelays).toFixed(1):-;constcsP90cusumDelays.length?String(percentile(cusumDelays,90)):-;constg2MedValg2Delays.length?median(g2Delays):Infinity;constcsMedValcusumDelays.length?median(cusumDelays):Infinity;constwinnerg2MedValcsMedVal?G2:(csMedValg2MedVal?CUSUM:TIE);constnote(csDetPct100)?CUSUM MISS:;console.log(String(T).padStart(9)(String(amp)%).padStart(6)(g2DetPct%).padStart(9)String(g2Med).padStart(8)g2P90.padStart(8)(csDetPct%).padStart(11)String(csMed).padStart(10)csP90.padStart(10)winner.padStart(8)note.padStart(15));}}}// 主程序 console.log(\nCUSUM vs G2 FINAL FIXED COMPARISON\n);console.log(说明);console.log(1. CUSUM 增加运行最小值更新v0 时 x_est min(x_est, z));console.log(2. setPathChanged 时重置 S_pos 和 detected 标志);console.log(确保 bdp() min(x_est, min_rtt) 立即超过旧基线\n);compareG2vsCUSUM();