// Create the visualization
{
const width = 700;
const height = 400;
const margin = {top: 30, right: 60, bottom: 40, left: 60};
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto;");
const xScale = d3.scaleLinear()
.domain([0, 1])
.range([margin.left, width - margin.right]);
const yScale = d3.scaleLinear()
.domain([0, referenceVoltage])
.range([height - margin.bottom, margin.top]);
// Draw quantization levels (horizontal lines)
const levels = Math.pow(2, adcBits);
const stepSize = referenceVoltage / levels;
const visibleLevels = Math.min(levels, 32);
const levelStep = Math.max(1, Math.floor(levels / visibleLevels));
for (let i = 0; i <= levels; i += levelStep) {
const y = yScale(i * stepSize);
svg.append("line")
.attr("x1", margin.left)
.attr("x2", width - margin.right)
.attr("y1", y)
.attr("y2", y)
.attr("stroke", "#E5E5E5")
.attr("stroke-width", 0.5);
}
// Analog signal line
const analogLine = d3.line()
.x(d => xScale(d.t))
.y(d => yScale(d.analog));
svg.append("path")
.datum(analogSignal)
.attr("fill", "none")
.attr("stroke", "#3498DB")
.attr("stroke-width", 2)
.attr("d", analogLine);
// Quantized signal (staircase)
const quantizedLine = d3.line()
.x(d => xScale(d.t))
.y(d => yScale(d.quantized))
.curve(d3.curveStepAfter);
svg.append("path")
.datum(quantizedSignal)
.attr("fill", "none")
.attr("stroke", "#E74C3C")
.attr("stroke-width", 2)
.attr("d", quantizedLine);
// X axis
svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale).ticks(5).tickFormat(d => `${(d * 100).toFixed(0)}%`))
.call(g => g.append("text")
.attr("x", width / 2)
.attr("y", 35)
.attr("fill", "#666")
.attr("text-anchor", "middle")
.text("Time"));
// Y axis
svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale).ticks(8).tickFormat(d => `${d.toFixed(2)}V`))
.call(g => g.append("text")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("y", -45)
.attr("fill", "#666")
.attr("text-anchor", "middle")
.text("Voltage"));
// Legend
const legend = svg.append("g")
.attr("transform", `translate(${width - margin.right - 120}, ${margin.top})`);
legend.append("rect")
.attr("width", 115)
.attr("height", 60)
.attr("fill", "white")
.attr("stroke", "#ddd")
.attr("rx", 5);
legend.append("line")
.attr("x1", 10).attr("x2", 30)
.attr("y1", 20).attr("y2", 20)
.attr("stroke", "#3498DB").attr("stroke-width", 2);
legend.append("text")
.attr("x", 35).attr("y", 24)
.attr("font-size", "12px")
.text("Analog");
legend.append("line")
.attr("x1", 10).attr("x2", 30)
.attr("y1", 40).attr("y2", 40)
.attr("stroke", "#E74C3C").attr("stroke-width", 2);
legend.append("text")
.attr("x", 35).attr("y", 44)
.attr("font-size", "12px")
.text("Quantized");
return svg.node();
}