Ejercicios: Integración y Aplicación de Conceptos en Python para Física

Introducción

En esta serie de ejercicios, integraremos conceptos fundamentales de programación en Python para resolver problemas de física. Trabajaremos con funciones que manipulan listas, módulos estándar y propios, implementaciones recursivas, y aplicaciones a problemas físicos realistas. Estos ejercicios están diseñados para fortalecer tus habilidades de programación y tu capacidad de modelar fenómenos físicos mediante código.

Parte I: Funciones que Operan sobre Listas

Ejercicio 1: Análisis de Datos de Movimiento

Escribe una función analizar_trayectoria que reciba una lista de tuplas donde cada tupla contiene la posición (x, y) de un objeto en movimiento en diferentes instantes de tiempo, igualmente espaciados. La función debe tener un parámetro adicional intervalo_tiempo que indique el intervalo de tiempo en segundos entre cada medición (por defecto 1 segundo). La función debe calcular y retornar:

  1. La distancia total recorrida.

  2. El desplazamiento neto (distancia en línea recta desde el punto inicial al final).

  3. La velocidad media (magnitud del desplazamiento dividido por el tiempo total).

  4. Una lista con las velocidades instantáneas entre puntos consecutivos.

  5. Los puntos donde la velocidad instantánea cambia de dirección (si existen).

La distancia entre dos puntos consecutivos se calcula como:

\[d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}\]

Ejemplo de uso:

trayectoria = [(0, 0), (1, 1), (2, 0), (3, 2), (4, 1)]
# Usando el valor por defecto (intervalo de 1 segundo)
resultados = analizar_trayectoria(trayectoria)
print(resultados)

# Especificando un intervalo diferente (0.5 segundos entre mediciones)
resultados_detallados = analizar_trayectoria(trayectoria, intervalo_tiempo=0.5)
print(resultados_detallados)
# Debería mostrar la distancia total, desplazamiento, velocidad media,
# lista de velocidades instantáneas y puntos de cambio de dirección

Ejercicio 2: Procesamiento de Datos Experimentales

Implementa una función filtrar_outliers que tome una lista de mediciones experimentales y elimine valores atípicos (outliers). La función debe utilizar el método de la desviación absoluta de la mediana (MAD):

\[\text{MAD} = \text{mediana}(|x_i - \text{mediana}(X)|)\]

Cualquier valor que se desvíe más de n veces el MAD de la mediana se considera un outlier, donde n es un parámetro ajustable (típicamente entre 2 y 3).

La función debe retornar una nueva lista sin los outliers y un informe en forma de diccionario que incluya:

  • 'num_outliers': Número de outliers eliminados

  • 'outliers': Lista con los valores de los outliers

  • 'media_antes': Media aritmética antes de la filtración

  • 'desviacion_antes': Desviación estándar antes de la filtración

  • 'media_despues': Media aritmética después de la filtración

  • 'desviacion_despues': Desviación estándar después de la filtración

Ejemplo:

mediciones = [10.1, 10.2, 10.1, 10.3, 10.2, 15.6, 10.0, 10.1, -2.5, 10.3]
# 15.6 y -2.5 son outliers
datos_filtrados, informe = filtrar_outliers(mediciones, n=2.5)
print(datos_filtrados)  # Lista sin outliers

# El informe es un diccionario con la información del proceso
print(informe['num_outliers'])      # Debería mostrar 2
print(informe['outliers'])          # Debería mostrar [15.6, -2.5]
print(informe['media_antes'])       # Media antes de filtrar
print(informe['desviacion_antes'])  # Desviación estándar antes de filtrar
print(informe['media_despues'])     # Media después de filtrar
print(informe['desviacion_despues']) # Desviación estándar después de filtrar

Ejercicio 3: Búsqueda Binaria para Valores de Energía

Implementa una función busqueda_binaria que encuentre la posición de un valor en una lista ordenada de energías (en electronvoltios, eV). Si el valor exacto no existe, la función debe retornar la posición donde debería insertarse para mantener el orden.

La función debe incluir un parámetro opcional para especificar una tolerancia, permitiendo encontrar valores dentro de un rango cercano al solicitado.

Nota sobre búsqueda binaria: La búsqueda binaria es un algoritmo eficiente para encontrar un elemento en una lista ordenada. Funciona dividiendo repetidamente a la mitad el segmento de la lista que podría contener el elemento, hasta reducir las ubicaciones posibles a solo una. A diferencia de la búsqueda lineal (que revisa cada elemento), la búsqueda binaria tiene una complejidad de O(log n), haciéndola mucho más rápida para listas grandes.

