codexcockcroft-walton-voltage-ladder-and-beam-readout.py
cockcroft-walton-voltage-ladder-and-beam-readout.py
"""Original functional schematic; Python 3.14, matplotlib 3.10.7.
Run from _media; output is an opaque white PNG in the current directory.
The charge pump is intentionally a block, not a construction circuit.
"""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch
def box(ax, xy, width, height, text, color="#eaf2f8", fontsize=11):
ax.add_patch(FancyBboxPatch(xy, width, height, boxstyle="round,pad=0.04",
facecolor=color, edgecolor="#29475c", linewidth=1.3))
ax.text(xy[0] + width / 2, xy[1] + height / 2, text,
ha="center", va="center", fontsize=fontsize)
def arrow(ax, start, end, color="#176a9a"):
ax.annotate("", end, start, arrowprops=dict(arrowstyle="->", color=color, lw=2))
def main():
plt.rcParams.update({"font.size": 11, "font.family": "DejaVu Sans"})
fig, (a, b) = plt.subplots(2, 1, figsize=(10, 7),
gridspec_kw={"height_ratios": [1.1, 1]})
fig.patch.set_facecolor("white")
fig.suptitle("Store voltage, accelerate a beam, identify the products", fontsize=16)
for ax in (a, b):
ax.set(xlim=(0, 10), ylim=(0, 4))
ax.axis("off")
a.text(0, 3.8, "A. Chosen three-stage ideal ladder", fontsize=13, weight="bold")
box(a, (0.1, 0.65), 1.65, 1.05, "Alternating input\npeak $V_p$")
box(a, (2.15, 0.35), 2.15, 1.65, "Rectified charge\ntransfer\n(functional block)")
arrow(a, (1.8, 1.17), (2.1, 1.17))
levels = [0.45, 1.35, 2.25, 3.15]
for j, y in enumerate(levels):
a.plot([5.1, 7.0], [y, y], color="#29475c", lw=1.4)
a.text(7.15, y, ["0", "$2V_p$", "$4V_p$", "$6V_p$"][j], va="center")
if j < 3:
yc = (y + levels[j + 1]) / 2
a.plot([6.0, 6.0], [y, yc - .1], color="#29475c")
a.plot([6.0, 6.0], [yc + .1, levels[j + 1]], color="#29475c")
for offset in (-.1, .1):
a.plot([5.6, 6.4], [yc + offset] * 2, color="#176a9a", lw=2)
a.text(6.55, yc, "$C$", va="center")
for j in range(1, 4):
arrow(a, (4.35, 1.5), (5.1, levels[j]))
a.text(8.1, 2.35, "Series storage\nadds voltage", ha="center")
a.text(8.1, .8, "Load removes charge;\npump replenishes it", ha="center")
a.text(.1, -.02, "Block diagram only • no component ratings or wiring • not the 1932 stage count", fontsize=10)
b.text(0, 3.8, "B. Beam and reaction readout", fontsize=13, weight="bold")
box(b, (.15, 2.2), 1.6, 1, "Positive ions\nat $+V$")
box(b, (2.45, 2.1), 3.05, 1.2, "Evacuated accelerating tube\n$K_f-K_i=qV$")
box(b, (6.3, 2.15), 1.55, 1.1, "Lithium\ntarget\nat ground", color="#fff1dc")
arrow(b, (1.8, 2.7), (2.4, 2.7))
arrow(b, (5.55, 2.7), (6.25, 2.7))
b.text(5.87, 3.18, "beam", ha="center", fontsize=10)
box(b, (6.25, .15), 1.75, .9, "Mica absorber\nor window", color="#f1f0fb")
box(b, (8.4, .15), 1.35, .9, "ZnS screen\n+ microscope", color="#e9f5e9", fontsize=10)
arrow(b, (7.1, 2.1), (7.1, 1.1), color="#a63d35")
b.text(7.3, 1.55, "products", color="#a63d35", fontsize=10)
arrow(b, (8.05, .6), (8.35, .6), color="#a63d35")
b.text(.25, 1.3, "One total potential drop sets beam energy.\nAbsorption and flashes test the products.", fontsize=12)
b.text(.25, .3, "Historical readout functions; geometry simplified.\nBeam blocking supplies a separate control.", fontsize=10)
fig.subplots_adjust(top=.9, bottom=.07, left=.045, right=.98, hspace=.23)
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), dpi=130, facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()