import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
# =========================
# CONSTANTES PHYSIQUES
# =========================
beta0 = 5e-11 # GaP TPA approx
noise_floor = 1e-3 # 1 mV oscillo typique
R = 50 # ohms
# seuils physiques (W/cm²)
I_tpa = 1e7
I_sat = 5e8
I_damage = 1e9
# =========================
# MODELES
# =========================
def beta_lambda(l):
return beta0 * np.exp(-((l – 1000)/600)**2)
def saturation(I):
# saturation douce
return I / (1 + I/I_sat)
def compute(E, tau, S, wl, gain_db, detector= »PD »):
G = 10**(gain_db/20)
beta = beta_lambda(wl)
P = E / tau
I = P / S # W/m²
I_cm = I / 1e4 # W/cm²
# saturation
I_eff = saturation(I_cm)
signal = beta * (I_eff*1e4)**2 # retour en W/m²
# différence LED vs photodiode
if detector == « LED »:
signal *= 2 # LED souvent plus efficace en TPA localisée
else:
signal *= 1
V = signal * G * 1e-6
return V, I_cm
# =========================
# DOMAINE
# =========================
E = np.logspace(-9, -3, 400)
# =========================
# FIGURE
# =========================
fig, ax = plt.subplots()
plt.subplots_adjust(left=0.1, bottom=0.4)
tau0 = 200e-15
S0 = 100e-12
wl0 = 1030
gain0 = 40
V, Icm = compute(E, tau0, S0, wl0, gain0)
line, = ax.loglog(E*1e9, V, lw=2)
ax.set_xlabel(« Énergie (nJ) »)
ax.set_ylabel(« Tension (V) »)
ax.set_title(« TPA GaP PRO Tool »)
ax.grid()
# =========================
# ZONES PHYSIQUES
# =========================
ax.axhline(noise_floor, linestyle=’–‘, label= »Bruit oscillo »)
ax.axhline(1e-1, linestyle=’–‘, label= »Zone utile »)
ax.axhline(10, linestyle=’–‘, label= »Saturation électronique »)
ax.legend()
# =========================
# SLIDERS
# =========================
ax_tau = plt.axes([0.15, 0.30, 0.7, 0.03])
ax_S = plt.axes([0.15, 0.25, 0.7, 0.03])
ax_lambda = plt.axes([0.15, 0.20, 0.7, 0.03])
ax_gain = plt.axes([0.15, 0.15, 0.7, 0.03])
slider_tau = Slider(ax_tau, ‘Durée (fs)’, 10, 1e7, valinit=200)
slider_S = Slider(ax_S, ‘Surface (µm²)’, 10, 1000, valinit=100)
slider_lambda = Slider(ax_lambda, ‘λ (nm)’, 800, 2000, valinit=1030)
slider_gain = Slider(ax_gain, ‘Gain (dB)’, 0, 70, valinit=40)
# =========================
# TEXTE INFO
# =========================
text_box = ax.text(0.02, 0.95, « », transform=ax.transAxes)
# =========================
# UPDATE
# =========================
def update(val):
tau = slider_tau.val * 1e-15
S = slider_S.val * 1e-12
wl = slider_lambda.val
gain = slider_gain.val
V, Icm = compute(E, tau, S, wl, gain)
line.set_ydata(V)
# info en direct
I_peak = np.max(Icm)
if I_peak < I_tpa:
regime = « TPA faible »
elif I_peak < I_sat:
regime = « TPA optimal »
elif I_peak < I_damage:
regime = « Saturation »
else:
regime = « DANGER »
text_box.set_text(
f »I max = {I_peak:.2e} W/cm²\n »
f »Régime = {regime} »
)
fig.canvas.draw_idle()
slider_tau.on_changed(update)
slider_S.on_changed(update)
slider_lambda.on_changed(update)
slider_gain.on_changed(update)
plt.show()
