Ejemplo:

energias = [1.2, 2.4, 3.1, 4.5, 5.6, 6.7, 8.2, 9.5]
posicion = busqueda_binaria(energias, 4.5)  # Debería retornar 3
posicion_aprox = busqueda_binaria(energias, 4.6, tolerancia=0.2)  # Debería retornar 3

# Ejemplo donde el valor no existe y se retorna la posición donde debería insertarse
posicion_insercion = busqueda_binaria(energias, 7.0)  # Debería retornar 6
print(f"El valor 7.0 debería insertarse en la posición {posicion_insercion}")
energias_nueva = energias.copy()
energias_nueva.insert(posicion_insercion, 7.0)
print(f"Lista actualizada: {energias_nueva}")  # [1.2, 2.4, 3.1, 4.5, 5.6, 6.7, 7.0, 8.2, 9.5]

# Ejercicio 4: Algoritmo de Ordenamiento para Partículas

Ejercicio 4: Algoritmo de Ordenamiento para Partículas

Escribe una función ordenar_particulas que ordene una lista de partículas representadas como diccionarios. Cada partícula tiene propiedades como masa, carga y energía.

La función debe permitir especificar la propiedad por la cual ordenar y el orden (ascendente o descendente). Implementa el algoritmo de ordenamiento por selección (selection sort) desde cero, sin usar las funciones de ordenamiento integradas de Python.

Ejemplo:

particulas = [
    {'nombre': 'Electrón', 'masa': 9.1e-31, 'carga': -1.6e-19, 'energia': 5.2},
    {'nombre': 'Protón', 'masa': 1.67e-27, 'carga': 1.6e-19, 'energia': 7.8},
    {'nombre': 'Neutrón', 'masa': 1.67e-27, 'carga': 0, 'energia': 2.1},
    {'nombre': 'Muón', 'masa': 1.88e-28, 'carga': -1.6e-19, 'energia': 12.3}
]

# Ordenar por masa (ascendente)
ordenadas_por_masa = ordenar_particulas(particulas, 'masa')

# Ordenar por energía (descendente)
ordenadas_por_energia = ordenar_particulas(particulas, 'energia', ascendente=False)

El algoritmo de ordenamiento por selección (Selection Sort) es un método simple que opera directamente sobre la lista original, realizando un ordenamiento «in-place» (en el lugar):

  1. Se trabaja con una única lista, donde en cada momento hay una parte ordenada (al inicio) y una parte no ordenada (al final).

  2. Inicialmente, toda la lista se considera no ordenada.

  3. En cada iteración:

  • Se recorre la porción no ordenada para encontrar el elemento más pequeño.

  • Este elemento mínimo se intercambia con el primer elemento de la porción no ordenada.

  • La frontera entre la porción ordenada y no ordenada avanza una posición.

  1. El proceso continúa hasta que toda la lista queda ordenada.

A continuación se muestra un diagrama que ilustra el funcionamiento del algoritmo de ordenamiento por selección con una lista de 5 números:

digraph selection_sort {
   // Configuración general
   graph [rankdir=TB, nodesep=0.3, ranksep=0.3];
   node [shape=plaintext, fontname="Helvetica", fontsize=11];
   edge [fontname="Helvetica", fontsize=9];

   // Estado inicial
   initial [label=<
     <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
       <TR><TD COLSPAN="5">Estado Inicial</TD></TR>
       <TR><TD>8</TD><TD>3</TD><TD>5</TD><TD>1</TD><TD>7</TD></TR>
     </TABLE>
   >];

   // Iteración 1
   it1 [label=<
     <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
       <TR><TD COLSPAN="5">Iteración 1: Buscar mínimo</TD></TR>
       <TR><TD>8</TD><TD>3</TD><TD>5</TD><TD BGCOLOR="lightpink">1</TD><TD>7</TD></TR>
       <TR><TD COLSPAN="5">Mínimo encontrado: 1</TD></TR>
     </TABLE>
   >];

   it1_result [label=<
     <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
       <TR><TD COLSPAN="5">Después del intercambio</TD></TR>
       <TR><TD BGCOLOR="lightgreen">1</TD><TD>3</TD><TD>5</TD><TD>8</TD><TD>7</TD></TR>
       <TR><TD BGCOLOR="lightgreen">Ordenado</TD><TD COLSPAN="4">Desordenado</TD></TR>
     </TABLE>
   >];

   // Iteración 2
   it2 [label=<
     <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
       <TR><TD COLSPAN="5">Iteración 2: Buscar mínimo</TD></TR>
       <TR><TD BGCOLOR="lightgreen">1</TD><TD BGCOLOR="lightpink">3</TD><TD>5</TD><TD>8</TD><TD>7</TD></TR>
       <TR><TD BGCOLOR="lightgreen">Ordenado</TD><TD COLSPAN="4">Mínimo: 3</TD></TR>
     </TABLE>
   >];

   it2_result [label=<
     <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
       <TR><TD COLSPAN="5">Después del intercambio</TD></TR>
       <TR><TD BGCOLOR="lightgreen">1</TD><TD BGCOLOR="lightgreen">3</TD><TD>5</TD><TD>8</TD><TD>7</TD></TR>
       <TR><TD COLSPAN="2" BGCOLOR="lightgreen">Ordenado</TD><TD COLSPAN="3">Desordenado</TD></TR>
     </TABLE>
   >];

   // Iteración 3
   it3 [label=<
     <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
       <TR><TD COLSPAN="5">Iteración 3: Buscar mínimo</TD></TR>
       <TR><TD BGCOLOR="lightgreen">1</TD><TD BGCOLOR="lightgreen">3</TD><TD BGCOLOR="lightpink">5</TD><TD>8</TD><TD>7</TD></TR>
       <TR><TD COLSPAN="2" BGCOLOR="lightgreen">Ordenado</TD><TD COLSPAN="3">Mínimo: 5</TD></TR>
     </TABLE>
   >];

   it3_result [label=<
     <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
       <TR><TD COLSPAN="5">Después del intercambio</TD></TR>
       <TR><TD BGCOLOR="lightgreen">1</TD><TD BGCOLOR="lightgreen">3</TD><TD BGCOLOR="lightgreen">5</TD><TD>8</TD><TD>7</TD></TR>
       <TR><TD COLSPAN="3" BGCOLOR="lightgreen">Ordenado</TD><TD COLSPAN="2">Desordenado</TD></TR>
     </TABLE>
   >];

   // Iteración 4
   it4 [label=<
     <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
       <TR><TD COLSPAN="5">Iteración 4: Buscar mínimo</TD></TR>
       <TR><TD BGCOLOR="lightgreen">1</TD><TD BGCOLOR="lightgreen">3</TD><TD BGCOLOR="lightgreen">5</TD><TD>8</TD><TD BGCOLOR="lightpink">7</TD></TR>
       <TR><TD COLSPAN="3" BGCOLOR="lightgreen">Ordenado</TD><TD COLSPAN="2">Mínimo: 7</TD></TR>
     </TABLE>
   >];

   it4_result [label=<
     <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
       <TR><TD COLSPAN="5">Después del intercambio</TD></TR>
       <TR><TD BGCOLOR="lightgreen">1</TD><TD BGCOLOR="lightgreen">3</TD><TD BGCOLOR="lightgreen">5</TD><TD BGCOLOR="lightgreen">7</TD><TD>8</TD></TR>
       <TR><TD COLSPAN="4" BGCOLOR="lightgreen">Ordenado</TD><TD>Desordenado</TD></TR>
     </TABLE>
   >];

   // Resultado final
   final [label=<
     <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
       <TR><TD COLSPAN="5">Lista Ordenada</TD></TR>
       <TR><TD BGCOLOR="lightgreen">1</TD><TD BGCOLOR="lightgreen">3</TD><TD BGCOLOR="lightgreen">5</TD><TD BGCOLOR="lightgreen">7</TD><TD BGCOLOR="lightgreen">8</TD></TR>
     </TABLE>
   >];

   // Conexiones
   initial -> it1 -> it1_result -> it2 -> it2_result -> it3 -> it3_result -> it4 -> it4_result -> final;
}

Ordenamiento por selección de una lista de 5 números.

Parte II: Módulos y Organización de Código

Ejercicio 5: Creación de un Módulo de Mecánica

Crea un módulo llamado mecanica.py que contenga funciones para cálculos relacionados con mecánica clásica:

  1. calcular_trabajo(fuerza, desplazamiento, angulo=0): Calcula el trabajo realizado por una fuerza constante sobre un objeto.

    \[W = F \cdot d \cdot \cos(\theta)\]
  2. energia_cinetica(masa, velocidad): Calcula la energía cinética de un objeto.

    \[E_k = \frac{1}{2}mv^2\]
  3. energia_potencial_gravitatoria(masa, altura, g=9.8): Calcula la energía potencial gravitatoria.

    \[E_p = mgh\]
  4. conservacion_energia(energia_inicial, energia_final, tolerancia=1e-6): Verifica si se conserva la energía dentro de una tolerancia.

