Skip to content

[WIP] Add biological spectral model QCAL implementation#1030

Draft
Copilot wants to merge 1 commit intomainfrom
copilot/add-biological-spectral-model
Draft

[WIP] Add biological spectral model QCAL implementation#1030
Copilot wants to merge 1 commit intomainfrom
copilot/add-biological-spectral-model

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 8, 2026

Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.

‎modelo_biologico_espectral.py‎

  • 590
    Líneas modificadas: 590 adiciones y 0 eliminaciones
    Número de línea del archivo original Número de línea de diferencia Cambio de línea diferencial
    #!/usr/bin/env python3

-- coding: utf-8 --

"""
Modelo Biológico Espectral QCAL
Una nueva hipótesis falsable que une biología y teoría de números
a través del campo espectral Ψ
Autor: José Manuel Mota Burruezo
Instituto Consciencia Cuántica QCAL ∞³
Fecha: 27 de enero de 2026
"""
import numpy as np
import matplotlib.pyplot as plt
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
import json
import os
import tempfile

============================================================================

CONSTANTES FUNDAMENTALES

============================================================================

Frecuencia base QCAL

F_QCAL = 141.70001 # Hz

Frecuencias ambientales características

FREQ_ANUAL = 2 * np.pi / (365 * 24 * 3600) # rad/s (ciclo estacional)
FREQ_DIURNA = 2 * np.pi / (24 * 3600) # rad/s (ciclo día-noche)
FREQ_LUNAR = 2 * np.pi / (29.5 * 24 * 3600) # rad/s (ciclo lunar)

Parámetro de memoria de fase (retención del 90% de fase anterior)

ALPHA_MEMORIA = 0.1

Ciclos primos de Magicicada

CICLOS_MAGICICADA = [13, 17]

============================================================================

CLASES DE DATOS

============================================================================

@DataClass
class ComponenteEspectral:
"""Componente individual del campo espectral"""
amplitud: float # A_i
frecuencia: float # ω_i (rad/s)
fase: float # φ_i (radianes)
nombre: str = ""

def evaluar(self, t: float) -> complex:
    """Evalúa la componente en el tiempo t"""
    return self.amplitud * np.exp(1j * (self.frecuencia * t + self.fase))

@DataClass
class EstadoBiologico:
"""Estado del sistema biológico en un momento dado"""
tiempo: float
fase_acumulada: float
campo_psi: complex
activado: bool
coherencia: float

============================================================================

CLASE PRINCIPAL: MODELO BIOLÓGICO ESPECTRAL

============================================================================

class ModeloBiologicoEspectral:
"""
Implementación del modelo QCAL para relojes biológicos espectrales.

El modelo describe cómo los organismos responden a señales espectrales
del entorno, acumulando fase hasta alcanzar un umbral crítico que 
desencadena la acción biológica.
"""

def __init__(self, 
             componentes_ambientales: List[ComponenteEspectral],
             umbral_critico: float = 1.0,
             alpha_memoria: float = ALPHA_MEMORIA):
    """
    Inicializa el modelo biológico espectral.
    
    Args:
        componentes_ambientales: Lista de componentes espectrales del entorno
        umbral_critico: Φ_crítico para activación biológica
        alpha_memoria: Parámetro de memoria de fase (0.1 = 90% retención)
    """
    self.componentes = componentes_ambientales
    self.umbral_critico = umbral_critico
    self.alpha = alpha_memoria
    
    # Estado interno
    self.fase_acumulada = 0.0
    self.fase_anterior = 0.0
    self.activado = False
    self.historial: List[EstadoBiologico] = []
    
def campo_ambiental(self, t: float) -> complex:
    """
    Calcula el campo espectral ambiental Ψ_e(t).
    
    Ψ_e(t) = Σ A_i * exp(i(ω_i*t + φ_i))
    
    Args:
        t: Tiempo en segundos
        
    Returns:
        Campo espectral complejo en el tiempo t
    """
    psi = 0.0 + 0.0j
    for comp in self.componentes:
        psi += comp.evaluar(t)
    return psi

