Error sistemático y modelado#
Bajo la aproximación de pequeñas oscilaciones,
el periodo de oscilación
donde
Si medimos el periodo
En la práctica, se suele observar que hay que agregar una constante al ajuste. Sin embargo, no es lo mismo agregar una constante en (2)
que en (1)
En (2),
se puede interpretar esta constante
Veamos que sucede si simulamos uno de estos casos y ajustamos por los modelos incorrectos.
Show code cell content
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
def ajustar(func, x, y, yerr=None, **kwargs):
"""Ajusta con curve_fit y devuelve los errores
en lugar de la matriz de covarianza."""
p, cov = curve_fit(func, x, y, sigma=yerr, **kwargs)
err = np.sqrt(np.diag(cov))
return p, err
def graficar_ajuste(x, y, y_pred, yerr=None, *, color="C0", fig=None, axes=None):
"""Grafica el ajuste y los residuos."""
if axes is None:
if fig is None:
fig = plt.figure()
axes = fig.subplots(2, sharex=True)
axes[0].errorbar(x, y, yerr, fmt="o", capsize=5, color=color)
axes[0].plot(x, y_pred, color=color)
axes[1].errorbar(x, y - y_pred, yerr, fmt="o", capsize=5, color=color)
axes[1].axhline(0, color=color)
return axes
g = 9800 # mm/s
def periodo(L, g):
"""Periodo del péndulo en la aproximación de pequenas oscilaciones.
T = 2π √(L/g)
"""
return 2 * np.pi * np.sqrt(L / g)
Simulando una medición#
Para entender que pasa al analizar incorrectamente las mediciones, por ejemplo, cuando se ignora el efecto del error sistemático en la longitud, necesitamos simular correctamente el proceso de medición.
Hipótesis#
Para la simulación, vamos a asumir dos cosas:
tenemos un error sistemático
en la longitud ,el error en el periodo
es despreciable frente al error en la longitud .
Este último punto es razonable,
ya que podemos medir muchos periodos para una dada longitud,
y reducir el error de
Error por resolución en la longitud #
Al preparar el experimento,
se arma el péndulo de una dada longitud
donde asumimos que medimos con una cinta metrica de
Por otro lado,
el periodo
Con un error sistemático #
Para considerar un error sistemático
Al igual que antes,
el
Show code cell content
def experimento(*, L_min=300, L_max=1000, N_largos=10, L0=0, decimales=0):
def medir():
ΔL = 10 ** (-decimales)
# Los valores reales
# Al L real, para que no sea exactamente igual al medido cuando redondeemos,
# y varie en las repeticiones del experimento,
# le agregamos una pequeña desviación, tal que sus decimales no sean 0.
L_real = np.linspace(L_min, L_max, N_largos)
L_real += np.random.uniform(-ΔL / 2, ΔL / 2, size=N_largos)
T_real = periodo(L_real, g=g)
# Los valores medidos:
# - el T medido no tiene error, así que lo dejamos igual al T real
# - el L medido proviene de redonear el L real + un error sistemático L0
T_medido = T_real
L_medido = np.round(L_real + L0, decimales)
# El error para L equivalente a una desviación estándar es:
L_err = ΔL / 12**0.5
L_err = np.full(N_largos, L_err)
return T_medido, L_medido, L_err, L_real
return medir
Efecto del error sistemático#
Al realizar una simulación,
tenemos acceso a los valores reales,
sin «error de medición».
Antes de hacer ajustes,
podemos comparar las «mediciones» contra los valores reales.
Para eso,
vamos a realizar simulaciones para diferentes parámetros,
y gráficar tanto
Show code cell content
def graficar_vs_real(medir):
"""Realiza una medición y realiza un gráfico con residuos,
tanto para T^2 vs L como T vs √L."""
T, L, L_err, L_real = medir()
figs = plt.figure(figsize=(8, 3)).subfigures(ncols=3, width_ratios=[1, 0.3, 1])
# T^2 vs L
figs[0].suptitle("$L$ vs $T^2$")
axes = graficar_ajuste(x=T**2, y=L, y_pred=L_real, yerr=L_err, fig=figs[0])
axes[0].set(ylabel="L [mm]")
axes[1].set(ylabel="Residuos [mm]", xlabel="T² [s²]")
# T vs L^1/2
figs[2].suptitle(r"$\sqrt{L}$ vs $T$")
axes = graficar_ajuste(
x=T, y=L**0.5, y_pred=L_real**0.5, yerr=L_err / 2 / L**0.5, fig=figs[2]
)
axes[0].set(ylabel=r"$\sqrt{L}$ [√mm]")
axes[1].set(ylabel="Residuos [√mm]", xlabel="T [s]")
for fig in figs:
fig.align_ylabels()
Sin error sistemático#
Si no tenemos error sistemático, en ambos gráficos se observa una relación lineal, y los residuos se distribuyen aleatoriamente alrededor del 0.
graficar_vs_real(experimento(L_min=50, N_largos=30, L0=0))

