{"spec_id":"eye-diagram-basic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// eye-diagram-basic: Signal Integrity Eye Diagram\n// Library: echarts 5.5.1 | JavaScript 22.22.3\n// Quality: 85/100 | Created: 2026-06-18\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Seeded LCG for deterministic data generation (no Date.now / Math.random)\nlet _s = 42;\nfunction lcg() {\n  _s = (_s * 1664525 + 1013904223) >>> 0;\n  return _s / 4294967296;\n}\nfunction gauss() {\n  const u = Math.max(lcg(), 1e-10);\n  return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * lcg());\n}\n\n// NRZ signal parameters\nconst NUM_TRACES   = 400;   // overlaid signal periods\nconst SAMPLES      = 200;   // time-samples per trace across 2 UI\nconst NOISE_SIGMA  = 0.05;  // additive Gaussian noise (5% of amplitude)\nconst JITTER_SIGMA = 0.03;  // timing jitter per transition (3% of UI)\n\n// 2-D density grid\nconst T_BINS = 200;\nconst V_BINS = 100;\nconst T_MIN = 0,    T_MAX = 2;    // 0–2 unit intervals\nconst V_MIN = -0.5, V_MAX = 1.5;  // -0.5 V to 1.5 V (NRZ logic levels 0 V / 1 V)\n\nconst grid = new Uint32Array(T_BINS * V_BINS);\n\n// Sigmoid for bandwidth-limited bit transitions\nfunction sig(x, center) {\n  return 1 / (1 + Math.exp(-30 * (x - center)));\n}\n\n// Generate traces: each trace uses three random bits [b0, b1, b2] across 2 UI\nfor (let tr = 0; tr < NUM_TRACES; tr++) {\n  const b0 = lcg() < 0.5 ? 0 : 1;\n  const b1 = lcg() < 0.5 ? 0 : 1;\n  const b2 = lcg() < 0.5 ? 0 : 1;\n  const j0 = gauss() * JITTER_SIGMA;\n  const j1 = gauss() * JITTER_SIGMA;\n\n  for (let s = 0; s < SAMPLES; s++) {\n    const tVal = T_MIN + (s / (SAMPLES - 1)) * (T_MAX - T_MIN);\n    const vVal =\n      b0 + (b1 - b0) * sig(tVal, 0 + j0)\n         + (b2 - b1) * sig(tVal, 1 + j1)\n         + gauss() * NOISE_SIGMA;\n\n    const ti = Math.min(T_BINS - 1, Math.max(0,\n      Math.floor(((tVal - T_MIN) / (T_MAX - T_MIN)) * T_BINS)));\n    const vi = Math.min(V_BINS - 1, Math.max(0,\n      Math.floor(((vVal - V_MIN) / (V_MAX - V_MIN)) * V_BINS)));\n    grid[ti * V_BINS + vi]++;\n  }\n}\n\n// Sqrt-normalize density for better perceptual dynamic range\nlet maxCount = 0;\nfor (let i = 0; i < grid.length; i++) if (grid[i] > maxCount) maxCount = grid[i];\nconst sqrtMax = Math.sqrt(maxCount);\n\nconst heatData = [];\nfor (let ti = 0; ti < T_BINS; ti++) {\n  for (let vi = 0; vi < V_BINS; vi++) {\n    const c = grid[ti * V_BINS + vi];\n    if (c > 0) heatData.push([ti, vi, Math.sqrt(c) / sqrtMax]);\n  }\n}\n\n// Bin-center label arrays for category axes\nconst timeLabels = Array.from({ length: T_BINS }, (_, i) =>\n  (T_MIN + (i + 0.5) / T_BINS * (T_MAX - T_MIN)).toFixed(3)\n);\nconst voltLabels = Array.from({ length: V_BINS }, (_, i) =>\n  (V_MIN + (i + 0.5) / V_BINS * (V_MAX - V_MIN)).toFixed(3)\n);\n\n// Eye measurement coordinates — bin-center labels closest to each boundary\n// Eye height at mid-bit (t=0.5 UI): ~3σ noise bounds give open region 0.15–0.85 V → 0.70 V\n// Eye width at midpoint (v=0.5 V): ~3σ jitter bounds give open region 0.10–0.90 UI → 0.80 UI\nconst T_EYE_CTR  = timeLabels[50];  // t ≈ 0.505 UI  (center of first bit period)\nconst V_EYE_LOW  = voltLabels[32];  // v ≈ 0.150 V   (lower eye boundary)\nconst V_EYE_HIGH = voltLabels[67];  // v ≈ 0.850 V   (upper eye boundary)\nconst T_EYE_L    = timeLabels[10];  // t ≈ 0.105 UI  (left eye boundary)\nconst T_EYE_R    = timeLabels[90];  // t ≈ 0.905 UI  (right eye boundary)\nconst V_MID      = voltLabels[50];  // v ≈ 0.510 V   (midpoint for width measure)\nconst V_REF0     = voltLabels[25];  // v ≈ 0.010 V   (NRZ low-level reference)\nconst V_REF1     = voltLabels[75];  // v ≈ 1.010 V   (NRZ high-level reference)\n\nconst chart = echarts.init(document.getElementById(\"container\"));\n\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n\n  title: {\n    text: \"eye-diagram-basic · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 18,\n    textStyle: { color: t.ink, fontSize: 24, fontWeight: \"bold\" }\n  },\n\n  grid: { left: 100, right: 140, top: 80, bottom: 78 },\n\n  xAxis: {\n    type: \"category\",\n    data: timeLabels,\n    name: \"Time (UI)\",\n    nameLocation: \"middle\",\n    nameGap: 44,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    axisLabel: {\n      interval: (idx) => idx % 50 === 0 || idx === T_BINS - 1,\n      formatter: (val) => parseFloat(val).toFixed(1),\n      color: t.inkSoft,\n      fontSize: 14\n    },\n    axisLine: { show: false },\n    axisTick: { show: false },\n    splitLine: { show: false }\n  },\n\n  yAxis: {\n    type: \"category\",\n    data: voltLabels,\n    name: \"Voltage (V)\",\n    nameLocation: \"middle\",\n    nameGap: 58,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    axisLabel: {\n      interval: (idx) => idx % 25 === 0 || idx === V_BINS - 1,\n      formatter: (val) => parseFloat(val).toFixed(1),\n      color: t.inkSoft,\n      fontSize: 14\n    },\n    axisLine: { show: false },\n    axisTick: { show: false },\n    splitLine: { show: false }\n  },\n\n  visualMap: {\n    type: \"continuous\",\n    min: 0,\n    max: 1,\n    calculable: false,\n    orient: \"vertical\",\n    right: 18,\n    top: \"center\",\n    itemHeight: 220,\n    text: [\"Dense\", \"Sparse\"],\n    textStyle: { color: t.inkSoft, fontSize: 14 },\n    inRange: { color: [t.pageBg, t.seq[0], t.seq[1]] }\n  },\n\n  series: [{\n    type: \"heatmap\",\n    data: heatData,\n    emphasis: { disabled: true },\n    markLine: {\n      silent: true,\n      animation: false,\n      symbol: \"none\",\n      label: { show: false },\n      data: [\n        // NRZ logic level reference lines (dashed horizontal anchors)\n        {\n          yAxis: V_REF0,\n          lineStyle: { type: \"dashed\", color: t.inkSoft, width: 1, opacity: 0.55 },\n          label: { show: true, formatter: \"0 V\", position: \"start\", color: t.inkSoft, fontSize: 11 }\n        },\n        {\n          yAxis: V_REF1,\n          lineStyle: { type: \"dashed\", color: t.inkSoft, width: 1, opacity: 0.55 },\n          label: { show: true, formatter: \"1 V\", position: \"start\", color: t.inkSoft, fontSize: 11 }\n        },\n        // Eye height: bidirectional vertical arrow at mid-bit (t ≈ 0.5 UI)\n        [\n          {\n            coord: [T_EYE_CTR, V_EYE_LOW],\n            symbol: \"arrow\", symbolSize: 7,\n            lineStyle: { type: \"solid\", color: t.amber, width: 2 }\n          },\n          {\n            coord: [T_EYE_CTR, V_EYE_HIGH],\n            symbol: \"arrow\", symbolSize: 7,\n            label: { show: true, formatter: \"H: 0.70 V\", color: t.amber, fontSize: 11, position: \"end\", distance: 5 }\n          }\n        ],\n        // Eye width: bidirectional horizontal arrow at midpoint (v ≈ 0.5 V)\n        [\n          {\n            coord: [T_EYE_L, V_MID],\n            symbol: \"arrow\", symbolSize: 7,\n            lineStyle: { type: \"solid\", color: t.amber, width: 2 }\n          },\n          {\n            coord: [T_EYE_R, V_MID],\n            symbol: \"arrow\", symbolSize: 7,\n            label: { show: true, formatter: \"W: 0.80 UI\", color: t.amber, fontSize: 11, position: \"end\", distance: 5 }\n          }\n        ]\n      ]\n    }\n  }]\n});\n"}