def filtro_biologico(self, omega: float) -> float:
    """
    Filtro biológico H(ω) que representa la selectividad del organismo.
    
    Args:
        omega: Frecuencia angular (rad/s)
        
    Returns:
        Ganancia del filtro en la frecuencia omega
    """
    # Convertir a Hz para clasificación
    freq_hz = omega / (2 * np.pi)
    
    # Banda media (1-100 Hz): resonancias proteicas y celulares
    if 1.0 <= freq_hz <= 100.0:
        return 1.0
    
    # Banda baja (<1 Hz): ciclos ambientales lentos - IMPORTANTE para Magicicada
    elif freq_hz < 1.0:
        return 1.0  # Permitir acumulación de ciclos estacionales
    
    # Banda alta (>100 Hz): filtrado parcial
    else:
        return 0.5

def acumular_fase(self, t: float, dt: float) -> float:
    """
    Acumula fase según el modelo de memoria exponencial.
    
    Φ_acum(t) = Φ_acum(t-1) + incremento con memoria
    
    Args:
        t: Tiempo actual
        dt: Paso temporal
        
    Returns:
        Fase acumulada total
    """
    # Densidad de energía espectral filtrada
    # Aproximación: |H(ω)*Ψ_e(ω)|²
    energia_filtrada = 0.0
    for comp in self.componentes:
        H = self.filtro_biologico(comp.frecuencia)
        energia_filtrada += (H * comp.amplitud) ** 2
    
    # Incremento de fase en este paso temporal
    # Normalizar por el período del año para que un ciclo anual acumule ~1
    segundos_por_año = 365 * 24 * 3600
    incremento = energia_filtrada * dt / segundos_por_año
    
    # Aplicar memoria exponencial al incremento
    # La memoria suaviza fluctuaciones pero no impide acumulación
    incremento_suavizado = self.alpha * incremento + (1 - self.alpha) * self.fase_anterior
    
    # Acumular (sumar al total)
    self.fase_acumulada += incremento_suavizado
    self.fase_anterior = incremento_suavizado
    
    return self.fase_acumulada

def verificar_condicion_activacion(self, t: float, dt: float) -> bool:
    """
    Verifica si se cumple la condición de activación biológica.
    
    Condición: Φ(t) ≥ Φ_crítico AND dΦ/dt > 0
    
    Args:
        t: Tiempo actual
        dt: Paso temporal
        
    Returns:
        True si se activa, False en caso contrario
    """
    # Condición 1: Umbral alcanzado
    umbral_alcanzado = self.fase_acumulada >= self.umbral_critico
    
    # Condición 2: Flujo positivo (tendencia creciente)
    flujo_positivo = self.fase_anterior > 0
    
    return umbral_alcanzado and flujo_positivo

def simular(self, t_max: float, dt: float = 3600.0) -> List[EstadoBiologico]:
    """
    Simula la evolución temporal del sistema biológico.
    
    Args:
        t_max: Tiempo máximo de simulación (segundos)
        dt: Paso temporal (segundos, default=1 hora)
        
    Returns:
        Lista de estados a lo largo del tiempo
    """
    self.historial = []
    tiempos = np.arange(0, t_max, dt)
    
    for t in tiempos:
        # Acumular fase
        self.acumular_fase(t, dt)
        
        # Calcular campo Ψ
        psi = self.campo_ambiental(t)
        
        # Calcular coherencia (|Ψ|/max(|Ψ|))
        coherencia = abs(psi)
        
        # Verificar activación (solo si aún no está activado)
        if not self.activado:
            self.activado = self.verificar_condicion_activacion(t, dt)
        
        # Registrar estado (usar el estado de activación actual)
        estado = EstadoBiologico(
            tiempo=t,
            fase_acumulada=self.fase_acumulada,
            campo_psi=psi,
            activado=self.activado,
            coherencia=coherencia
        )
        self.historial.append(estado)
    
    return self.historial