Luego, crea un script principal simulacion_energia.py que importe y use estas funciones para simular un péndulo simple, mostrando cómo las energías cinética y potencial varían durante la oscilación y verificando la conservación de la energía total.

El script debe:

  • Simular el movimiento del péndulo para varios periodos

  • Calcular y las energías cinética, potencial y total a lo largo del tiempo

  • Verificar que la energía total se conserva

Ejercicio 6: Análisis Físico con Módulos Estándar

Escribe un programa pendulo.py que analice datos de oscilaciones de un péndulo utilizando módulos estándar de Python como math, random, statistics y sys.

El programa debe:

  1. Generar datos sintéticos de un péndulo:

    • Crear una función simular_pendulo(longitud, tiempo_max, dt, ruido) que:

      • Simule la posición angular θ(t) = θ₀·cos(ωt) donde ω = √(g/L)

      • Añada ruido aleatorio a las posiciones

      • Devuelva dos listas: tiempos y posiciones angulares

  2. Determinar el periodo experimental:

    • Implementar una función calcular_periodo(tiempos, posiciones) que:

      • Detecte los cruces por cero con pendiente positiva en la señal

      • Calcule el tiempo entre cruces consecutivos

      • Devuelva la lista de periodos medidos

  3. Analizar los resultados:

    • Calcular estadísticas básicas del periodo (media, mediana, desviación estándar)

    • Estimar el valor de g usando la fórmula T = 2π√(L/g)

    • Mostrar los resultados en un formato legible

El programa debe funcionar con valores preestablecidos (sin necesidad de argumentos de línea de comando) pero permitir modificarlos fácilmente en el código.

Ejemplo de código base para empezar:

import math
import random
import statistics

def simular_pendulo(longitud=1.0, amplitud=0.1, tiempo_max=10.0, dt=0.01, ruido=0.005):
   """
   Simula el movimiento de un péndulo y devuelve los datos con ruido.

   Args:
      longitud: Longitud del péndulo en metros
      amplitud: Amplitud inicial en radianes
      tiempo_max: Tiempo máximo de simulación en segundos
      dt: Paso temporal en segundos
      ruido: Magnitud del ruido aleatorio en radianes

   Returns:
      Tupla con (lista_tiempos, lista_posiciones)
   """
   # Tu código aquí: implementar la simulación
   pass

def calcular_periodo(tiempos, posiciones):
   """
   Calcula los periodos observados a partir de los datos de posición.

   Args:
      tiempos: Lista de tiempos
      posiciones: Lista de posiciones angulares

   Returns:
      Lista con los periodos medidos
   """
   # Tu código aquí: implementar detección de periodos
   pass

def main():
   # Parámetros de simulación
   longitud = 1.0  # metros
   amplitud = 0.1  # radianes
   g_teorico = 9.8  # m/s²

   # Simular el péndulo
   tiempos, posiciones = simular_pendulo(longitud=longitud, amplitud=amplitud)

   # Calcular periodos
   periodos = calcular_periodo(tiempos, posiciones)

   # Analizar resultados
   periodo_medio = statistics.mean(periodos)
   periodo_std = statistics.stdev(periodos)
   periodo_mediana = statistics.median(periodos)

   # Calcular g experimental
   # Tu código aquí

   # Imprimir resultados
   print("=== ANÁLISIS DE PÉNDULO SIMPLE ===")
   print(f"Longitud: {longitud} m")
   print(f"Periodo medio: {periodo_medio:.4f} ± {periodo_std:.4f} s")
   print(f"Valor de g calculado: {g_calculado:.3f} ± {g_incertidumbre:.3f} m/s²")

if __name__ == "__main__":
   main()

Parte III: Recursividad

Ejercicio 7: Integración Numérica Recursiva

Implementa una función recursiva integrar_recursiva que calcule la integral definida de una función utilizando el método de Simpson recursivo adaptativo.

El método de Simpson recursivo divide el intervalo en dos mitades y aplica la regla:

\[\int_{a}^{b} f(x) dx \approx \frac{b-a}{6} \left[ f(a) + 4f\left(\frac{a+b}{2}\right) + f(b) \right]\]