Error sistemático en la longitud#
Si simulamos un error sistemático pequeño,
Para
En cambio,
para
graficar_vs_real(experimento(L_min=50, N_largos=30, L0=1))

Rango de longitudes medidas#
Con el mismo
graficar_vs_real(experimento(L_min=500, N_largos=30, L0=1))

Aumentando la precisión en #
Si aumentamos la precisión de medición de
graficar_vs_real(experimento(L_min=500, N_largos=30, L0=1, decimales=1))

Ajustes y el estimado#
Realicemos simulaciones para diferentes parámetros experimentales
y observemos que sucede con la estimación de
Definamos 3 funciones para ajustar, correspondientes a las ecuaciones (1), (3) y (4).
def sin_constante(T, g):
Tp = T / (2 * np.pi)
return g * Tp**2
def sistematico_longitud(T, g, L_0):
Tp = T / (2 * np.pi)
return g * Tp**2 + L_0
def sistematico_periodo(T, g, T_0):
Tp = T / (2 * np.pi)
return g * (Tp + T_0) ** 2
En lo siguiente,
simularemos una medición y ajustaremos las 3 funciones,
gráficando el ajuste y los residuos.
Además,
repetiremos estre proceso
Show code cell content
def repetir_experimentos(medir, N_experimentos=1000):
def create_plot_axes(fig):
ax_plot, *ax_residuos = fig.subplots(4, sharex=True)
ax_plot.set(ylabel="Longitud [mm]")
for ax in ax_residuos:
ax.set(ylabel="Residuos [mm]")
ax.set(xlabel="Periodo [s]")
fig.align_ylabels()
return ax_plot, ax_residuos
def create_hist_axes(fig):
_, fig = fig.subfigures(2, height_ratios=[1, 4])
ax = fig.subplots()
ax.set(xlabel="Ac. de la gravedad [mm/s]")
return ax
def ajustar_y_graficar(func, T, L, L_err, *, color, ax_plot, ax_residuos):
p, err = ajustar(func, T, L, L_err)
L_pred = func(T, *p)
ax_plot.plot(T, L_pred, color=color, linestyle="--")
ax_residuos.errorbar(T, L - L_pred, L_err, fmt="o", capsize=5, color=color)
ax_residuos.axhline(0, color=color)
figs = plt.figure(figsize=(8, 6)).subfigures(ncols=2)
ax_plot, ax_residuos = create_plot_axes(figs[0])
ax_hist = create_hist_axes(figs[1])
labels = ("Sin constante", "Longitud $L_0$", "Tiempo $T_0$")
funcs = (sin_constante, sistematico_longitud, sistematico_periodo)
colors = ("C0", "C1", "C2")
T, L, L_err, _ = medir()
ax_plot.errorbar(T, L, L_err, fmt="o", capsize=5, color="black")
for ax, func, color in zip(ax_residuos, funcs, colors):
ajustar_y_graficar(
func,
T,
L,
L_err,
color=color,
ax_plot=ax_plot,
ax_residuos=ax,
)
def analisis_multiple():
T, L, L_err, _ = medir()
p0, _ = ajustar(sin_constante, T, L, L_err)
p1, _ = ajustar(sistematico_longitud, T, L, L_err)
p2, _ = ajustar(sistematico_periodo, T, L, L_err)
return p0[0], p1[0], p2[0]
p = np.array([analisis_multiple() for _ in range(N_experimentos)])
ax_hist.axvline(g, color="black", label="Valor real")
for label, pi in zip(labels, p.T):
ax_hist.hist(pi, bins="auto", histtype="step", label=label)
ax_hist.legend(loc="lower left", bbox_to_anchor=(0, 1))
Sin error sistemático#
Al no tener error sistemático,
los tres modelos ajustan bien a las mediciones,
a juzgar por los gráficos de los residuos.
Con respecto a los histogramas de
repetir_experimentos(experimento(L_min=100, L0=0, N_largos=30))

Error sistemático grande#
Si tenemos un error sistemático «grande»,
repetir_experimentos(experimento(L_min=100, L0=5, N_largos=30))

Rango de longitudes medidas#
Si achicamos el rango de longitudes medidas,
alejándonos de
repetir_experimentos(experimento(L_min=500, L0=5, N_largos=30))

Error sistemático pequeño#
Consideramos un error sistemático pequeño,
Si medimos para pocas longitudes,
repetir_experimentos(experimento(L_min=300, L0=0.1, N_largos=10))

En cambio,
si medimos para más longitudes,
repetir_experimentos(experimento(L_min=300, L0=0.1, N_largos=100))
/tmp/ipykernel_1998/3907591550.py:9: OptimizeWarning: Covariance of the parameters could not be estimated
p, cov = curve_fit(func, x, y, sigma=yerr, **kwargs)
