codex/vibroscope-bending-bias.py

vibroscope-bending-bias.py
"""Plot an original simply supported tensioned-beam model, not experimental data.

Writes vibroscope-bending-bias.png in the current working directory. The actual
clamped-grip vibroscope problem has different boundary conditions.
"""

from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np


def main():
    for ratio in (0.0, 0.1, 1.0, 2.0):
        intercept = 4e6
        gradient = ratio * intercept
        first = np.sqrt(intercept + gradient)
        second = 2 * np.sqrt(intercept + 4 * gradient)
        np.testing.assert_allclose(
            (second**2 / 4 - first**2) / 3, gradient, atol=1e-8
        )
        np.testing.assert_allclose(
            (4 * first**2 - second**2 / 4) / 3, intercept
        )
        np.testing.assert_allclose(intercept / first**2, 1 / (1 + ratio))
        assert 2 <= second / first < 4

    plt.rcParams.update({"font.size": 11, "axes.titlesize": 11})
    fig, axes = plt.subplots(1, 2, figsize=(8.8, 4.4), dpi=100, facecolor="white")
    fig.subplots_adjust(left=0.08, right=0.975, top=0.78, bottom=0.17, wspace=0.33)
    fig.suptitle("Hinged fibre model: frequency and area bias", fontsize=15, y=0.97)
    fig.text(0.5, 0.88, r"Simply supported ends; $r=\pi^2 B/(T L^2)$; $B=EI$",
             ha="center", fontsize=12)
    ratio = np.linspace(0, 2, 601)
    area = 1 / (1 + ratio)
    modes = 2 * np.sqrt((1 + 4 * ratio) / (1 + ratio))
    axes[0].plot(ratio, area, color="#0072b2", lw=2.4)
    axes[0].set(xlabel="Bending-to-tension parameter r", ylabel=r"Area ratio $\hat A/A$",
                title="Uncorrected flexible-string estimate", xlim=(0, 2), ylim=(0.25, 1.05))
    axes[0].plot(0.1, 1 / 1.1, "o", color="#0072b2")
    axes[0].annotate("r = 0.10:\n9.09% below true area", xy=(0.1, 1 / 1.1),
                     xytext=(0.55, 0.88), fontsize=10,
                     arrowprops={"arrowstyle": "->", "color": "#555555"})
    axes[1].plot(ratio, modes, color="#d55e00", lw=2.4)
    axes[1].axhline(4, ls="--", color="#888888", lw=0.9)
    axes[1].set(xlabel="Bending-to-tension parameter r", ylabel=r"Mode ratio $f_2/f_1$",
                title="Diagnostic from two frequencies", xlim=(0, 2), ylim=(1.9, 4.15))
    axes[1].text(1.97, 3.94, "large-r limit", ha="right", va="top", fontsize=9)
    for ax in axes:
        ax.grid(alpha=0.23)
        ax.set_facecolor("white")
        ax.spines[["top", "right"]].set_visible(False)
    fig.savefig(Path.cwd() / "vibroscope-bending-bias.png", dpi=100,
                facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()