🎯 But pédagogique¶
Comprendre intuitivement l’impact de la densité d’échantillonnage sur le variogramme expérimental, et l’impact sur l’ajustement d’un modèle théorique à celui-ci.
⚙️ Fonctionnalités¶
- Sliders interactifs pour :
- Le nombre de points d’échantillonnage
- Le pas de classe (lag) utilisé pour le calcul du variogramme expérimental
- Visualisation du champ simulé et des échantillons utilisés
- Comparaison entre variogramme expérimental et modèle ajusté
Source
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, FloatSlider
# --- Modèles de covariance ---
def spherical_cov(h, range_):
return np.where(h < range_, 1 - 1.5 * (h / range_) + 0.5 * (h / range_)**3, 0)
def exponential_cov(h, range_):
return np.exp(-3*h / range_)
def gaussian_cov(h, range_):
return np.exp(-np.sqrt(3)*(h / range_)**2)
def nugget_model(h):
return np.where(h == 0, 1, 0)
def get_cov_model(name, h, range_, sill):
if name == "Spherique":
return spherical_cov(h, range_) * sill
elif name == "Exponentiel":
return exponential_cov(h, range_) * sill
elif name == "Gaussien":
return gaussian_cov(h, range_) * sill
elif name == "Pepite":
return nugget_model(h) * sill
return np.zeros_like(h)
# --- FFT-MA 1D ---
def compute_nested_covariance(h, models):
cov = np.zeros_like(h, dtype=float)
for model in models:
type_ = model["type"]
range_ = model["range"]
sill = model.get("sill", 1.0)
if type_ == "Spherique":
cov += sill * spherical_cov(h, range_)
elif type_ == "Exponentiel":
cov += sill * exponential_cov(h, range_)
elif type_ == "Gaussien":
cov += sill * gaussian_cov(h, range_)
elif type_ == "Pepite":
cov += sill * nugget_model(h)
else:
raise ValueError(f"Modèle de covariance inconnu : {type_}")
return cov
def fftma_1d(n, models, sigma=1.0, seed=544):
if seed is not None:
np.random.seed(seed)
nfft = 2 * n
h = np.arange(nfft)
cov = compute_nested_covariance(h, models)
cov = np.concatenate([cov[:n], cov[:n][::-1]])
spectrum = np.real(np.fft.fft(cov))
spectrum[spectrum < 0] = 0
amp = np.sqrt(np.maximum(spectrum, 1e-10))
noise = np.random.normal(0, 1, nfft)
noise_fft = np.fft.fft(noise)
field_fft = amp * noise_fft
field = np.fft.ifft(field_fft).real[:n]
return field
# --- Variogramme expérimental ---
def empirical_variogram(z, max_lag, lag_step, x=None, n_sample=None, seed=5652):
if x is None:
x = np.arange(len(z))
if seed is not None:
np.random.seed(seed)
if n_sample is not None and n_sample < len(z):
indices_sample = np.random.choice(len(z), n_sample, replace=False)
x = x[indices_sample]
z = z[indices_sample]
else:
indices_sample = np.arange(len(z))
n = len(z)
distances = []
semivars = []
for i in range(n):
for j in range(i + 1, n):
h = abs(x[j] - x[i])
sv = 0.5 * (z[j] - z[i])**2
distances.append(h)
semivars.append(sv)
distances = np.array(distances)
semivars = np.array(semivars)
bins = np.arange(0, max_lag + lag_step * 1.5, lag_step)
bin_indices = np.digitize(distances, bins, right=True) - 1
gamma = []
lags = []
for i in range(len(bins) - 1):
mask = bin_indices == i
gamma.append(np.mean(semivars[mask]) if np.any(mask) else np.nan)
lags.append((bins[i] + bins[i+1]) / 2)
return np.array(lags), np.array(gamma), indices_sample
# --- Données simulées ---
n = 500
models_sim = [
{"type": "Spherique", "range": 100, "sill": 0.8},
{"type": "Pepite", "range": 0, "sill": 0.2}
]
models_adj = [
{"type": "Spherique", "range": 161, "sill": 0.69},
{"type": "Pepite", "range": 2, "sill": 0.20}
]
z_true = fftma_1d(n, models_sim)
lags_exp, gamma_exp, _ = empirical_variogram(z_true, max_lag=n//2, lag_step=5)
# --- Visualisation interactive ---
def plot_fitting(lag_step=5, n_sample=100):
n_sample = int(n_sample)
lags_exp, gamma_exp, sample_indices = empirical_variogram(z_true, max_lag=n//2, lag_step=lag_step, n_sample=n_sample)
models_user = [
{"type": "Spherique", "range": 161, "sill": 0.69},
{"type": "Pepite", "range": 0, "sill": 0.20}
]
gamma_model = [0.69 + 0.20 - compute_nested_covariance(np.array([lag]), models_user)[0] for lag in lags_exp]
gamma_target = []
sill = sum(model['sill'] for model in models_adj)
gamma_target = [sill - compute_nested_covariance(np.array([lag]), models_adj)[0] for lag in lags_exp]
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].plot(lags_exp, gamma_exp, 'o', label="Variogramme expérimental")
axes[0].plot(lags_exp, gamma_model, 'k-', label="Modèle ajusté")
axes[0].set_xlabel("h")
axes[0].set_ylabel("γ(h)")
axes[0].set_title("Ajustement du variogramme")
axes[0].grid(True)
axes[0].legend()
axes[0].set_xlim(0, n//2)
axes[0].set_ylim(0, 2)
x_full = np.arange(len(z_true))
axes[1].plot(x_full, z_true, label="Champ simulé")
axes[1].plot(sample_indices, z_true[sample_indices], 'ro', label="Échantillons")
axes[1].set_xlabel("x")
axes[1].set_ylabel("z(x)")
axes[1].set_title("Champ simulé et points utilisés")
axes[1].grid(True)
axes[1].legend()
plt.tight_layout()
plt.show()
interact(
plot_fitting,
lag_step=FloatSlider(min=1, max=50, step=1, value=5, description="Pas (lag)"),
n_sample=FloatSlider(min=20, max=n, step=10, value=100, description="n échantillons"),
)
Loading...