tostido's picture
Add blueprints archive: ARACHNE-001, MARIONETTE-001, AIRFOIL-CORDAGE-SYSTEM, PERSPECTIVE
26fa66a
"""
Archery Tether Propulsion Systems - Main Simulation
====================================================
Entry point for the KAPS (Kinetic Active Protection System) simulation.
This simulation demonstrates:
1. Cross-formation flight with 4 TABs
2. 360° defensive bubble mechanics
3. Slingshot intercept maneuvers
4. Speed burst escape mechanics
"""
import numpy as np
import yaml
import time
from pathlib import Path
from typing import Dict, Optional
# Physics engines
from .physics import (
TetherArray, CableProperties, CableState,
MomentumEngine, SlingshotManeuver, SlingshotParameters, MomentumState,
ReleaseMode
)
# Entities
from .entities import (
MotherDrone, MotherDroneConfig,
TABArray, TowedAerodynamicBody, FormationPosition
)
# AI Controllers
from .ai import (
DefensiveMatrixAI, DefenseConfig, ThreatType,
FormationController, FormationMode
)
class KAPSSimulation:
"""
Main simulation controller for the Kinetic Active Protection System.
Orchestrates:
- Physics integration
- Entity updates
- AI decision making
- Visualization callbacks
"""
def __init__(self, config_path: Optional[str] = None):
# Load configuration
if config_path:
with open(config_path, 'r') as f:
self.config = yaml.safe_load(f)
else:
self.config = self._default_config()
# Initialize physics engines
self.momentum_engine = MomentumEngine()
cable_props = CableProperties(
length=self.config['cables']['length'],
diameter=self.config['cables']['diameter'],
breaking_strength=self.config['cables']['breaking_strength'],
stiffness=self.config['cables']['stiffness'],
damping=self.config['cables']['damping'],
linear_density=self.config['cables']['linear_density'],
max_tension=self.config['cables']['max_tension'],
min_tension=self.config['cables']['min_tension']
)
self.tether_array = TetherArray(cable_props, num_cables=4)
# Initialize entities
drone_config = MotherDroneConfig(
mass=self.config['mother_drone']['mass'],
wingspan=self.config['mother_drone']['wingspan'],
max_thrust=self.config['mother_drone']['max_thrust'],
cruise_thrust_ratio=self.config['mother_drone']['cruise_thrust_ratio']
)
self.mother_drone = MotherDrone(drone_config)
self.tab_array = TABArray(
cable_length=cable_props.length,
mother_position=self.mother_drone.position
)
# Initialize AI
self.defensive_ai = DefensiveMatrixAI(DefenseConfig(
detection_radius=self.config['defensive_ai']['detection_radius'],
tracking_update_rate=self.config['defensive_ai']['tracking_update_rate']
))
self.formation_ctrl = FormationController()
# Slingshot maneuver handler
slingshot_params = SlingshotParameters(
spiral_rate=np.radians(self.config['slingshot']['spiral_rate']),
wind_up_time=2.0,
release_angle=np.pi/2,
cable_length=cable_props.length,
conservation_efficiency=self.config['slingshot']['conservation_efficiency']
)
self.slingshot = SlingshotManeuver(self.momentum_engine, slingshot_params)
# Simulation state
self.time = 0.0
self.dt = self.config['simulation']['timestep']
self.running = False
# Telemetry history
self.telemetry_log = []
def _default_config(self) -> Dict:
"""Default configuration if no file provided"""
return {
'mother_drone': {
'mass': 150.0,
'wingspan': 8.0,
'max_thrust': 2500.0,
'cruise_thrust_ratio': 0.9
},
'cables': {
'length': 30.0,
'diameter': 0.004,
'breaking_strength': 15000.0,
'stiffness': 1.2e9,
'damping': 0.15,
'linear_density': 0.012,
'max_tension': 12000.0,
'min_tension': 50.0
},
'defensive_ai': {
'detection_radius': 500.0,
'tracking_update_rate': 100.0
},
'slingshot': {
'spiral_rate': 45.0,
'conservation_efficiency': 0.95
},
'simulation': {
'timestep': 0.001,
'duration': 60.0
}
}
def step(self) -> Dict:
"""
Execute one simulation timestep.
Returns telemetry data for visualization.
"""
# 1. Get current positions/velocities
tab_positions = self.tab_array.get_positions()
tab_velocities = self.tab_array.get_velocities()
# 2. Compute cable forces
tether_results = self.tether_array.compute_all_forces(
self.mother_drone.position,
self.mother_drone.velocity,
tab_positions,
tab_velocities,
self.dt
)
# 3. Formation control
formation_commands = self.formation_ctrl.compute_control_commands(
self.mother_drone.position,
self.mother_drone.velocity,
tab_positions,
tab_velocities,
self.dt
)
# Apply formation commands to TABs
for tab_id, cmd in formation_commands.items():
if tab_id in self.tab_array.tabs:
self.tab_array.tabs[tab_id].set_control_targets(
elevator=cmd['elevator'],
rudder=cmd['rudder']
)
# 4. Defensive AI response
tab_states = {
tab_id: tab.get_status_report()
for tab_id, tab in self.tab_array.tabs.items()
}
defense_response = self.defensive_ai.calculate_defensive_response(
self.mother_drone.position,
self.mother_drone.velocity,
tab_states
)
# 5. Execute any release commands
for release_cmd in defense_response['release_commands']:
tab_id = release_cmd['tab_id']
if tab_id in self.tab_array.tabs:
tab = self.tab_array.tabs[tab_id]
# Calculate release velocity
release_vel = self.momentum_engine.compute_release_velocity(
self.mother_drone.momentum_state,
tab.momentum_state,
tether_results.get(tab_id, {}).get('tension', 0),
ReleaseMode.SLINGSHOT if release_cmd['mode'] == 'slingshot' else ReleaseMode.INSTANT,
self.slingshot.params
)
# Execute release
tab.execute_release(release_vel)
self.tether_array.release_cable(tab_id)
self.mother_drone.release_tab(tab_id)
# 6. Update mother drone
total_tether_force = tether_results.get('total_mother_force', np.zeros(3))
mother_telemetry = self.mother_drone.update(self.dt, total_tether_force)
# 7. Update all TABs
cable_forces = {
tab_id: tether_results.get(tab_id, {}).get('force_on_tab', np.zeros(3))
for tab_id in self.tab_array.tabs
}
cable_states = {
tab_id: tether_results.get(tab_id, {}).get('state', CableState.ATTACHED)
for tab_id in self.tab_array.tabs
}
tab_telemetry = self.tab_array.update_all(self.dt, cable_forces, cable_states)
# 8. Update time
self.time += self.dt
# 9. Compile telemetry
telemetry = {
'time': self.time,
'mother_drone': mother_telemetry,
'tabs': tab_telemetry,
'cables': {
tab_id: {
'tension': tether_results.get(tab_id, {}).get('tension', 0),
'length': tether_results.get(tab_id, {}).get('length', 0),
'state': str(tether_results.get(tab_id, {}).get('state', CableState.ATTACHED))
}
for tab_id in self.tab_array.tabs
},
'defense': self.defensive_ai.get_defensive_bubble_status(),
'formation': self.formation_ctrl.get_formation_status(
self.mother_drone.position,
tab_positions
)
}
return telemetry
def run(self, duration: Optional[float] = None, callback=None):
"""
Run simulation for specified duration.
Args:
duration: Simulation time in seconds (default from config)
callback: Optional function called each step with telemetry
"""
if duration is None:
duration = self.config['simulation']['duration']
self.running = True
start_time = time.time()
print(f"Starting KAPS Simulation - Duration: {duration}s")
print("=" * 50)
while self.time < duration and self.running:
telemetry = self.step()
if callback:
callback(telemetry)
# Progress update every second
if int(self.time * 10) % 10 == 0 and int(self.time) != int(self.time - self.dt):
self._print_status(telemetry)
real_time = time.time() - start_time
print("=" * 50)
print(f"Simulation complete. Sim time: {self.time:.2f}s, Real time: {real_time:.2f}s")
print(f"Speed ratio: {self.time/real_time:.1f}x realtime")
def _print_status(self, telemetry: Dict):
"""Print compact status line"""
md = telemetry['mother_drone']
defense = telemetry['defense']
print(f"T={self.time:6.1f}s | "
f"Alt: {md['altitude']:6.1f}m | "
f"Speed: {md['speed']:5.1f}m/s | "
f"TABs: {self.tab_array.count_attached()}/4 | "
f"Alert: {defense['alert_level']}")
def inject_threat(self,
position: np.ndarray = None,
velocity: np.ndarray = None,
threat_type: ThreatType = ThreatType.MISSILE_IR):
"""
Inject a threat for testing defensive response.
Args:
position: Threat starting position (default: 400m ahead)
velocity: Threat velocity vector (default: toward mother drone)
threat_type: Type of threat
"""
if position is None:
# Default: threat approaching from ahead
position = self.mother_drone.position + np.array([400, 50, 0])
if velocity is None:
# Default: heading toward mother drone at 100 m/s
to_mother = self.mother_drone.position - position
to_mother = to_mother / (np.linalg.norm(to_mother) + 1e-9)
velocity = to_mother * 100
threat_id = self.defensive_ai.detect_threat(
position,
velocity,
threat_type,
self.mother_drone.position
)
print(f"THREAT INJECTED: {threat_id} - {threat_type.value}")
return threat_id
def execute_speed_burst(self, verbose: bool = False):
"""
Execute emergency speed burst maneuver.
Releases all TABs for maximum acceleration.
"""
if verbose:
print("EXECUTING SPEED BURST MANEUVER")
# Get pre-release state
pre_speed = self.mother_drone.speed
# Release all TABs
released = self.mother_drone.release_all_tabs()
self.tether_array.release_all()
# Update TAB states
for tab in self.tab_array.tabs.values():
release_vel = self.momentum_engine.compute_release_velocity(
self.mother_drone.momentum_state,
tab.momentum_state,
0, # No tension at release
ReleaseMode.INSTANT
)
tab.execute_release(release_vel)
if verbose:
print(f"Released {released} TABs")
print(f"Pre-release speed: {pre_speed:.1f} m/s")
# Calculate expected acceleration
burst_data = self.momentum_engine.compute_mother_acceleration_burst(
self.mother_drone.momentum_state,
[tab.momentum_state for tab in self.tab_array.tabs.values()],
self.mother_drone.current_thrust,
self.mother_drone.compute_parasitic_drag()
)
if verbose:
print(f"Expected acceleration multiplier: {burst_data['acceleration_multiplier']:.1f}x")
print(f"Drag reduction: {burst_data['drag_reduction_percent']:.1f}%")
print(f"Predicted speed in 1s: {burst_data['predicted_speed_1s']:.1f} m/s")
def demo_slingshot_intercept():
"""
Demonstration: Slingshot intercept of incoming threat.
Shows the "Archery" mechanics where a TAB is released
on an intercept trajectory.
"""
print("\n" + "=" * 60)
print("DEMO: SLINGSHOT INTERCEPT MANEUVER")
print("=" * 60 + "\n")
# Create simulation
sim = KAPSSimulation()
# Run for 5 seconds to stabilize formation
print("Phase 1: Formation stabilization...")
for _ in range(5000): # 5 seconds at 0.001s timestep
sim.step()
print(f"Formation stable at T={sim.time:.1f}s")
print(f"Mother drone speed: {sim.mother_drone.speed:.1f} m/s")
print(f"TABs attached: {sim.tab_array.count_attached()}")
# Inject threat
print("\nPhase 2: Threat injection...")
sim.inject_threat(
position=sim.mother_drone.position + np.array([300, 20, -10]),
velocity=np.array([-80, 0, 0]), # Heading toward drone
threat_type=ThreatType.DRONE_SUICIDE
)
# Run for 3 more seconds (AI should respond)
print("\nPhase 3: Defensive response...")
for _ in range(3000):
telemetry = sim.step()
print(f"\nFinal state at T={sim.time:.1f}s:")
print(f"TABs remaining: {sim.tab_array.count_attached()}")
print(f"Intercepts executed: {sim.defensive_ai.intercepts_executed}")
def demo_speed_burst():
"""
Demonstration: Speed burst escape maneuver.
Shows the "mechanical capacitor" effect when all TABs
are released simultaneously.
"""
print("\n" + "=" * 60)
print("DEMO: SPEED BURST MANEUVER")
print("=" * 60 + "\n")
sim = KAPSSimulation()
# Run for 2 seconds
print("Pre-burst flight...")
for _ in range(2000):
sim.step()
print(f"T={sim.time:.1f}s - Initiating speed burst")
print(f"Current speed: {sim.mother_drone.speed:.1f} m/s")
# Execute speed burst
sim.execute_speed_burst()
# Run for 2 more seconds to see acceleration
print("\nPost-burst acceleration...")
for _ in range(2000):
telemetry = sim.step()
if int(sim.time * 100) % 50 == 0:
print(f" T={sim.time:.1f}s - Speed: {telemetry['mother_drone']['speed']:.1f} m/s")
print(f"\nFinal speed: {sim.mother_drone.speed:.1f} m/s")
if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
if sys.argv[1] == "slingshot":
demo_slingshot_intercept()
elif sys.argv[1] == "burst":
demo_speed_burst()
else:
print("Unknown demo. Options: 'slingshot', 'burst'")
else:
# Run main simulation
config_path = Path(__file__).parent.parent / "config" / "simulation_params.yaml"
if config_path.exists():
sim = KAPSSimulation(str(config_path))
else:
sim = KAPSSimulation()
# Run for 10 seconds as demo
sim.run(duration=10.0)