"""Секущая и касательная для авторской обратимой функции Psi(I).

Среда: встроенный Python FEMM 5. Входы: А, Вб; выходы: Гн, Дж.
Это аналитическая кривая без гистерезиса, не паспорт стали и не FEMM-решение.
"""
import math
import json

psi_sat_Wb, current_scale_A, I0_A = 0.06, 5.0, 5.0

def psi(current_A):
    # tanh через exp доступен и в минимальном встроенном math.
    e = math.exp(2 * current_A / current_scale_A)
    return psi_sat_Wb * (e - 1) / (e + 1)

psi0 = psi(I0_A)
x = I0_A / current_scale_A
cosh_x = (math.exp(x) + math.exp(-x)) / 2
L_sec_H = psi0 / I0_A
L_diff_H = psi_sat_Wb / current_scale_A / (cosh_x * cosh_x)
coenergy_J = psi_sat_Wb * current_scale_A * math.log(cosh_x)
energy_J = I0_A * psi0 - coenergy_J
records = []
for step_A in (0.1, 0.05, 0.025):
    derivative = (psi(I0_A + step_A) - psi(I0_A - step_A)) / (2 * step_A)
    records.append({"step_A": step_A, "L_central_H": derivative,
                    "relative_error": abs(derivative / L_diff_H - 1)})

# Проверяем касательную, сходимость разности и тождество энергии/коэнергии.
assert abs(L_diff_H - 0.005039692099368312) < 1e-12
assert 0 < L_diff_H < L_sec_H
assert records[-1]["relative_error"] < records[0]["relative_error"]
assert abs(energy_J + coenergy_J - I0_A * psi0) < 1e-14
print(json.dumps({"origin": "author_analytical_reference_not_FEMM",
                  "I0_A": I0_A, "psi0_Wb": psi0,
                  "L_sec_H": L_sec_H, "L_diff_H": L_diff_H,
                  "energy_J": energy_J, "coenergy_J": coenergy_J,
                  "ripple_local_A": 1.0 * 0.0005 / L_diff_H,
                  "derivative_checks": records}))
