1// snn-tornado.js 2// Live Sensitivity Analysis (Tornado Chart) 3 4window.tornadoChart = null; 5window.tempOverrideParams = null; 6window.tornadoEnabled = true; 7 8const sensitivityParams = [ 9 { key: 'Lg', label: 'Gate Length' }, 10 { key: 'Vdd', label: 'Vdd' }, 11 { key: 'EOT', label: 'Oxide Thk.' }, 12 { key: 'T', label: 'Temperature' }, 13 { key: 'Wns', label: 'Channel Width' } 14]; 15 16let debounceTimer = null; 17 18window.initTornadoChart = function() { 19 const ctx = document.getElementById('chSnnTornado'); 20 if (!ctx) return; 21 22 window.tornadoChart = new Chart(ctx.getContext('2d'), { 23 type: 'bar', 24 data: { 25 labels: sensitivityParams.map(p => p.label), 26 datasets: [ 27 { 28 label: '-10% Variation', 29 data: [0, 0, 0, 0, 0], 30 backgroundColor: 'rgba(231, 76, 60, 0.7)', 31 borderColor: 'rgba(231, 76, 60, 1)', 32 borderWidth: 1, 33 barPercentage: 0.8 34 }, 35 { 36 label: '+10% Variation', 37 data: [0, 0, 0, 0, 0], 38 backgroundColor: 'rgba(46, 204, 113, 0.7)', 39 borderColor: 'rgba(46, 204, 113, 1)', 40 borderWidth: 1, 41 barPercentage: 0.8 42 } 43 ] 44 }, 45 options: { 46 indexAxis: 'y', 47 responsive: true, 48 maintainAspectRatio: false, 49 scales: { 50 x: { 51 title: { display: true, text: 'Change in Accuracy (%)', color: '#888' }, 52 grid: { color: '#2a2a3a' }, 53 ticks: { color: '#888' } 54 }, 55 y: { 56 grid: { display: false }, 57 ticks: { color: '#888', font: { size: 13 } } 58 } 59 }, 60 plugins: { 61 legend: { labels: { color: '#888' } }, 62 tooltip: { 63 callbacks: { 64 label: function(context) { 65 let val = context.raw; 66 let sign = val >= 0 ? '+' : ''; 67 return `${context.dataset.label} ${sign}${val.toFixed(2)}% Acc`; 68 } 69 } 70 } 71 }, 72 onHover: (e, activeElements) => { 73 if (!activeElements || activeElements.length === 0) { 74 if (window.tempOverrideParams !== null) { 75 window.tempOverrideParams = null; 76 if(typeof fallbackComputeAll === 'function') fallbackComputeAll(true); // true means isPreview 77 let hl = document.getElementById('snn-acc-highlight'); 78 if (hl) hl.style.opacity = "0"; 79 } 80 return; 81 } 82 83 const el = activeElements[0]; 84 const datasetIndex = el.datasetIndex; // 0 for -10%, 1 for +10% 85 const dataIndex = el.index; // parameter index 86 87 const param = sensitivityParams[dataIndex]; 88 const mult = datasetIndex === 0 ? 0.9 : 1.1; 89 90 // Set temporary override 91 let overrides = JSON.parse(JSON.stringify(window.currentS || {})); 92 // Wait, S is global in index.html. We can access it directly via S. 93 overrides = JSON.parse(JSON.stringify(typeof S !== 'undefined' ? S : {})); 94 95 overrides[param.key] = overrides[param.key] * mult; 96 window.tempOverrideParams = overrides; 97 98 if(typeof fallbackComputeAll === 'function') fallbackComputeAll(true); 99 100 let hl = document.getElementById('snn-acc-highlight'); 101 if (hl) { 102 hl.innerText = `Preview: ${datasetIndex===0?'-10%':'+10%'} ${param.label}`; 103 hl.style.opacity = "1"; 104 } 105 } 106 } 107 }); 108 109 // Add mouseleave just to be safe 110 document.getElementById('chSnnTornado').addEventListener('mouseleave', () => { 111 if (window.tempOverrideParams !== null) { 112 window.tempOverrideParams = null; 113 if(typeof fallbackComputeAll === 'function') fallbackComputeAll(true); 114 let hl = document.getElementById('snn-acc-highlight'); 115 if (hl) hl.style.opacity = "0"; 116 } 117 }); 118}; 119 120window.triggerTornadoCompute = function() { 121 if (!window.tornadoEnabled || !window.tornadoChart) return; 122 123 clearTimeout(debounceTimer); 124 debounceTimer = setTimeout(() => { 125 window.computeSensitivity(); 126 }, 250); // 250ms debounce 127}; 128 129window.computeSensitivity = function() { 130 if (!window.tornadoChart) return; 131 132 // We need the base accuracy. 133 const baseS = typeof S !== 'undefined' ? S : {}; 134 let baseD = computeDevice(baseS); 135 if(window.agingEnabled && window.applyAging) baseD = window.applyAging(baseD, window.agingYears); 136 let baseSnn = computeSNN(baseD, baseS); 137 let baseAcc = baseSnn.A;
138 if (isNaN(baseAcc)) baseAcc = 50; 139 140 let leftData = []; 141 let rightData = []; 142 143 let maxChange = 0; 144 let mostSensitiveParam = "None"; 145 let mostSensitiveDir = ""; 146 147 sensitivityParams.forEach(param => { 148 // -10% 149 let sLeft = JSON.parse(JSON.stringify(baseS)); 150 sLeft[param.key] = sLeft[param.key] * 0.9; 151 let dLeft = computeDevice(sLeft); 152 if(window.agingEnabled && window.applyAging) dLeft = window.applyAging(dLeft, window.agingYears); 153 let accLeft = computeSNN(dLeft, sLeft).A; 154 let deltaLeft = accLeft - baseAcc; 155 if (isNaN(deltaLeft)) deltaLeft = 0; 156 leftData.push(deltaLeft); 157 158 if (Math.abs(deltaLeft) > Math.abs(maxChange)) { 159 maxChange = deltaLeft; 160 mostSensitiveParam = param.label; 161 mostSensitiveDir = "-10%"; 162 } 163 164 // +10% 165 let sRight = JSON.parse(JSON.stringify(baseS)); 166 sRight[param.key] = sRight[param.key] * 1.1; 167 let dRight = computeDevice(sRight); 168 if(window.agingEnabled && window.applyAging) dRight = window.applyAging(dRight, window.agingYears); 169 let accRight = computeSNN(dRight, sRight).A; 170 let deltaRight = accRight - baseAcc; 171 if (isNaN(deltaRight)) deltaRight = 0; 172 rightData.push(deltaRight); 173 174 if (Math.abs(deltaRight) > Math.abs(maxChange)) { 175 maxChange = deltaRight; 176 mostSensitiveParam = param.label; 177 mostSensitiveDir = "+10%"; 178 } 179 }); 180 181 window.tornadoChart.data.datasets[0].data = leftData; 182 window.tornadoChart.data.datasets[1].data = rightData; 183 window.tornadoChart.update(); 184 185 let baseLab = document.getElementById('tornado-base-acc'); 186 if (baseLab) baseLab.innerText = baseAcc.toFixed(1) + "%"; 187 188 let mstLab = document.getElementById('tornado-most-sensitive'); 189 if (mstLab) { 190 let sign = maxChange >= 0 ? '+' : ''; 191 mstLab.innerText = `${mostSensitiveParam} (${mostSensitiveDir} ${sign}${maxChange.toFixed(2)}% Acc)`; 192 } 193}; 194 195window.resetTornadoHighlight = function() { 196 window.tempOverrideParams = null; 197 if(typeof fallbackComputeAll === 'function') fallbackComputeAll(true); 198 let hl = document.getElementById('snn-acc-highlight'); 199 if (hl) hl.style.opacity = "0"; 200};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.