Diferencia entre revisiones de «Series de Fourier(PDM)»

De MateWiki
Saltar a: navegación, buscar
(Página creada con «{{ TrabajoED | Series de Fourier(DPM)| EDP|2025-26 | Diego García Raposo Paula Dopico Muñoz Manuel Herreros Zarco}} ==Seri...»)
 
(Poster)
 
(No se muestran 2 ediciones intermedias del mismo usuario)
Línea 5: Línea 5:
 
Manuel Herreros Zarco}}
 
Manuel Herreros Zarco}}
  
==Series de Fourier DPM==
+
==Series de Fourier==
  
 
===Poster===
 
===Poster===
[[Archivo:FinalPosterDefinitivo.jpeg|center|800px]]]]
+
[[Archivo:PosterFInal VF(1).png|center|800px]]]]
  
 
===Códigos===
 
===Códigos===
Línea 326: Línea 326:
 
plt.show()
 
plt.show()
 
</pre>
 
</pre>
 +
[[Categoría:EDP]]
 +
[[Categoría:EDP25/26]]

Revisión actual del 00:33 24 feb 2026

Trabajo realizado por estudiantes
Título Series de Fourier(DPM)
Asignatura EDP
Curso 2025-26
Autores Diego García Raposo

Paula Dopico Muñoz

Manuel Herreros Zarco

Este artículo ha sido escrito por estudiantes como parte de su evaluación en la asignatura


1 Series de Fourier

1.1 Poster

center]]

1.2 Códigos

import numpy as np
import matplotlib.pyplot as plt


T = 1.0 ### Longitud del intervalo
n_max = 3  # La frecuencua hasta la que pinta senos y cosenos para representar la base lineal
M = 3000 ### Número de puntos en X

x = np.linspace(-T, T, M) ### Genera un vector de M puntos entre -T y T

plt.figure(figsize=(10,5)) ### Tamaño de la gráfica, pa q sea grande o chiquita pero no afecta a los puntos


phi0 = (1/np.sqrt(2*T)) * np.ones_like(x) ### Genera un vector de 3000 ptos con cada uno la función cte de la basepara luego representarlo
plt.plot(x, phi0, linewidth=3) ### Pinta la linea generada por la función phi0


for n in range(1, n_max + 1): ### Pinta las funciones seno y coseno asociadas a cada frecuencia en el plot
    phi_c = (1/np.sqrt(T)) * np.cos(n*np.pi*x/T) ### funcion coseno
    phi_s = (1/np.sqrt(T)) * np.sin(n*np.pi*x/T) ### funcion seno
    
    plt.plot(x, phi_c)
    plt.plot(x, phi_s) 

plt.title("Base trigonométrica ortonormal en [-T, T]") ### SIstema de representación de python
plt.xlabel("x")
plt.grid(True)
plt.tight_layout()
plt.show()

<pre>
#nuevo código
import math
import numpy as np
import matplotlib.pyplot as plt


# --------- función de ejemplo ----------
def f(x):
    return x   # cambia aquí si quieres


# --------- coeficientes numéricos ----------
def fourier_coeffs_numeric(L, N, M=20000):
    xs = np.linspace(0.0, L, M)
    fx = f(xs)

    a0 = (2.0 / L) * np.trapz(fx, xs)

    a = np.zeros(N + 1)
    b = np.zeros(N + 1)

    for n in range(1, N + 1):
        c = np.cos(2.0 * math.pi * n * xs / L)
        s = np.sin(2.0 * math.pi * n * xs / L)

        a[n] = (2.0 / L) * np.trapz(fx * c, xs)
        b[n] = (2.0 / L) * np.trapz(fx * s, xs)

    return a0, a, b


def S_N(x, L, N, a0, a, b):
    val = a0 / 2.0
    for n in range(1, N + 1):
        val += (
            a[n] * np.cos(2.0 * math.pi * n * x / L)
            + b[n] * np.sin(2.0 * math.pi * n * x / L)
        )
    return val


# --------- visualizar error en muchos puntos ----------
def visualize_error(Ls, N, num_points=500):

    xs = np.linspace(0.001, min(Ls), num_points)  # intervalo común

    plt.figure()

    for L in Ls:

        a0, a, b = fourier_coeffs_numeric(L, N)

        approx = S_N(xs, L, N, a0, a, b)
        exact = f(xs)

        error = np.abs(approx - exact)

        plt.plot(xs, error, label=f"L={L}")

    plt.yscale("log")
    plt.xlabel("x")
    plt.ylabel("|S_N(x) - f(x)|")
    plt.title(f"Error puntual para N={N}")
    plt.legend()
    plt.grid(True, which="both")
    plt.show()


