codex/capacitive-bridging-error-bandwidth.py

capacitive-bridging-error-bandwidth.py
"""A finite input resistance almost exhausts an unloaded-source error budget."""
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np


def main():
    source_resistance = 1e4
    input_resistance = 1e6
    input_capacitance = 1e-10
    tolerance = 0.01
    g = source_resistance / input_resistance
    scale = 2 * np.pi * source_resistance * input_capacitance
    complex_limit = np.sqrt((tolerance**2 * (1 + g)**2 - g**2)
                            / (1 - tolerance**2)) / scale
    amplitude_limit = np.sqrt(1 / (1 - tolerance)**2 - (1 + g)**2) / scale
    half_power = (1 + g) / scale

    def transfer(f):
        return 1 / (1 + g + 1j * scale * f)

    assert np.isclose(abs(1 - transfer(complex_limit)), tolerance)
    assert np.isclose(1 - abs(transfer(amplitude_limit)), tolerance)
    assert np.isclose(abs(transfer(half_power)) / abs(transfer(0)), 1 / np.sqrt(2))
    f = np.geomspace(1, 1e6, 2401)
    h = transfer(f)
    fig, ax = plt.subplots(figsize=(8.6, 4.5), dpi=100, layout="constrained")
    fig.set_facecolor("white")
    ax.loglog(f, 100 * abs(1 - h), color="#246e99", label="Complex error |1 − H|")
    ax.loglog(f, 100 * (1 - abs(h)), color="#b36a31", label="Amplitude loss 1 − |H|")
    ax.axhline(100 * tolerance, color="#333333", linestyle="--", linewidth=1,
                label="1% allowance")
    ax.axvline(half_power, color="#888888", linestyle=":", linewidth=1.2,
                label="Half power relative to DC")
    for limit, color, label, offset in [
        (complex_limit, "#246e99", f"Complex: {complex_limit:.2f} Hz", (-12, 33)),
        (amplitude_limit, "#b36a31", f"Amplitude: {amplitude_limit:.2f} Hz", (12, -28)),
    ]:
        ax.scatter([limit], [100 * tolerance], color=color, s=28, zorder=4)
        ax.annotate(label, (limit, 100 * tolerance), xytext=offset,
                     textcoords="offset points", color=color, fontsize=9,
                     ha="right" if offset[0] < 0 else "left",
                     arrowprops={"arrowstyle": "-", "color": color})
    ax.set(xlim=(1, 1e6), ylim=(0.5, 120), xlabel="Frequency (Hz)",
            ylabel="Error relative to unloaded source (%)",
            title="DC loading error = 0.9901%; total error allowance = 1%")
    ax.grid(which="both", alpha=0.12)
    ax.legend(loc="upper left", fontsize=9)
    fig.savefig(Path(__file__).with_suffix(".png").name, facecolor="white")
    plt.close(fig)


if __name__ == "__main__":
    main()