def tiempo_activacion(self) -> Optional[float]:
    """
    Retorna el tiempo en que ocurrió la activación biológica.
    
    Returns:
        Tiempo de activación en segundos, o None si no se activó
    """
    for estado in self.historial:
        if estado.activado:
            return estado.tiempo
    return None

def generar_reporte(self) -> Dict:
    """
    Genera un reporte completo del modelo y simulación.
    
    Returns:
        Diccionario con resultados y métricas
    """
    t_activacion = self.tiempo_activacion()
    
    reporte = {
        "modelo": "Modelo Biológico Espectral QCAL",
        "frecuencia_base_qcal": F_QCAL,
        "parametros": {
            "umbral_critico": self.umbral_critico,
            "alpha_memoria": self.alpha,
            "num_componentes": len(self.componentes)
        },
        "componentes_ambientales": [
            {
                "nombre": c.nombre,
                "amplitud": c.amplitud,
                "frecuencia_Hz": c.frecuencia / (2 * np.pi),
                "fase_rad": c.fase
            }
            for c in self.componentes
        ],
        "resultados": {
            "activado": self.activado,
            "tiempo_activacion_dias": t_activacion / (24 * 3600) if t_activacion else None,
            "fase_final": self.fase_acumulada,
            "pasos_simulados": len(self.historial)
        }
    }
    
    return reporte

============================================================================

MODELO ESPECÍFICO: MAGICICADA

============================================================================

class ModeloMagicicada(ModeloBiologicoEspectral):
"""
Modelo especializado para la cigarra periódica (Magicicada spp.).

Implementa el mecanismo de memoria de fase que explica los ciclos
de 13 y 17 años con precisión de ±3-5 días.
"""

def __init__(self, ciclo_años: int = 17):
    """
    Inicializa el modelo de Magicicada.
    
    Args:
        ciclo_años: Número de años del ciclo (13 o 17)
    """
    assert ciclo_años in CICLOS_MAGICICADA, \
        f"Ciclo debe ser {CICLOS_MAGICICADA}"
    
    # Componentes espectrales que la cigarra "escucha"
    componentes = [
        ComponenteEspectral(
            amplitud=1.0,
            frecuencia=FREQ_ANUAL,
            fase=0.0,
            nombre="Ciclo estacional anual"
        ),
        ComponenteEspectral(
            amplitud=0.3,
            frecuencia=FREQ_DIURNA,
            fase=0.0,
            nombre="Ciclo térmico diurno"
        ),
        ComponenteEspectral(
            amplitud=0.1,
            frecuencia=FREQ_LUNAR,
            fase=0.0,
            nombre="Ciclo lunar"
        ),
        # Componente resonante QCAL (141.7 Hz)
        ComponenteEspectral(
            amplitud=0.05,
            frecuencia=2 * np.pi * F_QCAL,
            fase=0.0,
            nombre="Resonancia QCAL 141.7 Hz"
        )
    ]
    
    # Umbral crítico: N ciclos anuales
    # Energía media por ciclo ≈ amplitud² = 1.0
    umbral = ciclo_años * 1.0
    
    super().__init__(
        componentes_ambientales=componentes,
        umbral_critico=umbral,
        alpha_memoria=ALPHA_MEMORIA
    )
    
    self.ciclo_años = ciclo_años

def precision_emergencia(self) -> Tuple[float, float]:
    """
    Calcula la precisión de emergencia del modelo.
    
    Returns:
        (desviacion_estandar_dias, precision_porcentual)
    """
    if not self.activado:
        return (None, None)
    
    # Tiempo teórico ideal
    t_teorico = self.ciclo_años * 365 * 24 * 3600  # segundos
    
    # Tiempo real de emergencia
    t_real = self.tiempo_activacion()
    
    # Desviación
    desviacion_seg = abs(t_real - t_teorico)
    desviacion_dias = desviacion_seg / (24 * 3600)
    
    # Precisión porcentual
    precision = 100 * (1 - desviacion_seg / t_teorico)
    
    return (desviacion_dias, precision)

============================================================================