if __name__ == "__main__":

    Ls = [1.0, 4.0]
    N = 20

    visualize_error(Ls, N, num_points=800)



#nuevo código
import numpy as np
import matplotlib.pyplot as plt

# =====================================================
# 1) INTERVALO Y FUNCIÓN
# =====================================================
a, b = 0.0, 1.0 ### Inicio y final del intervalo
L = b - a ### Longitud intervalo

def f(x):
    return np.where((x >= 0.0) & (x < 0.5), 1.0, 0.0) ### Funcion indicatriz 

# =====================================================
# 2) MUESTREO
# =====================================================
M = 8192 ### Numero de puntos en x
x = np.linspace(a, b, M, endpoint=False) ### Genera un vector de M puntos entre a y b, pero no incluye el punto b
fx = f(x) ### Aplica la función a cada elementos del vector del linspace x tanto es un vector de lomgitud M

# =====================================================
# 3) COEFICIENTES REALES DIRECTOS (SIN FFT)
# =====================================================
def coeffs_real_direct(fx, N, a=0.0, L=1.0):
    M = fx.size
    j = np.arange(M)
    xj = a + L*j/M  # mismos puntos que linspace(endpoint=False)

    a0 = fx.mean()  # (1/M) sum f_j

    k = np.arange(1, N+1) ### np array, es decir una lista de las frecuencias ordenadas desde 0 hasta N, siendo N la mayor de la suma parcial deseada
    theta = 2*np.pi * k[:, None] * (xj[None, :] - a) / L ### Crea una matriz donde el elemento Aij es 2*pi*k_i*x_j

    ak = (2/M) * (fx[None, :] * np.cos(theta)).sum(axis=1) ### Calcula un vector donde cada elemento es el coeficiente asociado a la frecuencua ki
    bk = (2/M) * (fx[None, :] * np.sin(theta)).sum(axis=1) ### Lo mismo pero el seno

    return a0, ak, bk

# =====================================================
# 4) RECONSTRUCCIÓN S_N EN BASE REAL
# =====================================================
def partial_sum_real_direct(N, x, fx, a=0.0, L=1.0):
    a0, ak, bk = coeffs_real_direct(fx, N, a=a, L=L)

    k = np.arange(1, N+1) ### Vector de frecuencias 
    theta = 2*np.pi * k[:, None] * (x[None, :] - a) / L ### Genera una matriz elemento Aij es igual que antes pero con el cambio de intervalo para poder aplicar fourier

    sN = a0 \
         + (ak[:, None] * np.cos(theta)).sum(axis=0) \ ### multiplica cada coeficiente con su coseno respectivo, en forma de vector por cada punto del linspace
         + (bk[:, None] * np.sin(theta)).sum(axis=0)   ### lo mismo para el seno

    return sN ### devuelve la serie de fourier

# =====================================================
# 5) VISUALIZACIÓN
# =====================================================
Ns = [1, 3, 5, 10, 40, 80] ### Representación python

cols = 3
rows = (len(Ns) + cols - 1) // cols

fig, axes = plt.subplots(rows, cols, figsize=(12, 3*rows))
axes = axes.flatten()

for i, N in enumerate(Ns):
    sN = partial_sum_real_direct(N, x, fx, a=a, L=L)

    axes[i].plot(x, fx, color='black', linewidth=2, label="f(x)")
    axes[i].plot(x, sN, color='red', linewidth=1.6, label="S_N(x) (sin FFT)")
    axes[i].set_title(f"N = {N}")
    axes[i].grid(True)

    if i == 0:
        axes[i].legend(loc="best")

# Quitar paneles vacíos
for j in range(i+1, len(axes)):
    fig.delaxes(axes[j])

plt.tight_layout()
plt.show()

#nuevo código

import numpy as np
import matplotlib.pyplot as plt

# =====================================================
# CONFIG
# =====================================================
a, b = 0.0, 1.0
L = b - a

M_fft = 8192
h_L2 = 1e-5
Ns = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