Para estimar el error, se debe:

  1. Calcular la integral con la fórmula de Simpson para el intervalo completo [a,b], llamémosla S(a,b)

  2. Dividir el intervalo en dos mitades [a,m] y [m,b] donde m=(a+b)/2

  3. Calcular la integral para cada mitad: S(a,m) y S(m,b)

  4. Comparar S(a,b) con la suma S(a,m) + S(m,b)

  5. Estimar el error como:

\[error = \left| S(a,b) - [S(a,m) + S(m,b)] \right|\]

La recursividad se aplica si el error estimado es mayor que una tolerancia especificada. En ese caso, se divide el intervalo en dos y se aplica la integración a cada mitad, sumando los resultados. Si el error es menor que la tolerancia, se acepta el valor S(a,m) + S(m,b) como aproximación válida.

Tu implementación debe:

  • Aceptar la función a integrar, los límites de integración y la tolerancia

  • Aplicar recursivamente el método de Simpson

  • Utilizar la estimación de error como criterio de parada

  • Opcionalmente, incluir un parámetro para limitar la profundidad máxima de recursión

Utiliza esta función para calcular:

  1. La integral de la función seno entre 0 y π (cuyo resultado exacto es 2)

  2. La integral de la función \(e^{-x^2}\) entre -1 y 1 (relacionada con la función error)

Ejemplo:

import math

def integrar_recursiva(f, a, b, tolerancia=1e-6, profundidad_max=30):
    # Implementa el método de Simpson recursivo con estimación de error
    # ...

# Calcular la integral de sin(x) de 0 a π
resultado = integrar_recursiva(math.sin, 0, math.pi, tolerancia=1e-6)
print(f"Integral de sin(x) de 0 a π: {resultado}")  # Debería ser cercano a 2

# Calcular la integral de e^(-x²) de -1 a 1
def gaussiana(x):
    return math.exp(-x**2)

resultado_gaussiana = integrar_recursiva(gaussiana, -1, 1, tolerancia=1e-8)
print(f"Integral de e^(-x²) de -1 a 1: {resultado_gaussiana}")

Parte IV: Problemas de Aplicación

Ejercicio 8: Difusión de Calor en una Varilla

Implementa una simulación numérica de la ecuación de difusión de calor en una dimensión:

\[\frac{\partial T}{\partial t} = \alpha \frac{\partial^2 T}{\partial x^2}\]

donde \(T\) es la temperatura, \(t\) es el tiempo, \(x\) es la posición, y \(\alpha\) es la difusividad térmica.

Para resolver numéricamente esta ecuación, usaremos el método de diferencias finitas:

La ecuación de actualización es:

\[T_i^{n+1} = T_i^n + \alpha \frac{\Delta t}{(\Delta x)^2} (T_{i+1}^n - 2T_i^n + T_{i-1}^n)\]

Donde:

  • \(i\) representa el índice de la posición espacial en la varilla (0, 1, 2, …, N)

  • \(n\) representa el índice del paso temporal (0, 1, 2, …, M)

  • \(T_i^n\) es la temperatura en la posición \(i\) y en el tiempo \(n\)

Condiciones del problema:

  • Condición inicial: Temperatura de 100°C en el centro de la varilla y 25°C en el resto

  • Condiciones de contorno: Los extremos de la varilla se mantienen fijos a 25°C

  • Difusividad térmica: \(\alpha = 0.01\)

  • Longitud de la varilla: 1 metro

  • Tiempo de simulación: 1 segundo

Tu programa debe:

  1. Crear una malla espacial para la varilla (representada por una lista de temperaturas)

  2. Inicializar la temperatura según la condición inicial dada

  3. Para cada paso temporal:

    1. Calcular la distribución de temperatura en el tiempo n+1 a partir de la distribución actual (tiempo n)

    2. Actualizar la distribución actual con los nuevos valores calculados

    3. Repetir el proceso para el número de pasos temporales deseado

  4. Mostrar la distribución de temperatura para diferentes instantes de tiempo durante la simulación

Evolución de la Temperatura en la Varilla

Tiempo

Posición x₀

Posición x₁

Posición x₂

Posición x₃

Posición x₄

Descripción

t₀ (inicial)

25°C

25°C

100°C

25°C

25°C

Condición inicial: calor en el centro

t₁ (ciclo 1)

25°C

26.2°C

97.6°C

26.2°C

25°C

El calor comienza a difundirse

t₂ (ciclo 2)

25°C

27.3°C

95.3°C

27.3°C

25°C

La temperatura continúa equilibrándose