FUNCIONES DE VISUALIZACIÓN

============================================================================

def graficar_evolucion_temporal(modelo: ModeloBiologicoEspectral,
guardar: str = None):
"""
Grafica la evolución temporal del campo Ψ y la fase acumulada.

Args:
    modelo: Modelo con historial de simulación
    guardar: Ruta para guardar la figura (opcional)
"""
if not modelo.historial:
    print("Error: El modelo no tiene historial de simulación.")
    return

tiempos_dias = [e.tiempo / (24 * 3600) for e in modelo.historial]
fases = [e.fase_acumulada for e in modelo.historial]
coherencias = [e.coherencia for e in modelo.historial]

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))

# Gráfico 1: Fase acumulada
ax1.plot(tiempos_dias, fases, 'b-', linewidth=2)
ax1.axhline(y=modelo.umbral_critico, color='r', linestyle='--', 
            label=f'Umbral crítico = {modelo.umbral_critico}')

# Marcar punto de activación
t_act = modelo.tiempo_activacion()
if t_act:
    t_act_dias = t_act / (24 * 3600)
    fase_act = [e.fase_acumulada for e in modelo.historial 
                if e.tiempo == t_act][0]
    ax1.plot(t_act_dias, fase_act, 'ro', markersize=10, 
            label=f'Activación (día {t_act_dias:.1f})')

ax1.set_xlabel('Tiempo (días)', fontsize=12)
ax1.set_ylabel('Fase Acumulada Φ(t)', fontsize=12)
ax1.set_title('Acumulación de Fase en el Tiempo', fontsize=14, fontweight='bold')
ax1.legend()
ax1.grid(True, alpha=0.3)

# Gráfico 2: Coherencia del campo
ax2.plot(tiempos_dias, coherencias, 'g-', linewidth=2)
ax2.set_xlabel('Tiempo (días)', fontsize=12)
ax2.set_ylabel('Coherencia |Ψ(t)|', fontsize=12)
ax2.set_title('Coherencia del Campo Espectral', fontsize=14, fontweight='bold')
ax2.grid(True, alpha=0.3)

plt.tight_layout()

if guardar:
    plt.savefig(guardar, dpi=300, bbox_inches='tight')
    print(f"Figura guardada en: {guardar}")

plt.show()

def graficar_espectro_ambiental(modelo: ModeloBiologicoEspectral,
guardar: str = None):
"""
Grafica el espectro de frecuencias del campo ambiental.

Args:
    modelo: Modelo biológico espectral
    guardar: Ruta para guardar la figura (opcional)
"""
frecuencias_hz = [c.frecuencia / (2 * np.pi) for c in modelo.componentes]
amplitudes = [c.amplitud for c in modelo.componentes]
nombres = [c.nombre for c in modelo.componentes]

fig, ax = plt.subplots(figsize=(12, 6))

# Gráfico de barras en escala logarítmica
colores = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728']
bars = ax.bar(range(len(frecuencias_hz)), amplitudes, 
              color=colores[:len(frecuencias_hz)])

ax.set_xticks(range(len(frecuencias_hz)))
ax.set_xticklabels([f"{n}\n({f:.2e} Hz)" for n, f in zip(nombres, frecuencias_hz)],
                   rotation=15, ha='right')
ax.set_ylabel('Amplitud A_i', fontsize=12)
ax.set_title('Espectro del Campo Ambiental Ψ_e', fontsize=14, fontweight='bold')
ax.grid(True, alpha=0.3, axis='y')

plt.tight_layout()

if guardar:
    plt.savefig(guardar, dpi=300, bbox_inches='tight')
    print(f"Figura guardada en: {guardar}")

plt.show()

============================================================================

FUNCIÓN DE DEMOSTRACIÓN

============================================================================

def demo_magicicada():
"""
Demostración del modelo aplicado a Magicicada de ciclo 17 años.
"""
print("=" * 80)
print("MODELO BIOLÓGICO ESPECTRAL QCAL")
print("Demostración: Magicicada ciclo 17 años")
print("=" * 80)
print()