m_max = 3  # vamos a construir f0, f1, f2, f3 a mano

# =====================================================
# 1) f0 y sus primitivas exactas f1,f2,f3
# =====================================================
def f0(x):
    return np.where((x >= 0.0) & (x < 0.5), 1.0, 0.0)

def f1(x):
    # ∫0^x f0(t) dt
    return np.where(x < 0.5, x, 0.5)

def f2(x):
    # ∫0^x f1(t) dt
    # x<0.5: x^2/2
    # x>=0.5: (1/2)x - 1/8
    return np.where(x < 0.5, 0.5*x**2, 0.5*x - 0.125)

def f3(x):
    # ∫0^x f2(t) dt
    # x<0.5: x^3/6
    # x>=0.5: (1/4)x^2 - (1/8)x + 1/48
    return np.where(x < 0.5, (x**3)/6.0, 0.25*x**2 - 0.125*x + (1.0/48.0))

f_funcs = [f0, f1, f2, f3]  # lista de funciones exactas

# =====================================================
# 2) MALLAS Y VALORES "TRUE" EN L2
# =====================================================
x_L2 = np.arange(a, b, h_L2)
f_list = [f_funcs[m](x_L2) for m in range(m_max + 1)]  # f0..f3 evaluadas en x_L2

# =====================================================
# 3) Fourier por FFT sobre una malla uniforme para coeficientes
#    (ojo: extensión periódica implícita de lo que haya en [0,1))
# =====================================================
x_fft = np.linspace(a, b, M_fft, endpoint=False)

def fourier_coeffs_up_to_from_samples(fx_samples):
    """
    Devuelve coeffs_up_to(N) -> (a0, ak, bk) para:
    f(x) ~ a0 + sum_{k=1}^N [ak cos(2πk(x-a)/L) + bk sin(2πk(x-a)/L)].
    """
    C = np.fft.fft(fx_samples) / M_fft
    a0 = C[0].real

    def coeffs_up_to(N):
        ck = C[1:N+1]
        ak = 2.0 * ck.real
        bk = -2.0 * ck.imag
        return a0, ak, bk

    return coeffs_up_to

def partial_sum_real(coeffs_up_to, N, xgrid):
    a0, ak, bk = coeffs_up_to(N)
    s = a0 * np.ones_like(xgrid, dtype=float)
    for k in range(1, N+1):
        ang = 2*np.pi*k*(xgrid - a)/L
        s += ak[k-1]*np.cos(ang) + bk[k-1]*np.sin(ang)
    return s

def L2_error(f_true_vals, s_vals, xgrid):
    e = f_true_vals - s_vals
    return np.sqrt(np.trapz(e**2, xgrid))

# Precomputamos coeffs_up_to para cada m (muestreando en x_fft)
coeffs_list = []
for m in range(m_max + 1):
    f_m_on_fft = f_funcs[m](x_fft)  # como es explícita, no hace falta interp
    coeffs_list.append(fourier_coeffs_up_to_from_samples(f_m_on_fft))

# =====================================================
# 4) EXPERIMENTO: error L2 vs N para cada m
# =====================================================
plt.figure(figsize=(7,5))

for m in range(m_max + 1):
    f_true = f_list[m]
    coeffs_up_to = coeffs_list[m]
    E = []
    for N in Ns:
        sN = partial_sum_real(coeffs_up_to, N, x_L2)
        E.append(L2_error(f_true, sN, x_L2))
    plt.loglog(Ns, E, marker='o', label=f"m={m} (f_{m} exacta)")

plt.grid(True, which="both")
plt.xlabel("N")
plt.ylabel(r"$\|f_m - S_N\|_{L^2(0,1)}$")
plt.title("Convergencia L2 vs N usando primitivas EXACTAS (sin integrar numéricamente)")
plt.legend()
plt.tight_layout()
plt.show()

# =====================================================
# 5) Visualización de f_m exactas
# =====================================================
fig, axes = plt.subplots(m_max + 1, 1, figsize=(9, 2.4*(m_max+1)))
if m_max == 0:
    axes = [axes]

for m in range(m_max + 1):
    axes[m].plot(x_L2, f_list[m], linewidth=1.8)
    axes[m].grid(True)
    axes[m].set_title(f"f_{m}(x) exacta (integración aplicada {m} veces)")

plt.tight_layout()
plt.show()