import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import numpy as np

'''---------------- VOS MESURES ----------------'''
t = np.array([  0  ,    10,    20,   30,    40,     50,    60,    70,    80,    90,    100,    110,   120,    130,    140]) # temps mesuré en seconde
uc = np.array([ 0.0, 4.30 , 6.99  , 8.79 , 9.9  , 10.4  , 11     , 11.2     ,     11.5 , 11.6     , 11.7      , 11.8      ,  11.85    ,  11.9     ,  11.94     ]) # tension aux bornes du condensateur en V


'''---------------- MODELISATION ---------------'''
def modelecharge(t, E, tau):
    return E * (1 - np.exp(-t / tau))

# Estimations initiales raisonnables
E_init = uc[-1]  # La tension finale est proche de E
tau_init = 20    # On estime tau autour de 20-30 s

popt, pcov = curve_fit(modelecharge, t, uc, p0=[E_init, tau_init])
E, tau = popt

# Créer un tableau dense pour tracer la courbe lisse
t_modele = np.linspace(0, t.max(), 500)  # 500 points entre 0 et 140
y = modelecharge(t_modele, *popt)

# ---------- Valeurs utiles ----------
uc_final = np.ceil(uc[-1] * 10) / 10  # asymptote (arrondie)
uc_tau = 0.63 * E                    # valeur à tau

'''---------------- GRAPHE ---------------------'''
fig, ax = plt.subplots(figsize=(10, 7))

ax.plot(t, uc, marker='+', linestyle='', label='Mesures', zorder=4, markersize=10, markeredgewidth=2) # données
ax.plot(t_modele, y, 'r-', label='Modélisation de $u_c(t)$', zorder=3, linewidth=2) # modèle LISSE

ax.axhline(uc_final, color='blue', linestyle='-', label='Tension aux bornes du générateur', zorder=2) # asymptote

# tangente (pente correcte à l'origine = E/tau)
t_tangente = np.linspace(0, 1.3 * tau, 100)
tangente = (E / tau) * t_tangente
ax.plot(t_tangente, tangente, color='green', label='Tangente à l\'origine', zorder=3)


# ---------- Axes "flèches" ----------
x_pad = 0.08 * t.max()
y_pad = 0.18 * uc_final
x_left, x_right = -x_pad, t.max() + x_pad
y_bottom, y_top = -0.08 * uc_final, uc_final + y_pad

ax.set_xlim(x_left, x_right)
ax.set_ylim(y_bottom, y_top)

for sp in ['top', 'right', 'left', 'bottom']:
    ax.spines[sp].set_visible(False)

# flèches des axes
ax.annotate('', xy=(x_right, 0), xytext=(x_left, 0),
            arrowprops=dict(arrowstyle='->', linewidth=1.5), clip_on=False, zorder=10)
ax.annotate('', xy=(0, y_top), xytext=(0, y_bottom),
            arrowprops=dict(arrowstyle='->', linewidth=1.5), clip_on=False, zorder=10)

# ---------- Graduations personnalisées ----------
x_ticks = np.arange(0, 150, 20)
y_ticks = np.arange(0, 14, 2)

# Graduations sur l'axe des x
for x_val in x_ticks:
    if x_val > 0:
        ax.plot([x_val, x_val], [0, 0.3], 'black', linewidth=1.5, zorder=10)
        ax.text(x_val, -0.2, str(int(x_val)), ha='center', va='top', fontsize=10)

# Graduations sur l'axe des y
for y_val in y_ticks:
    if y_val > 0:
        ax.plot([0, 2], [y_val, y_val], 'black', linewidth=1.5, zorder=10)
        ax.text(-1.5, y_val, str(int(y_val)), ha='right', va='center', fontsize=10)

ax.set_xticks([])
ax.set_yticks([])

# ---------- Labels et annotations ----------
ax.annotate('0', xy=(0, 0), xytext=(-6, -6), textcoords='offset points',ha='right', va='top', fontsize=10)

ax.annotate(r'$t$ (s)', xy=(x_right, 0), xytext=(5, -10),textcoords='offset points', ha='center', va='top', fontsize=12)
ax.annotate(r'$u_c$ (V)', xy=(0, y_top), xytext=(-30, 5),textcoords='offset points', ha='left', va='bottom', rotation=0, fontsize=12)

ax.set_title('Evolution de la tension aux bornes du condensateur au cours du temps')

# ---------- Grille personnalisée ----------
for x_val in x_ticks:
    if x_val > 0 and x_val <= t.max():
        ax.plot([x_val, x_val], [0, y_top], 'lightgray', linewidth=0.5, zorder=1)

for y_val in y_ticks:
    if y_val > 0 and y_val <= uc_final:
        ax.plot([0, x_right], [y_val, y_val], 'lightgray', linewidth=0.5, zorder=1)

ax.legend(loc='lower right', bbox_to_anchor=(0.95, 0.32))
plt.show()