Nota

  • Los extremos (x₀ y x₄) permanecen a temperatura constante de 25°C (condiciones de borde).

  • Para estos cálculos, se usó α = 0.01, Δx = 0.25 m y Δt = 0.1 s.

Fórmula de actualización:

\[T_i^{n+1} = T_i^n + \alpha \frac{\Delta t}{(\Delta x)^2} (T_{i+1}^n - 2T_i^n + T_{i-1}^n)\]

Ejemplo de cálculo para el primer ciclo:

Para calcular la temperatura en la posición x₂ en el tiempo t₁:

\[\begin{split}T_2^1 &= T_2^0 + \alpha \frac{\Delta t}{(\Delta x)^2} (T_{3}^0 - 2T_2^0 + T_{1}^0) \\ &= 100°C + 0.01 \cdot \frac{0.1}{(0.25)^2} \cdot (25°C - 2 \cdot 100°C + 25°C) \\ &= 100°C + 0.016 \cdot (-150°C) \\ &= 100°C - 2.4°C \\ &= 97.6°C\end{split}\]

En cada ciclo, todas las temperaturas interiores (excepto las de los extremos) se actualizan simultáneamente según esta fórmula.

Ejercicio 9: Oscilador Armónico Amortiguado

Implementa una simulación de un oscilador armónico amortiguado, como un sistema masa-resorte con fricción. La ecuación diferencial que gobierna el sistema es:

\[m\frac{d^2x}{dt^2} + b\frac{dx}{dt} + kx = F(t)\]

donde \(m\) es la masa, \(b\) es el coeficiente de amortiguamiento, \(k\) es la constante del resorte, y \(F(t)\) es una fuerza externa que puede variar con el tiempo.

Para resolver numéricamente esta ecuación, sigue estos pasos:

  1. Transformación a ecuaciones de primer orden: Introduce las variables \(x\) (posición) y \(v\) (velocidad), para convertir la ecuación de segundo orden en un sistema de dos ecuaciones de primer orden:

    \[\begin{split}\frac{dx}{dt} &= v \\ \frac{dv}{dt} &= \frac{F(t) - bv - kx}{m}\end{split}\]
  2. Método de integración numérica: Utiliza el método de Euler simple para avanzar la solución en pasos de tiempo pequeños:

    Para cada paso de tiempo de tamaño \(\Delta t\):

    \[\begin{split}x_{n+1} &= x_n + v_n \cdot \Delta t \\ v_{n+1} &= v_n + \frac{F(t_n) - bv_n - kx_n}{m} \cdot \Delta t\end{split}\]
  3. Fuerza externa: Implementa al menos dos tipos diferentes de fuerza externa: - Fuerza constante: \(F(t) = F_0\) - Fuerza sinusoidal: \(F(t) = F_0 \sin(\omega t)\)

  4. Visualización: Calcula y grafica:

    • La posición \(x(t)\) en función del tiempo

    • La velocidad \(v(t)\) en función del tiempo

    • La energía total: \(E(t) = \frac{1}{2}mv^2 + \frac{1}{2}kx^2\)

  5. Análisis de regímenes: Experimenta con diferentes valores de los parámetros para identificar:

    • Régimen subamortiguado (oscilatorio): \(b^2 < 4mk\)

    • Régimen críticamente amortiguado: \(b^2 = 4mk\)

    • Régimen sobreamortiguado: \(b^2 > 4mk\)

    Para cada régimen, muestra un gráfico representativo y explica las diferencias observadas.

Sugerencias prácticas:

  • Utiliza un paso de tiempo pequeño (p. ej., \(\Delta t = 0.01\) segundos) para mantener la estabilidad numérica

  • Simula el sistema durante un tiempo suficientemente largo para observar el comportamiento completo

  • Puedes elegir valores iniciales como \(x(0) = 1\) (posición desplazada) y \(v(0) = 0\) (velocidad inicial nula)

Conclusión

Estos ejercicios están diseñados para integrar múltiples conceptos de programación en Python aplicados a problemas físicos relevantes. Abarcan desde manipulación básica de datos hasta simulaciones complejas, promoviendo un enfoque organizado y modular en la escritura de código.

Recuerda que la clave para resolver estos problemas no es solo obtener el resultado correcto, sino desarrollar soluciones que sean: - Claras y bien documentadas - Eficientes en términos de recursos computacionales - Modeladas correctamente según los principios físicos - Organizadas de manera modular y reutilizable

Al trabajar en estos ejercicios, desarrollarás habilidades valiosas para la modelación computacional en física y otras ciencias.