"""Sensory modality definitions and energy hierarchy (SPECTRAL A.1.1)."""
from dataclasses import dataclass
from enum import Enum
import numpy as np
from mercurial.spectral.quantum_fields import ModalityField, UnifiedField
[docs]
class Modality(Enum):
"""All sensory modalities recognized in SPECTRAL."""
DPR = "dpr"
AFFECTIVE = "affective"
AUDITORY = "auditory"
TACTILE = "tactile"
VISUAL = "visual"
OLFACTORY = "olfactory"
GUSTATORY = "gustatory"
PROPRIOCEPTIVE = "proprioceptive"
VESTIBULAR = "vestibular"
INTEROCEPTIVE = "interoceptive"
NOCICEPTIVE = "nociceptive"
THERMOCEPTIVE = "thermoceptive"
CHRONOCEPTIVE = "chronoceptive"
AGENCY = "agency"
MAGNETOCEPTIVE = "magnetoceptive"
ELECTROCEPTIVE = "electroceptive"
[docs]
@dataclass
class ModalitySpec:
name: Modality
log_energy_threshold: float # log10(E_thresh) [log10(J)]
baseline_latency: float # τ_act0 [s]
coupling_coefficient: float # sensitivity
# Energy thresholds from SPECTRAL A.1.1 (in log10 Joules)
MODALITY_SPECS = {
Modality.DPR: ModalitySpec(Modality.DPR, -23.0, 0.001, 1.0),
Modality.AFFECTIVE: ModalitySpec(Modality.AFFECTIVE, -21.0, 0.0, 0.9),
Modality.AUDITORY: ModalitySpec(Modality.AUDITORY, -18.0, 0.05, 0.8),
Modality.TACTILE: ModalitySpec(Modality.TACTILE, -17.0, 0.1, 0.7),
Modality.VISUAL: ModalitySpec(Modality.VISUAL, -16.0, 0.2, 0.6),
Modality.OLFACTORY: ModalitySpec(Modality.OLFACTORY, -15.0, 0.5, 0.5),
Modality.GUSTATORY: ModalitySpec(Modality.GUSTATORY, -13.0, 1.0, 0.4),
Modality.PROPRIOCEPTIVE: ModalitySpec(Modality.PROPRIOCEPTIVE, -18.0, 0.01, 0.7),
Modality.VESTIBULAR: ModalitySpec(Modality.VESTIBULAR, -18.0, 0.01, 0.7),
Modality.INTEROCEPTIVE: ModalitySpec(Modality.INTEROCEPTIVE, -19.0, 0.5, 0.6),
Modality.NOCICEPTIVE: ModalitySpec(Modality.NOCICEPTIVE, -17.0, 0.05, 0.8),
Modality.THERMOCEPTIVE: ModalitySpec(Modality.THERMOCEPTIVE, -18.0, 0.1, 0.7),
Modality.CHRONOCEPTIVE: ModalitySpec(Modality.CHRONOCEPTIVE, -20.0, 0.0, 0.5),
Modality.AGENCY: ModalitySpec(Modality.AGENCY, -19.0, 0.05, 0.6),
Modality.MAGNETOCEPTIVE: ModalitySpec(Modality.MAGNETOCEPTIVE, -21.0, 0.5, 0.3),
Modality.ELECTROCEPTIVE: ModalitySpec(Modality.ELECTROCEPTIVE, -20.0, 0.3, 0.4),
}
[docs]
class ModalityEnergyHierarchy:
"""Manages energy thresholds and manifestation probabilities."""
[docs]
def __init__(self, steepness: float = 5.0, spatial_points: int = 10):
"""
steepness: logistic slope factor (higher = sharper transition)
"""
self.steepness = steepness
self.unified_field = UnifiedField(spatial_points)
self.specs = MODALITY_SPECS
def manifestation_probability(
self, modality: Modality, pattern_energy: float, pattern_entropy: float
) -> float:
"""
p_manif = sigmoid(steepness * (log10(E_pattern) - log10(E_thresh)))
* max(0, 1 - entropy/10)
"""
spec = self.specs[modality]
logE_pattern = np.log10(max(pattern_energy, 1e-30))
logE_thresh = spec.log_energy_threshold
# Logistic function centered at threshold
energy_factor = 1.0 / (1.0 + np.exp(-self.steepness * (logE_pattern - logE_thresh)))
# Entropy factor: lower entropy → higher probability
entropy_factor = max(0.0, 1.0 - pattern_entropy / 10.0)
# Coupling coefficient modulates overall sensitivity
return energy_factor * entropy_factor * spec.coupling_coefficient
[docs]
def activation_time(self, modality: Modality, pattern_power: float) -> float:
"""
τ_act = τ_0 + ΔE / P_bias
Using log-energy difference as proxy for ΔE.
"""
spec = self.specs[modality]
logE_pattern = np.log10(max(pattern_power, 1e-30))
logE_thresh = spec.log_energy_threshold
delta_logE = max(0.0, logE_thresh - logE_pattern)
# Convert log difference to a time penalty
time_penalty = delta_logE * 0.1 # 0.1 s per order of magnitude deficit
return spec.baseline_latency + time_penalty
[docs]
def dominant_modality(self, pattern_energy: float, pattern_entropy: float) -> Modality:
best_mod = None
best_prob = -1.0
for mod in Modality:
prob = self.manifestation_probability(mod, pattern_energy, pattern_entropy)
if prob > best_prob:
best_prob = prob
best_mod = mod
return best_mod
[docs]
def update_field_evolution(self, dt: float, pattern_energy: float, pattern_coherence: float):
"""Call this each simulation step to evolve quantum fields."""
self.unified_field.evolve_all(dt, pattern_energy, pattern_coherence)
[docs]
def manifestation_probability(
self, modality: Modality, pattern_energy: float, pattern_entropy: float
) -> float:
# Use field-based probability if available, else fallback
try:
mod_field = getattr(ModalityField, modality.name)
return self.unified_field.manifestation_probability(mod_field)
except (AttributeError, KeyError):
# Fallback to energy-based
spec = self.specs[modality]
logE_pattern = np.log10(max(pattern_energy, 1e-30))
logE_thresh = spec.log_energy_threshold
energy_factor = 1.0 / (1.0 + np.exp(-self.steepness * (logE_pattern - logE_thresh)))
entropy_factor = max(0.0, 1.0 - pattern_entropy / 10.0)
return energy_factor * entropy_factor * spec.coupling_coefficient