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()

Voici les différents seuil que l’on doit respecter en utilisant des détecteurs TPA LED en GaP et InGaAs

                       seuil utile : 10⁸ W/cm²   

                       seuil danger : 10⁹ W/cm²

                       destruction : ≥10¹⁰ W/cm²

Pour un spot de 60 micron de diamètre sur le détecteur