2026-01-31 11:42:20 +08:00
|
|
|
|
"""
|
|
|
|
|
|
Moon Colony Construction - Combined Scenario Analysis
|
|
|
|
|
|
(Space Elevator + Traditional Rockets)
|
|
|
|
|
|
|
|
|
|
|
|
Problem: Deliver 100 million metric tons to Moon
|
|
|
|
|
|
- 3 Space Elevators: 179,000 metric tons/year each (priority)
|
|
|
|
|
|
- 10 Rocket launch sites: max 1 launch/day each, 125 tons/launch
|
|
|
|
|
|
- Optimize: Use elevators first (lower specific energy), then rockets
|
|
|
|
|
|
|
|
|
|
|
|
Key: As timeline extends:
|
|
|
|
|
|
1. More payload handled by elevators (lower energy)
|
|
|
|
|
|
2. Remaining rocket launches shift to lower-latitude sites
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
import matplotlib
|
|
|
|
|
|
matplotlib.use('Agg')
|
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
from matplotlib import rcParams
|
|
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
from typing import List, Tuple, Dict
|
|
|
|
|
|
import pandas as pd
|
|
|
|
|
|
|
|
|
|
|
|
# 设置字体
|
|
|
|
|
|
rcParams['font.sans-serif'] = ['Arial Unicode MS', 'DejaVu Sans', 'SimHei']
|
|
|
|
|
|
rcParams['axes.unicode_minus'] = False
|
|
|
|
|
|
|
|
|
|
|
|
# ============== 物理常数 ==============
|
|
|
|
|
|
G0 = 9.81 # m/s²
|
|
|
|
|
|
OMEGA_EARTH = 7.27e-5 # rad/s
|
|
|
|
|
|
R_EARTH = 6.371e6 # m
|
|
|
|
|
|
|
|
|
|
|
|
# ============== 任务参数 ==============
|
|
|
|
|
|
TOTAL_PAYLOAD = 100e6 # 100 million metric tons
|
|
|
|
|
|
|
|
|
|
|
|
# ============== 太空电梯参数 ==============
|
|
|
|
|
|
NUM_ELEVATORS = 3
|
|
|
|
|
|
ELEVATOR_CAPACITY_PER_YEAR = 179000 # metric tons per elevator per year
|
|
|
|
|
|
TOTAL_ELEVATOR_CAPACITY = NUM_ELEVATORS * ELEVATOR_CAPACITY_PER_YEAR # 537,000 tons/year
|
|
|
|
|
|
|
|
|
|
|
|
# 太空电梯能量参数 (从之前分析)
|
|
|
|
|
|
# 电梯提升能量: ~88.7 MJ/kg
|
|
|
|
|
|
# 顶端推进能量: ~68.5 MJ/kg
|
|
|
|
|
|
# 总计: ~157.2 MJ/kg = 157.2 TJ/1000 tons
|
|
|
|
|
|
ELEVATOR_SPECIFIC_ENERGY = 157.2e9 # J per metric ton (157.2 MJ/kg * 1000 kg)
|
|
|
|
|
|
|
|
|
|
|
|
# ============== 火箭参数 ==============
|
|
|
|
|
|
PAYLOAD_PER_LAUNCH = 125 # metric tons per launch
|
2026-02-02 14:32:39 +08:00
|
|
|
|
ISP = 363 # 比冲 (秒) - 液氧甲烷 (LOX/CH4, Raptor-class)
|
|
|
|
|
|
SPECIFIC_FUEL_ENERGY = 11.9e6 # J/kg
|
2026-01-31 11:42:20 +08:00
|
|
|
|
ALPHA = 0.10 # 结构系数
|
|
|
|
|
|
NUM_STAGES = 3
|
|
|
|
|
|
DELTA_V_BASE = 13300 # m/s (赤道发射到月球)
|
|
|
|
|
|
|
|
|
|
|
|
# 火箭比能量 (从之前分析: ~492.7 MJ/kg = 492.7 TJ/1000 tons for equator)
|
|
|
|
|
|
# 实际会因纬度变化
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============== 发射场定义 ==============
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class LaunchSite:
|
|
|
|
|
|
name: str
|
|
|
|
|
|
short_name: str
|
|
|
|
|
|
latitude: float
|
|
|
|
|
|
max_launches_per_day: int = 1
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
|
def abs_latitude(self) -> float:
|
|
|
|
|
|
return abs(self.latitude)
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
|
def rotation_velocity(self) -> float:
|
|
|
|
|
|
return OMEGA_EARTH * R_EARTH * np.cos(np.radians(self.abs_latitude))
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
|
def delta_v_loss(self) -> float:
|
|
|
|
|
|
v_equator = OMEGA_EARTH * R_EARTH
|
|
|
|
|
|
return v_equator - self.rotation_velocity
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
|
def total_delta_v(self) -> float:
|
|
|
|
|
|
return DELTA_V_BASE + self.delta_v_loss
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 10个发射场 (按纬度排序)
|
|
|
|
|
|
LAUNCH_SITES = sorted([
|
|
|
|
|
|
LaunchSite("Kourou (French Guiana)", "Kourou", 5.2),
|
|
|
|
|
|
LaunchSite("Satish Dhawan (India)", "SDSC", 13.7),
|
|
|
|
|
|
LaunchSite("Boca Chica (Texas)", "Texas", 26.0),
|
|
|
|
|
|
LaunchSite("Cape Canaveral (Florida)", "Florida", 28.5),
|
|
|
|
|
|
LaunchSite("Vandenberg (California)", "California", 34.7),
|
|
|
|
|
|
LaunchSite("Wallops (Virginia)", "Virginia", 37.8),
|
|
|
|
|
|
LaunchSite("Taiyuan (China)", "Taiyuan", 38.8),
|
|
|
|
|
|
LaunchSite("Mahia (New Zealand)", "Mahia", 39.3),
|
|
|
|
|
|
LaunchSite("Baikonur (Kazakhstan)", "Baikonur", 45.6),
|
|
|
|
|
|
LaunchSite("Kodiak (Alaska)", "Alaska", 57.4),
|
|
|
|
|
|
], key=lambda x: x.abs_latitude)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============== 核心计算函数 ==============
|
|
|
|
|
|
|
|
|
|
|
|
def fuel_ratio_multistage(delta_v: float) -> float:
|
|
|
|
|
|
"""多级火箭燃料/载荷比"""
|
|
|
|
|
|
ve = ISP * G0
|
|
|
|
|
|
delta_v_per_stage = delta_v / NUM_STAGES
|
|
|
|
|
|
R_stage = np.exp(delta_v_per_stage / ve)
|
|
|
|
|
|
|
|
|
|
|
|
denominator = 1 - ALPHA * (R_stage - 1)
|
|
|
|
|
|
if denominator <= 0:
|
|
|
|
|
|
return np.inf
|
|
|
|
|
|
|
|
|
|
|
|
k_stage = (R_stage - 1) / denominator
|
|
|
|
|
|
|
|
|
|
|
|
total_fuel_ratio = 0
|
|
|
|
|
|
remaining_ratio = 1.0
|
|
|
|
|
|
|
|
|
|
|
|
for _ in range(NUM_STAGES):
|
|
|
|
|
|
fuel_this_stage = remaining_ratio * k_stage
|
|
|
|
|
|
total_fuel_ratio += fuel_this_stage
|
|
|
|
|
|
remaining_ratio *= (1 + k_stage * (1 + ALPHA))
|
|
|
|
|
|
|
|
|
|
|
|
return total_fuel_ratio
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rocket_energy_per_ton(site: LaunchSite) -> float:
|
|
|
|
|
|
"""火箭发射每吨载荷的能量消耗 (J/ton)"""
|
|
|
|
|
|
k = fuel_ratio_multistage(site.total_delta_v)
|
|
|
|
|
|
fuel_per_ton = k * 1000 # kg fuel per metric ton payload
|
|
|
|
|
|
return fuel_per_ton * SPECIFIC_FUEL_ENERGY
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rocket_energy_per_launch(site: LaunchSite) -> float:
|
|
|
|
|
|
"""单次火箭发射的能量消耗 (J)"""
|
|
|
|
|
|
return rocket_energy_per_ton(site) * PAYLOAD_PER_LAUNCH
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============== 组合方案计算 ==============
|
|
|
|
|
|
|
|
|
|
|
|
def calculate_combined_scenario(completion_years: float) -> Dict:
|
|
|
|
|
|
"""
|
|
|
|
|
|
计算给定完成年限下的组合方案
|
|
|
|
|
|
|
|
|
|
|
|
策略:
|
|
|
|
|
|
1. 太空电梯满负荷运行
|
|
|
|
|
|
2. 剩余载荷由火箭发射,优先低纬度站点
|
|
|
|
|
|
|
|
|
|
|
|
返回:
|
|
|
|
|
|
方案详情字典
|
|
|
|
|
|
"""
|
|
|
|
|
|
# 太空电梯运输量
|
|
|
|
|
|
elevator_payload = min(TOTAL_ELEVATOR_CAPACITY * completion_years, TOTAL_PAYLOAD)
|
|
|
|
|
|
elevator_energy = elevator_payload * ELEVATOR_SPECIFIC_ENERGY
|
|
|
|
|
|
|
|
|
|
|
|
# 剩余需要火箭运输的载荷
|
|
|
|
|
|
remaining_payload = TOTAL_PAYLOAD - elevator_payload
|
|
|
|
|
|
|
|
|
|
|
|
if remaining_payload <= 0:
|
|
|
|
|
|
# 完全由电梯完成
|
|
|
|
|
|
return {
|
|
|
|
|
|
'completion_years': completion_years,
|
|
|
|
|
|
'elevator_payload': elevator_payload,
|
|
|
|
|
|
'elevator_energy_PJ': elevator_energy / 1e15,
|
|
|
|
|
|
'rocket_payload': 0,
|
|
|
|
|
|
'rocket_energy_PJ': 0,
|
|
|
|
|
|
'total_energy_PJ': elevator_energy / 1e15,
|
|
|
|
|
|
'rocket_launches': 0,
|
|
|
|
|
|
'sites_used': 0,
|
|
|
|
|
|
'elevator_fraction': 1.0,
|
|
|
|
|
|
'rocket_distribution': [],
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 需要火箭发射
|
|
|
|
|
|
rocket_launches_needed = int(np.ceil(remaining_payload / PAYLOAD_PER_LAUNCH))
|
|
|
|
|
|
|
|
|
|
|
|
# 按纬度优先分配火箭发射
|
|
|
|
|
|
days_available = completion_years * 365
|
|
|
|
|
|
max_launches_per_site = int(days_available)
|
|
|
|
|
|
|
|
|
|
|
|
rocket_distribution = []
|
|
|
|
|
|
remaining_launches = rocket_launches_needed
|
|
|
|
|
|
rocket_energy = 0
|
|
|
|
|
|
sites_used = 0
|
|
|
|
|
|
|
|
|
|
|
|
for site in LAUNCH_SITES:
|
|
|
|
|
|
if remaining_launches <= 0:
|
|
|
|
|
|
rocket_distribution.append((site, 0))
|
|
|
|
|
|
else:
|
|
|
|
|
|
allocated = min(remaining_launches, max_launches_per_site)
|
|
|
|
|
|
rocket_distribution.append((site, allocated))
|
|
|
|
|
|
rocket_energy += rocket_energy_per_launch(site) * allocated
|
|
|
|
|
|
remaining_launches -= allocated
|
|
|
|
|
|
if allocated > 0:
|
|
|
|
|
|
sites_used += 1
|
|
|
|
|
|
|
|
|
|
|
|
# 检查是否能在规定时间内完成
|
|
|
|
|
|
total_rocket_capacity = len(LAUNCH_SITES) * max_launches_per_site * PAYLOAD_PER_LAUNCH
|
|
|
|
|
|
if remaining_payload > total_rocket_capacity:
|
|
|
|
|
|
# 无法完成
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
rocket_payload = rocket_launches_needed * PAYLOAD_PER_LAUNCH
|
|
|
|
|
|
total_energy = elevator_energy + rocket_energy
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
'completion_years': completion_years,
|
|
|
|
|
|
'elevator_payload': elevator_payload,
|
|
|
|
|
|
'elevator_energy_PJ': elevator_energy / 1e15,
|
|
|
|
|
|
'rocket_payload': rocket_payload,
|
|
|
|
|
|
'rocket_energy_PJ': rocket_energy / 1e15,
|
|
|
|
|
|
'total_energy_PJ': total_energy / 1e15,
|
|
|
|
|
|
'rocket_launches': rocket_launches_needed,
|
|
|
|
|
|
'sites_used': sites_used,
|
|
|
|
|
|
'elevator_fraction': elevator_payload / TOTAL_PAYLOAD,
|
|
|
|
|
|
'rocket_distribution': rocket_distribution,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def analyze_combined_timeline() -> pd.DataFrame:
|
|
|
|
|
|
"""
|
|
|
|
|
|
分析不同完成年限下的组合方案
|
|
|
|
|
|
"""
|
|
|
|
|
|
# 计算关键时间点
|
|
|
|
|
|
# 1. 仅电梯完成所需时间
|
|
|
|
|
|
elevator_only_years = TOTAL_PAYLOAD / TOTAL_ELEVATOR_CAPACITY
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 最短时间(电梯+全部火箭站点满负荷)
|
|
|
|
|
|
rocket_capacity_per_year = len(LAUNCH_SITES) * 365 * PAYLOAD_PER_LAUNCH
|
|
|
|
|
|
total_capacity_per_year = TOTAL_ELEVATOR_CAPACITY + rocket_capacity_per_year
|
|
|
|
|
|
min_years = TOTAL_PAYLOAD / total_capacity_per_year
|
|
|
|
|
|
|
|
|
|
|
|
print(f"Elevator-only completion: {elevator_only_years:.1f} years")
|
|
|
|
|
|
print(f"Minimum completion (all systems): {min_years:.1f} years")
|
|
|
|
|
|
print(f"Elevator capacity: {TOTAL_ELEVATOR_CAPACITY:,} tons/year")
|
|
|
|
|
|
print(f"Rocket capacity: {rocket_capacity_per_year:,} tons/year")
|
|
|
|
|
|
|
|
|
|
|
|
# 分析范围
|
|
|
|
|
|
years_range = np.linspace(min_years, elevator_only_years * 1.1, 200)
|
|
|
|
|
|
|
|
|
|
|
|
results = []
|
|
|
|
|
|
for years in years_range:
|
|
|
|
|
|
scenario = calculate_combined_scenario(years)
|
|
|
|
|
|
if scenario is not None:
|
|
|
|
|
|
results.append(scenario)
|
|
|
|
|
|
|
|
|
|
|
|
return pd.DataFrame(results)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============== 可视化 ==============
|
|
|
|
|
|
|
|
|
|
|
|
def plot_combined_analysis(
|
|
|
|
|
|
save_path: str = '/Volumes/Files/code/mm/20260130_b/combined_scenario_analysis.png'
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
绘制组合方案分析图
|
|
|
|
|
|
"""
|
|
|
|
|
|
df = analyze_combined_timeline()
|
|
|
|
|
|
|
|
|
|
|
|
# 关键时间点
|
|
|
|
|
|
elevator_only_years = TOTAL_PAYLOAD / TOTAL_ELEVATOR_CAPACITY
|
|
|
|
|
|
rocket_capacity_per_year = len(LAUNCH_SITES) * 365 * PAYLOAD_PER_LAUNCH
|
|
|
|
|
|
total_capacity_per_year = TOTAL_ELEVATOR_CAPACITY + rocket_capacity_per_year
|
|
|
|
|
|
min_years = TOTAL_PAYLOAD / total_capacity_per_year
|
|
|
|
|
|
|
|
|
|
|
|
fig, axes = plt.subplots(2, 2, figsize=(16, 14))
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 图1: 完成年份 vs 总能量消耗 ==========
|
|
|
|
|
|
ax1 = axes[0, 0]
|
|
|
|
|
|
|
|
|
|
|
|
ax1.plot(df['completion_years'], df['total_energy_PJ'], 'b-', linewidth=2.5,
|
|
|
|
|
|
label='Total Energy')
|
|
|
|
|
|
ax1.plot(df['completion_years'], df['elevator_energy_PJ'], 'g--', linewidth=2,
|
|
|
|
|
|
label='Elevator Energy')
|
|
|
|
|
|
ax1.plot(df['completion_years'], df['rocket_energy_PJ'], 'r--', linewidth=2,
|
|
|
|
|
|
label='Rocket Energy')
|
|
|
|
|
|
|
|
|
|
|
|
# 标记关键点
|
|
|
|
|
|
ax1.axvline(x=min_years, color='orange', linestyle=':', linewidth=1.5,
|
|
|
|
|
|
label=f'Min time: {min_years:.0f} years')
|
|
|
|
|
|
ax1.axvline(x=elevator_only_years, color='purple', linestyle=':', linewidth=1.5,
|
|
|
|
|
|
label=f'Elevator-only: {elevator_only_years:.0f} years')
|
|
|
|
|
|
|
|
|
|
|
|
ax1.set_xlabel('Completion Time (years)', fontsize=12)
|
|
|
|
|
|
ax1.set_ylabel('Energy Consumption (PJ)', fontsize=12)
|
|
|
|
|
|
ax1.set_title('Combined Scenario: Completion Time vs Energy\n'
|
|
|
|
|
|
'(Space Elevator + Rockets)', fontsize=14)
|
|
|
|
|
|
ax1.legend(loc='upper right')
|
|
|
|
|
|
ax1.grid(True, alpha=0.3)
|
|
|
|
|
|
ax1.set_xlim(min_years * 0.95, elevator_only_years * 1.05)
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 图2: 电梯 vs 火箭载荷比例 ==========
|
|
|
|
|
|
ax2 = axes[0, 1]
|
|
|
|
|
|
|
|
|
|
|
|
ax2.fill_between(df['completion_years'], 0, df['elevator_fraction'] * 100,
|
|
|
|
|
|
alpha=0.7, color='green', label='Space Elevator')
|
|
|
|
|
|
ax2.fill_between(df['completion_years'], df['elevator_fraction'] * 100, 100,
|
|
|
|
|
|
alpha=0.7, color='red', label='Rockets')
|
|
|
|
|
|
|
|
|
|
|
|
ax2.axvline(x=min_years, color='orange', linestyle=':', linewidth=1.5)
|
|
|
|
|
|
ax2.axvline(x=elevator_only_years, color='purple', linestyle=':', linewidth=1.5)
|
|
|
|
|
|
|
|
|
|
|
|
ax2.set_xlabel('Completion Time (years)', fontsize=12)
|
|
|
|
|
|
ax2.set_ylabel('Payload Share (%)', fontsize=12)
|
|
|
|
|
|
ax2.set_title('Payload Distribution: Elevator vs Rockets', fontsize=14)
|
|
|
|
|
|
ax2.legend(loc='center right')
|
|
|
|
|
|
ax2.set_ylim(0, 100)
|
|
|
|
|
|
ax2.set_xlim(min_years * 0.95, elevator_only_years * 1.05)
|
|
|
|
|
|
ax2.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 图3: 使用的火箭发射场数量 ==========
|
|
|
|
|
|
ax3 = axes[1, 0]
|
|
|
|
|
|
|
|
|
|
|
|
ax3.plot(df['completion_years'], df['sites_used'], 'r-', linewidth=2)
|
|
|
|
|
|
ax3.fill_between(df['completion_years'], 0, df['sites_used'], alpha=0.3, color='red')
|
|
|
|
|
|
|
|
|
|
|
|
ax3.axvline(x=min_years, color='orange', linestyle=':', linewidth=1.5)
|
|
|
|
|
|
ax3.axvline(x=elevator_only_years, color='purple', linestyle=':', linewidth=1.5)
|
|
|
|
|
|
|
|
|
|
|
|
# 标注发射场
|
|
|
|
|
|
for i, site in enumerate(LAUNCH_SITES):
|
|
|
|
|
|
ax3.axhline(y=i+1, color='gray', linestyle=':', alpha=0.2)
|
|
|
|
|
|
ax3.text(df['completion_years'].max() * 0.99, i+1 + 0.15,
|
|
|
|
|
|
f'{site.short_name} ({site.abs_latitude:.0f}°)',
|
|
|
|
|
|
fontsize=8, ha='right', va='bottom')
|
|
|
|
|
|
|
|
|
|
|
|
ax3.set_xlabel('Completion Time (years)', fontsize=12)
|
|
|
|
|
|
ax3.set_ylabel('Number of Rocket Sites Used', fontsize=12)
|
|
|
|
|
|
ax3.set_title('Rocket Launch Sites Required\n(Longer timeline → fewer high-lat sites)', fontsize=14)
|
|
|
|
|
|
ax3.set_ylim(0, 11)
|
|
|
|
|
|
ax3.set_xlim(min_years * 0.95, elevator_only_years * 1.05)
|
|
|
|
|
|
ax3.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 图4: 能量效率对比 ==========
|
|
|
|
|
|
ax4 = axes[1, 1]
|
|
|
|
|
|
|
|
|
|
|
|
# 计算平均比能量
|
|
|
|
|
|
avg_specific_energy = df['total_energy_PJ'] * 1e15 / TOTAL_PAYLOAD / 1e9 # GJ/ton
|
|
|
|
|
|
|
|
|
|
|
|
ax4.plot(df['completion_years'], avg_specific_energy, 'b-', linewidth=2)
|
|
|
|
|
|
|
|
|
|
|
|
# 参考线
|
|
|
|
|
|
elevator_specific = ELEVATOR_SPECIFIC_ENERGY / 1e9 # GJ/ton
|
|
|
|
|
|
ax4.axhline(y=elevator_specific, color='green', linestyle='--',
|
|
|
|
|
|
label=f'Elevator only: {elevator_specific:.1f} GJ/ton')
|
|
|
|
|
|
|
|
|
|
|
|
# 平均火箭比能量 (赤道)
|
|
|
|
|
|
rocket_specific_equator = rocket_energy_per_ton(LAUNCH_SITES[0]) / 1e9
|
|
|
|
|
|
ax4.axhline(y=rocket_specific_equator, color='red', linestyle='--',
|
|
|
|
|
|
label=f'Rocket (equator): {rocket_specific_equator:.1f} GJ/ton')
|
|
|
|
|
|
|
|
|
|
|
|
ax4.axvline(x=min_years, color='orange', linestyle=':', linewidth=1.5)
|
|
|
|
|
|
ax4.axvline(x=elevator_only_years, color='purple', linestyle=':', linewidth=1.5)
|
|
|
|
|
|
|
|
|
|
|
|
ax4.set_xlabel('Completion Time (years)', fontsize=12)
|
|
|
|
|
|
ax4.set_ylabel('Average Specific Energy (GJ/ton)', fontsize=12)
|
|
|
|
|
|
ax4.set_title('Energy Efficiency vs Timeline\n(Longer time → more elevator → lower energy)', fontsize=14)
|
|
|
|
|
|
ax4.legend()
|
|
|
|
|
|
ax4.set_xlim(min_years * 0.95, elevator_only_years * 1.05)
|
|
|
|
|
|
ax4.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
|
|
plt.suptitle(f'Combined Scenario: 100M tons to Moon\n'
|
|
|
|
|
|
f'3 Elevators ({TOTAL_ELEVATOR_CAPACITY:,} t/yr) + 10 Rocket Sites',
|
|
|
|
|
|
fontsize=15, y=1.02)
|
|
|
|
|
|
|
|
|
|
|
|
plt.tight_layout()
|
|
|
|
|
|
plt.savefig(save_path, dpi=150, bbox_inches='tight')
|
|
|
|
|
|
print(f"\n组合方案分析图已保存至: {save_path}")
|
|
|
|
|
|
|
|
|
|
|
|
return df
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def plot_scenario_comparison(
|
|
|
|
|
|
save_path: str = '/Volumes/Files/code/mm/20260130_b/scenario_comparison.png'
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
对比三种方案:仅电梯、仅火箭、组合
|
|
|
|
|
|
"""
|
|
|
|
|
|
# 关键时间点分析
|
|
|
|
|
|
elevator_only_years = TOTAL_PAYLOAD / TOTAL_ELEVATOR_CAPACITY
|
|
|
|
|
|
rocket_capacity_per_year = len(LAUNCH_SITES) * 365 * PAYLOAD_PER_LAUNCH
|
|
|
|
|
|
rocket_only_min_years = TOTAL_PAYLOAD / rocket_capacity_per_year
|
|
|
|
|
|
combined_min_years = TOTAL_PAYLOAD / (TOTAL_ELEVATOR_CAPACITY + rocket_capacity_per_year)
|
|
|
|
|
|
|
|
|
|
|
|
# 各方案能量
|
|
|
|
|
|
elevator_only_energy = TOTAL_PAYLOAD * ELEVATOR_SPECIFIC_ENERGY / 1e15 # PJ
|
|
|
|
|
|
|
|
|
|
|
|
# 火箭方案 (平均所有站点)
|
|
|
|
|
|
avg_rocket_energy_per_ton = sum(rocket_energy_per_ton(s) for s in LAUNCH_SITES) / len(LAUNCH_SITES)
|
|
|
|
|
|
rocket_only_energy = TOTAL_PAYLOAD * avg_rocket_energy_per_ton / 1e15 # PJ
|
|
|
|
|
|
|
|
|
|
|
|
# 组合方案 (最短时间 - 加余量)
|
|
|
|
|
|
combined_scenario = calculate_combined_scenario(combined_min_years * 1.01)
|
|
|
|
|
|
combined_min_energy = combined_scenario['total_energy_PJ'] if combined_scenario else elevator_only_energy
|
|
|
|
|
|
|
|
|
|
|
|
# 组合方案 (仅电梯时间)
|
|
|
|
|
|
combined_extended = calculate_combined_scenario(elevator_only_years * 0.95)
|
|
|
|
|
|
combined_extended_energy = combined_extended['total_energy_PJ'] if combined_extended else elevator_only_energy
|
|
|
|
|
|
|
|
|
|
|
|
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 图1: 完成时间对比 ==========
|
|
|
|
|
|
ax1 = axes[0]
|
|
|
|
|
|
|
|
|
|
|
|
scenarios = ['Elevator\nOnly', 'Rocket\nOnly', 'Combined\n(Min Time)', 'Combined\n(Extended)']
|
|
|
|
|
|
times = [elevator_only_years, rocket_only_min_years, combined_min_years, elevator_only_years * 0.99]
|
|
|
|
|
|
colors = ['green', 'red', 'blue', 'purple']
|
|
|
|
|
|
|
|
|
|
|
|
bars = ax1.bar(scenarios, times, color=colors, alpha=0.7)
|
|
|
|
|
|
|
|
|
|
|
|
ax1.set_ylabel('Completion Time (years)', fontsize=12)
|
|
|
|
|
|
ax1.set_title('Completion Time Comparison', fontsize=14)
|
|
|
|
|
|
ax1.grid(True, alpha=0.3, axis='y')
|
|
|
|
|
|
|
|
|
|
|
|
for bar, t in zip(bars, times):
|
|
|
|
|
|
ax1.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 2,
|
|
|
|
|
|
f'{t:.0f}y', ha='center', fontsize=11, fontweight='bold')
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 图2: 能量消耗对比 ==========
|
|
|
|
|
|
ax2 = axes[1]
|
|
|
|
|
|
|
|
|
|
|
|
energies = [elevator_only_energy, rocket_only_energy, combined_min_energy, combined_extended_energy]
|
|
|
|
|
|
|
|
|
|
|
|
bars = ax2.bar(scenarios, energies, color=colors, alpha=0.7)
|
|
|
|
|
|
|
|
|
|
|
|
ax2.set_ylabel('Total Energy (PJ)', fontsize=12)
|
|
|
|
|
|
ax2.set_title('Energy Consumption Comparison', fontsize=14)
|
|
|
|
|
|
ax2.grid(True, alpha=0.3, axis='y')
|
|
|
|
|
|
|
|
|
|
|
|
for bar, e in zip(bars, energies):
|
|
|
|
|
|
ax2.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 500,
|
|
|
|
|
|
f'{e:.0f}', ha='center', fontsize=11, fontweight='bold')
|
|
|
|
|
|
|
|
|
|
|
|
plt.tight_layout()
|
|
|
|
|
|
plt.savefig(save_path, dpi=150, bbox_inches='tight')
|
|
|
|
|
|
print(f"方案对比图已保存至: {save_path}")
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
'elevator_only': {'years': elevator_only_years, 'energy_PJ': elevator_only_energy},
|
|
|
|
|
|
'rocket_only': {'years': rocket_only_min_years, 'energy_PJ': rocket_only_energy},
|
|
|
|
|
|
'combined_min': {'years': combined_min_years, 'energy_PJ': combined_min_energy},
|
|
|
|
|
|
'combined_extended': {'years': elevator_only_years * 0.99, 'energy_PJ': combined_extended_energy},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def print_summary(df: pd.DataFrame):
|
|
|
|
|
|
"""打印分析摘要"""
|
|
|
|
|
|
elevator_only_years = TOTAL_PAYLOAD / TOTAL_ELEVATOR_CAPACITY
|
|
|
|
|
|
rocket_capacity_per_year = len(LAUNCH_SITES) * 365 * PAYLOAD_PER_LAUNCH
|
|
|
|
|
|
combined_min_years = TOTAL_PAYLOAD / (TOTAL_ELEVATOR_CAPACITY + rocket_capacity_per_year)
|
|
|
|
|
|
|
|
|
|
|
|
print("\n" + "=" * 90)
|
|
|
|
|
|
print("COMBINED SCENARIO (SPACE ELEVATOR + ROCKETS) ANALYSIS")
|
|
|
|
|
|
print("=" * 90)
|
|
|
|
|
|
|
|
|
|
|
|
print(f"\nSystem Capacities:")
|
|
|
|
|
|
print(f" - 3 Space Elevators: {TOTAL_ELEVATOR_CAPACITY:,} tons/year")
|
|
|
|
|
|
print(f" - 10 Rocket Sites: {rocket_capacity_per_year:,} tons/year (@ 1 launch/day each)")
|
|
|
|
|
|
print(f" - Combined: {TOTAL_ELEVATOR_CAPACITY + rocket_capacity_per_year:,} tons/year")
|
|
|
|
|
|
|
|
|
|
|
|
print(f"\nSpecific Energy:")
|
|
|
|
|
|
print(f" - Elevator: {ELEVATOR_SPECIFIC_ENERGY/1e9:.1f} GJ/ton ({ELEVATOR_SPECIFIC_ENERGY/1e9/rocket_energy_per_ton(LAUNCH_SITES[0])*1e9*100:.1f}% of rocket)")
|
|
|
|
|
|
print(f" - Rocket (Kourou): {rocket_energy_per_ton(LAUNCH_SITES[0])/1e9:.1f} GJ/ton")
|
|
|
|
|
|
print(f" - Rocket (Alaska): {rocket_energy_per_ton(LAUNCH_SITES[-1])/1e9:.1f} GJ/ton")
|
|
|
|
|
|
|
|
|
|
|
|
print(f"\nKey Scenarios:")
|
|
|
|
|
|
|
|
|
|
|
|
# 最短时间 (加一点余量确保可以完成)
|
|
|
|
|
|
min_scenario = calculate_combined_scenario(combined_min_years * 1.01)
|
|
|
|
|
|
print(f"\n 1. Minimum Time (~{combined_min_years:.0f} years):")
|
|
|
|
|
|
print(f" - Elevator payload: {min_scenario['elevator_payload']/1e6:.1f}M tons ({min_scenario['elevator_fraction']*100:.1f}%)")
|
|
|
|
|
|
print(f" - Rocket payload: {min_scenario['rocket_payload']/1e6:.1f}M tons")
|
|
|
|
|
|
print(f" - Rocket launches: {min_scenario['rocket_launches']:,}")
|
|
|
|
|
|
print(f" - Sites used: {min_scenario['sites_used']}")
|
|
|
|
|
|
print(f" - Total energy: {min_scenario['total_energy_PJ']:.0f} PJ")
|
|
|
|
|
|
|
|
|
|
|
|
# 中等时间
|
|
|
|
|
|
mid_years = (combined_min_years + elevator_only_years) / 2
|
|
|
|
|
|
mid_scenario = calculate_combined_scenario(mid_years)
|
|
|
|
|
|
print(f"\n 2. Medium Timeline ({mid_years:.0f} years):")
|
|
|
|
|
|
print(f" - Elevator payload: {mid_scenario['elevator_payload']/1e6:.1f}M tons ({mid_scenario['elevator_fraction']*100:.1f}%)")
|
|
|
|
|
|
print(f" - Rocket payload: {mid_scenario['rocket_payload']/1e6:.1f}M tons")
|
|
|
|
|
|
print(f" - Rocket launches: {mid_scenario['rocket_launches']:,}")
|
|
|
|
|
|
print(f" - Sites used: {mid_scenario['sites_used']}")
|
|
|
|
|
|
print(f" - Total energy: {mid_scenario['total_energy_PJ']:.0f} PJ")
|
|
|
|
|
|
|
|
|
|
|
|
# 接近仅电梯
|
|
|
|
|
|
extended_years = elevator_only_years * 0.95
|
|
|
|
|
|
extended_scenario = calculate_combined_scenario(extended_years)
|
|
|
|
|
|
print(f"\n 3. Extended Timeline ({extended_years:.0f} years):")
|
|
|
|
|
|
print(f" - Elevator payload: {extended_scenario['elevator_payload']/1e6:.1f}M tons ({extended_scenario['elevator_fraction']*100:.1f}%)")
|
|
|
|
|
|
print(f" - Rocket payload: {extended_scenario['rocket_payload']/1e6:.1f}M tons")
|
|
|
|
|
|
print(f" - Rocket launches: {extended_scenario['rocket_launches']:,}")
|
|
|
|
|
|
print(f" - Sites used: {extended_scenario['sites_used']}")
|
|
|
|
|
|
print(f" - Total energy: {extended_scenario['total_energy_PJ']:.0f} PJ")
|
|
|
|
|
|
|
|
|
|
|
|
# 仅电梯
|
|
|
|
|
|
print(f"\n 4. Elevator Only ({elevator_only_years:.0f} years):")
|
|
|
|
|
|
elevator_energy = TOTAL_PAYLOAD * ELEVATOR_SPECIFIC_ENERGY / 1e15
|
|
|
|
|
|
print(f" - Elevator payload: 100M tons (100%)")
|
|
|
|
|
|
print(f" - Rocket launches: 0")
|
|
|
|
|
|
print(f" - Total energy: {elevator_energy:.0f} PJ")
|
|
|
|
|
|
|
|
|
|
|
|
print("\n" + "=" * 90)
|
|
|
|
|
|
print("ENERGY SAVINGS ANALYSIS")
|
|
|
|
|
|
print("=" * 90)
|
|
|
|
|
|
|
|
|
|
|
|
rocket_only_energy = TOTAL_PAYLOAD * sum(rocket_energy_per_ton(s) for s in LAUNCH_SITES) / len(LAUNCH_SITES) / 1e15
|
|
|
|
|
|
|
|
|
|
|
|
print(f"\n Baseline (Rocket Only): {rocket_only_energy:.0f} PJ")
|
|
|
|
|
|
print(f" Combined (Min Time): {min_scenario['total_energy_PJ']:.0f} PJ (saves {(1-min_scenario['total_energy_PJ']/rocket_only_energy)*100:.0f}%)")
|
|
|
|
|
|
print(f" Combined (Extended): {extended_scenario['total_energy_PJ']:.0f} PJ (saves {(1-extended_scenario['total_energy_PJ']/rocket_only_energy)*100:.0f}%)")
|
|
|
|
|
|
print(f" Elevator Only: {elevator_energy:.0f} PJ (saves {(1-elevator_energy/rocket_only_energy)*100:.0f}%)")
|
|
|
|
|
|
|
|
|
|
|
|
print("=" * 90)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def plot_three_scenarios_comparison(
|
|
|
|
|
|
year_min: float = 100,
|
|
|
|
|
|
year_max: float = 300,
|
|
|
|
|
|
save_path: str = '/Volumes/Files/code/mm/20260130_b/three_scenarios_comparison.png'
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
绘制三种方案在指定年份范围内的能量消耗对比折线图
|
|
|
|
|
|
|
|
|
|
|
|
方案:
|
|
|
|
|
|
1. 纯火箭方案 (Rocket Only)
|
|
|
|
|
|
2. 纯电梯方案 (Elevator Only)
|
|
|
|
|
|
3. 混合方案 (Combined)
|
|
|
|
|
|
"""
|
|
|
|
|
|
years = np.linspace(year_min, year_max, 200)
|
|
|
|
|
|
|
|
|
|
|
|
# 计算各方案的能量
|
|
|
|
|
|
rocket_energy = []
|
|
|
|
|
|
elevator_energy = []
|
|
|
|
|
|
combined_energy = []
|
|
|
|
|
|
|
|
|
|
|
|
# 关键时间点
|
|
|
|
|
|
elevator_only_min_years = TOTAL_PAYLOAD / TOTAL_ELEVATOR_CAPACITY # ~186 years
|
|
|
|
|
|
rocket_only_min_years = TOTAL_PAYLOAD / (len(LAUNCH_SITES) * 365 * PAYLOAD_PER_LAUNCH) # ~219 years
|
|
|
|
|
|
combined_min_years = TOTAL_PAYLOAD / (TOTAL_ELEVATOR_CAPACITY + len(LAUNCH_SITES) * 365 * PAYLOAD_PER_LAUNCH) # ~101 years
|
|
|
|
|
|
|
|
|
|
|
|
for y in years:
|
|
|
|
|
|
# ===== 纯火箭方案 =====
|
|
|
|
|
|
if y >= rocket_only_min_years:
|
|
|
|
|
|
# 可以完成,优先使用低纬度站点
|
|
|
|
|
|
total_launches = int(TOTAL_PAYLOAD / PAYLOAD_PER_LAUNCH)
|
|
|
|
|
|
days_available = y * 365
|
|
|
|
|
|
max_per_site = int(days_available)
|
|
|
|
|
|
|
|
|
|
|
|
energy = 0
|
|
|
|
|
|
remaining = total_launches
|
|
|
|
|
|
for site in LAUNCH_SITES:
|
|
|
|
|
|
if remaining <= 0:
|
|
|
|
|
|
break
|
|
|
|
|
|
allocated = min(remaining, max_per_site)
|
|
|
|
|
|
energy += rocket_energy_per_launch(site) * allocated
|
|
|
|
|
|
remaining -= allocated
|
|
|
|
|
|
|
|
|
|
|
|
rocket_energy.append(energy / 1e15)
|
|
|
|
|
|
else:
|
|
|
|
|
|
# 无法完成
|
|
|
|
|
|
rocket_energy.append(np.nan)
|
|
|
|
|
|
|
|
|
|
|
|
# ===== 纯电梯方案 =====
|
|
|
|
|
|
if y >= elevator_only_min_years:
|
|
|
|
|
|
# 可以完成
|
|
|
|
|
|
energy = TOTAL_PAYLOAD * ELEVATOR_SPECIFIC_ENERGY
|
|
|
|
|
|
elevator_energy.append(energy / 1e15)
|
|
|
|
|
|
else:
|
|
|
|
|
|
# 无法完成
|
|
|
|
|
|
elevator_energy.append(np.nan)
|
|
|
|
|
|
|
|
|
|
|
|
# ===== 混合方案 =====
|
|
|
|
|
|
if y >= combined_min_years:
|
|
|
|
|
|
scenario = calculate_combined_scenario(y)
|
|
|
|
|
|
if scenario:
|
|
|
|
|
|
combined_energy.append(scenario['total_energy_PJ'])
|
|
|
|
|
|
else:
|
|
|
|
|
|
combined_energy.append(np.nan)
|
|
|
|
|
|
else:
|
|
|
|
|
|
combined_energy.append(np.nan)
|
|
|
|
|
|
|
|
|
|
|
|
# 创建图表
|
|
|
|
|
|
fig, ax = plt.subplots(figsize=(14, 8))
|
|
|
|
|
|
|
|
|
|
|
|
# 绘制三条折线
|
|
|
|
|
|
ax.plot(years, rocket_energy, 'r-', linewidth=2.5, label='Rocket Only', marker='', markersize=4)
|
|
|
|
|
|
ax.plot(years, elevator_energy, 'g-', linewidth=2.5, label='Elevator Only', marker='', markersize=4)
|
|
|
|
|
|
ax.plot(years, combined_energy, 'b-', linewidth=2.5, label='Combined (Elevator + Rocket)', marker='', markersize=4)
|
|
|
|
|
|
|
|
|
|
|
|
# 标记关键时间点
|
|
|
|
|
|
ax.axvline(x=combined_min_years, color='blue', linestyle=':', alpha=0.7, linewidth=1.5)
|
|
|
|
|
|
ax.axvline(x=elevator_only_min_years, color='green', linestyle=':', alpha=0.7, linewidth=1.5)
|
|
|
|
|
|
ax.axvline(x=rocket_only_min_years, color='red', linestyle=':', alpha=0.7, linewidth=1.5)
|
|
|
|
|
|
|
|
|
|
|
|
# 添加标注
|
|
|
|
|
|
y_pos = ax.get_ylim()[1] * 0.95
|
|
|
|
|
|
ax.annotate(f'Combined\nMin: {combined_min_years:.0f}y',
|
|
|
|
|
|
xy=(combined_min_years, y_pos), fontsize=9, ha='center',
|
|
|
|
|
|
bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.8))
|
|
|
|
|
|
ax.annotate(f'Elevator\nMin: {elevator_only_min_years:.0f}y',
|
|
|
|
|
|
xy=(elevator_only_min_years, y_pos * 0.85), fontsize=9, ha='center',
|
|
|
|
|
|
bbox=dict(boxstyle='round', facecolor='lightgreen', alpha=0.8))
|
|
|
|
|
|
ax.annotate(f'Rocket\nMin: {rocket_only_min_years:.0f}y',
|
|
|
|
|
|
xy=(rocket_only_min_years, y_pos * 0.75), fontsize=9, ha='center',
|
|
|
|
|
|
bbox=dict(boxstyle='round', facecolor='lightsalmon', alpha=0.8))
|
|
|
|
|
|
|
|
|
|
|
|
# 填充区域表示节能效果
|
|
|
|
|
|
# Combined比Rocket节省的能量
|
|
|
|
|
|
rocket_arr = np.array(rocket_energy)
|
|
|
|
|
|
combined_arr = np.array(combined_energy)
|
|
|
|
|
|
valid_mask = ~np.isnan(rocket_arr) & ~np.isnan(combined_arr)
|
|
|
|
|
|
ax.fill_between(years[valid_mask], combined_arr[valid_mask], rocket_arr[valid_mask],
|
|
|
|
|
|
alpha=0.2, color='purple', label='Energy saved by Combined vs Rocket')
|
|
|
|
|
|
|
|
|
|
|
|
ax.set_xlabel('Completion Time (years)', fontsize=13)
|
|
|
|
|
|
ax.set_ylabel('Total Energy Consumption (PJ)', fontsize=13)
|
|
|
|
|
|
ax.set_title('Moon Colony Construction: Energy vs Completion Time\n'
|
|
|
|
|
|
'(100 Million Metric Tons Payload Comparison)', fontsize=15)
|
|
|
|
|
|
ax.legend(loc='upper right', fontsize=11)
|
|
|
|
|
|
ax.grid(True, alpha=0.3)
|
|
|
|
|
|
ax.set_xlim(year_min, year_max)
|
|
|
|
|
|
|
|
|
|
|
|
# 添加数据表格
|
|
|
|
|
|
# 选择几个关键年份的数据
|
|
|
|
|
|
key_years = [110, 150, 186, 220, 250]
|
|
|
|
|
|
table_data = []
|
|
|
|
|
|
for ky in key_years:
|
|
|
|
|
|
idx = np.argmin(np.abs(years - ky))
|
|
|
|
|
|
table_data.append([
|
|
|
|
|
|
f'{ky}',
|
|
|
|
|
|
f'{combined_energy[idx]:.0f}' if not np.isnan(combined_energy[idx]) else 'N/A',
|
|
|
|
|
|
f'{elevator_energy[idx]:.0f}' if not np.isnan(elevator_energy[idx]) else 'N/A',
|
|
|
|
|
|
f'{rocket_energy[idx]:.0f}' if not np.isnan(rocket_energy[idx]) else 'N/A',
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
# 在图表下方添加表格
|
|
|
|
|
|
table = ax.table(
|
|
|
|
|
|
cellText=table_data,
|
|
|
|
|
|
colLabels=['Year', 'Combined (PJ)', 'Elevator (PJ)', 'Rocket (PJ)'],
|
|
|
|
|
|
loc='bottom',
|
|
|
|
|
|
bbox=[0.15, -0.25, 0.7, 0.18],
|
|
|
|
|
|
cellLoc='center'
|
|
|
|
|
|
)
|
|
|
|
|
|
table.auto_set_font_size(False)
|
|
|
|
|
|
table.set_fontsize(10)
|
|
|
|
|
|
table.scale(1, 1.5)
|
|
|
|
|
|
|
|
|
|
|
|
# 调整布局给表格留空间
|
|
|
|
|
|
plt.subplots_adjust(bottom=0.25)
|
|
|
|
|
|
|
|
|
|
|
|
plt.savefig(save_path, dpi=150, bbox_inches='tight')
|
|
|
|
|
|
print(f"\n三方案对比图已保存至: {save_path}")
|
|
|
|
|
|
|
|
|
|
|
|
# 打印关键数据
|
|
|
|
|
|
print("\n" + "=" * 70)
|
|
|
|
|
|
print("THREE SCENARIOS ENERGY COMPARISON (100-300 years)")
|
|
|
|
|
|
print("=" * 70)
|
|
|
|
|
|
print(f"\n{'Year':<10} {'Combined':>15} {'Elevator':>15} {'Rocket':>15}")
|
|
|
|
|
|
print(f"{'':10} {'(PJ)':>15} {'(PJ)':>15} {'(PJ)':>15}")
|
|
|
|
|
|
print("-" * 55)
|
|
|
|
|
|
|
|
|
|
|
|
for ky in [110, 130, 150, 186, 200, 220, 250, 300]:
|
|
|
|
|
|
idx = np.argmin(np.abs(years - ky))
|
|
|
|
|
|
c = f'{combined_energy[idx]:.0f}' if not np.isnan(combined_energy[idx]) else 'N/A'
|
|
|
|
|
|
e = f'{elevator_energy[idx]:.0f}' if not np.isnan(elevator_energy[idx]) else 'N/A'
|
|
|
|
|
|
r = f'{rocket_energy[idx]:.0f}' if not np.isnan(rocket_energy[idx]) else 'N/A'
|
|
|
|
|
|
print(f"{ky:<10} {c:>15} {e:>15} {r:>15}")
|
|
|
|
|
|
|
|
|
|
|
|
print("=" * 70)
|
|
|
|
|
|
|
|
|
|
|
|
return fig
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============== 主程序 ==============
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
print("=" * 90)
|
|
|
|
|
|
print("MOON COLONY: COMBINED SCENARIO ANALYSIS")
|
|
|
|
|
|
print("(Space Elevator System + Traditional Rockets)")
|
|
|
|
|
|
print("=" * 90)
|
|
|
|
|
|
|
|
|
|
|
|
# 主分析
|
|
|
|
|
|
df = plot_combined_analysis()
|
|
|
|
|
|
|
|
|
|
|
|
# 打印摘要
|
|
|
|
|
|
print_summary(df)
|
|
|
|
|
|
|
|
|
|
|
|
# 方案对比
|
|
|
|
|
|
print("\n\n正在生成方案对比图...")
|
|
|
|
|
|
comparison = plot_scenario_comparison()
|
|
|
|
|
|
|
|
|
|
|
|
print("\n" + "=" * 90)
|
|
|
|
|
|
print("FINAL COMPARISON")
|
|
|
|
|
|
print("=" * 90)
|
|
|
|
|
|
print(f"\n{'Scenario':<25} {'Years':>12} {'Energy (PJ)':>15} {'vs Rocket Only':>18}")
|
|
|
|
|
|
print("-" * 70)
|
|
|
|
|
|
for name, data in comparison.items():
|
|
|
|
|
|
rocket_energy_val = comparison['rocket_only']['energy_PJ']
|
|
|
|
|
|
savings = (1 - data['energy_PJ'] / rocket_energy_val) * 100 if rocket_energy_val > 0 else 0
|
|
|
|
|
|
print(f"{name:<25} {data['years']:>12.0f} {data['energy_PJ']:>15.0f} {savings:>17.0f}%")
|
|
|
|
|
|
print("=" * 90)
|
|
|
|
|
|
|
|
|
|
|
|
# 生成三方案对比折线图 (100-300年)
|
|
|
|
|
|
print("\n\n正在生成三方案对比折线图 (100-300年)...")
|
|
|
|
|
|
plot_three_scenarios_comparison(year_min=100, year_max=300)
|