# Crear modelo
modelo = ModeloMagicicada(ciclo_años=17)

print("Configuración del modelo:")
print(f"  • Ciclo: {modelo.ciclo_años} años")
print(f"  • Umbral crítico: Φ_crítico = {modelo.umbral_critico}")
print(f"  • Memoria de fase: α = {modelo.alpha} (retención 90%)")
print(f"  • Componentes espectrales: {len(modelo.componentes)}")
print()

# Simular 20 años para asegurar activación
t_max = 20 * 365 * 24 * 3600  # 20 años en segundos
dt = 24 * 3600  # Paso de 1 día

print(f"Simulando {20} años (paso temporal: {dt/(24*3600)} día)...")
modelo.simular(t_max=t_max, dt=dt)
print(f"  ✓ Simulación completada: {len(modelo.historial)} pasos")
print()

# Resultados
t_act = modelo.tiempo_activacion()
if t_act:
    t_act_años = t_act / (365 * 24 * 3600)
    t_act_dias = t_act / (24 * 3600)
    desv_dias, precision = modelo.precision_emergencia()
    
    print("RESULTADOS:")
    print(f"  ✓ Activación biológica detectada")
    print(f"  • Tiempo de emergencia: {t_act_años:.4f} años ({t_act_dias:.1f} días)")
    print(f"  • Desviación del ciclo teórico: ±{desv_dias:.2f} días")
    print(f"  • Precisión: {precision:.4f}%")
    print(f"  • Fase final acumulada: {modelo.fase_acumulada:.4f}")
    print()
    
    # Comparación con datos empíricos
    print("Comparación con datos empíricos de Magicicada:")
    print(f"  • Desviación observada: ±3-5 días")
    print(f"  • Precisión observada: 99.92%")
    print(f"  • Desviación del modelo: ±{desv_dias:.2f} días")
    print(f"  • Precisión del modelo: {precision:.4f}%")
    
    if abs(desv_dias) <= 5:
        print(f"  ✓ El modelo reproduce la precisión empírica")
    else:
        print(f"  ⚠ El modelo requiere ajuste de parámetros")
else:
    print("  ✗ No se detectó activación en el tiempo simulado")

print()
print("=" * 80)

# Generar reporte JSON
reporte = modelo.generar_reporte()

# Usar directorio temporal apropiado
temp_dir = tempfile.gettempdir()
reporte_path = os.path.join(temp_dir, 'reporte_magicicada.json')

with open(reporte_path, 'w') as f:
    json.dump(reporte, f, indent=2)
print(f"Reporte guardado en: {reporte_path}")

# Graficar
print("Generando gráficos...")
evolucion_path = os.path.join(temp_dir, 'magicicada_evolucion.png')
espectro_path = os.path.join(temp_dir, 'magicicada_espectro.png')

graficar_evolucion_temporal(modelo, guardar=evolucion_path)
graficar_espectro_ambiental(modelo, guardar=espectro_path)

return modelo

============================================================================

PUNTO DE ENTRADA

============================================================================

if name == "main":
# Ejecutar demostración
modelo = demo_magicicada()

print()
print("=" * 80)
print("CONCLUSIÓN")
print("=" * 80)
print()
print("El modelo QCAL demuestra que:")
print()
print("1. Los organismos pueden responder a estructuras espectrales,")
print("   no solo a acumulación energética total.")
print()
print("2. La memoria de fase (α ≈ 0.1) confiere robustez ante")
print("   perturbaciones ambientales.")
print()
print("3. La precisión de emergencia de Magicicada (99.92%) puede")
print("   explicarse mediante resonancia de múltiples ciclos ambientales.")
print()
print("4. La frecuencia QCAL 141.7 Hz actúa como componente resonante")
print("   que modula la respuesta biológica.")
print()
print("Esta hipótesis es FALSABLE mediante los experimentos propuestos.")
print()
print("=" * 80)

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Copilot stopped work on behalf of motanova84 due to an error March 8, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants