ELAI S.r.l.

Más puntos, los mismos datos: qué no resuelve añadir ceros

Más puntos, los mismos datos: qué no resuelve añadir ceros Un ejemplo explica método, supuestos y límites.

Más puntos, los mismos datos: qué no resuelve añadir ceros

Un gráfico más denso no contiene medidas nuevas

Un sensor registra una décima de segundo de vibraciones. Un pico ancho puede esconder dos oscilaciones próximas. Añadir ceros suaviza y densifica el gráfico, pero ¿mejora su separación? Estudiamos información observada, no apariencia, con tonos sintéticos de 100 y 103 hercios.

Primero, distinguir tres cantidades

f_s=1000 Hz son mil muestras por segundo; N=100 da T=N/f_s=0,1 s. Ambos tonos tienen amplitud unitaria arbitraria, fase inicial cero y sin ruido. La transformada discreta de Fourier, DFT, compara muestras con oscilaciones complejas. FFT es su algoritmo, no una fuente de observaciones. Frecuencia de muestreo, duración y separación gráfica son distintas.

x[n] = cos(2π·100·n/f_s) + cos(2π·103·n/f_s), n=0,…,N−1

La DFT de N puntos usa k f_s/N, separados diez hercios: ninguno cae en 103 Hz. Un tono entre puntos puede parecer atenuado y repartido. El máximo muestreado no tiene por qué ser la única frecuencia. Para entender el relleno evaluamos la misma suma en f arbitraria.

X(f) = Σ_(n=0..N−1) x[n] exp(−j 2π f n/f_s)

Los ceros cambian dónde evaluamos la suma

Añadimos ceros hasta M=1600 conservando las cien muestras. Los términos nuevos son cero: X(f) sigue siendo la misma función. La rejilla pasa a k f_s/M, cada 0,625 Hz. No observamos otros 1,5 segundos: evaluamos las cien muestras en más frecuencias, aunque el software lo llame resolución FFT.

El código verifica que, con M=16N, cada decimosexto valor coincide con la DFT original dentro de tolerancia. Es el mismo espectro más densamente muestreado. El relleno ayuda a localizar picos distinguibles y reduce error de rejilla, sin añadir ecuaciones independientes sobre la señal. Interpolar puede ser útil sin crear información.

La ventana observada determina la anchura del lóbulo

Una exponencial compleja aislada en f_0 con ventana rectangular de N muestras da una suma geométrica de módulo |sin(πNδ/f_s)/sin(πδ/f_s)|, δ=f−f_0, y límite N en cero. Los primeros ceros son ±f_s/N: anchura principal 2f_s/N. Depende de la ventana, no de M. Una sinusoide real contiene además frecuencia negativa.

Con T=0,1 s los primeros ceros distan diez hercios y los tonos solo tres. Aumentar M no estrecha lóbulos. Adquirir N=1000 a igual frecuencia observa un segundo y reduce esa distancia a un hercio: sí cambia los datos. El gráfico normaliza por muestras observadas, no por M, para no reducir artificialmente amplitudes.

NMT (s)Paso (Hz)
1001000.110
10016000.10.625
10001600010.0625
Ambas curvas tienen ceros y tonos iguales, pero distinta duración observada. Mirar separación, no densidad. Señales sintéticas.
Ambas curvas tienen ceros y tonos iguales, pero distinta duración observada. Mirar separación, no densidad. Señales sintéticas.

Qué no demuestra la comparación

La anchura no es una barrera universal: métodos paramétricos con supuestos fuertes pueden estimar frecuencias próximas, condicionados por ruido, orden e identificabilidad. Comparamos DFT deterministas, no superresolución. Otras ventanas intercambian anchura y lóbulos laterales. Dos picos no certifican por sí solos dos fallos físicos.

El código usa NumPy 2.5.3 y guarda espectros y versiones sin medir hardware. FFT más largas consumen cálculo y memoria; observar más añade latencia de adquisición, distinta del cálculo. Primero decidamos cuánto observar y qué detalle distinguir. Los ceros facilitan leer lo observado, no alargan la observación.

SciPy 1.18.0 — Spectral analysis and zero-padding.

import numpy as np
import json,sys
from pathlib import Path
fs=1000.;runs=[]
for n in [100,1000]:
 t=np.arange(n)/fs;x=np.cos(2*np.pi*100*t)+np.cos(2*np.pi*103*t)
 small=np.fft.rfft(x);m=16*n;large=np.fft.rfft(x,n=m)
 assert np.allclose(large[::16],small,rtol=1e-12,atol=1e-10)
 f=np.fft.rfftfreq(m,1/fs);sel=(f>=80)&(f<=125)
 runs.append(dict(n=n,padded=m,duration=n/fs,spacing=fs/n,paddedSpacing=fs/m,frequency=f[sel].tolist(),amplitude=(2*np.abs(large[sel])/n).tolist()))
r=dict(python=sys.version.split()[0],numpy=np.__version__,seed=None,scope='Synthetic two-tone signals, not sensor or hardware measurements',fsHz=fs,tonesHz=[100,103],runs=runs)
Path(__file__).with_name('results.json').write_text(json.dumps(r,indent=2),encoding='utf8')

Código, datos e instrucciones · JSON. Cálculos didácticos ejecutados con Python 3.14.0; figuras con Matplotlib 3.11.2. Análisis asistido por IA, sin afirmar revisión por pares ni humana. Portada original ImageGen ilustrativa: no documenta personas, sedes ni instalaciones de EL-AI. Fuentes consultadas el 25 de octubre de 2026.