Files
tianpu-ems/backend/app/services/simulator.py
Du Wenbo f53a610a19 Initial commit: Tianpu Zero-Carbon EMS Platform
Full-stack energy management system for Tianpu Daxing campus.
- Frontend: React 19 + TypeScript + Ant Design + ECharts
- Backend: FastAPI + SQLAlchemy + PostgreSQL/TimescaleDB
- Features: PV monitoring, heat pump management, carbon tracking, alarms, reports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:36:06 +08:00

145 lines
6.8 KiB
Python

"""模拟数据生成器 - 为天普园区设备生成真实感的模拟数据"""
import asyncio
import random
import math
from datetime import datetime, timezone
from sqlalchemy import select
from app.core.database import async_session
from app.models.device import Device
from app.models.energy import EnergyData
from app.models.alarm import AlarmEvent
class DataSimulator:
def __init__(self):
self._task = None
self._running = False
async def start(self):
self._running = True
self._task = asyncio.create_task(self._run_loop())
async def stop(self):
self._running = False
if self._task:
self._task.cancel()
async def _run_loop(self):
while self._running:
try:
await self._generate_data()
except Exception as e:
print(f"Simulator error: {e}")
await asyncio.sleep(15) # 每15秒生成一次
async def _generate_data(self):
now = datetime.now(timezone.utc)
hour = (now.hour + 8) % 24 # 北京时间
async with async_session() as session:
result = await session.execute(select(Device).where(Device.is_active == True))
devices = result.scalars().all()
data_points = []
for device in devices:
points = self._generate_device_data(device, now, hour)
data_points.extend(points)
device.status = "online"
device.last_data_time = now
if data_points:
session.add_all(data_points)
await session.commit()
def _generate_device_data(self, device: Device, now: datetime, hour: int) -> list[EnergyData]:
points = []
if device.device_type == "pv_inverter":
points = self._gen_pv_data(device, now, hour)
elif device.device_type == "heat_pump":
points = self._gen_heatpump_data(device, now, hour)
elif device.device_type == "meter":
points = self._gen_meter_data(device, now, hour)
elif device.device_type == "sensor":
points = self._gen_sensor_data(device, now, hour)
return points
def _gen_pv_data(self, device: Device, now: datetime, hour: int) -> list[EnergyData]:
"""光伏逆变器数据 - 基于日照模型"""
rated = device.rated_power or 110 # kW
# 日照模型: 6-18点有发电, 12点最大
if 6 <= hour <= 18:
solar_factor = math.sin(math.pi * (hour - 6) / 12)
weather_factor = random.uniform(0.6, 1.0) # 天气影响
power = rated * solar_factor * weather_factor * random.uniform(0.85, 0.95)
else:
power = 0
daily_energy = rated * 4.5 * random.uniform(0.8, 1.1) # 日发电量约4.5等效小时
cumulative_energy = 170 + random.uniform(0, 5) # 累计发电MWh
return [
EnergyData(device_id=device.id, timestamp=now, data_type="power", value=round(power, 2), unit="kW"),
EnergyData(device_id=device.id, timestamp=now, data_type="daily_energy", value=round(daily_energy * hour / 24, 2), unit="kWh"),
EnergyData(device_id=device.id, timestamp=now, data_type="total_energy", value=round(cumulative_energy * 1000, 1), unit="kWh"),
EnergyData(device_id=device.id, timestamp=now, data_type="dc_voltage", value=round(random.uniform(250, 800), 1), unit="V"),
EnergyData(device_id=device.id, timestamp=now, data_type="ac_voltage", value=round(random.uniform(218, 222), 1), unit="V"),
EnergyData(device_id=device.id, timestamp=now, data_type="temperature", value=round(random.uniform(25, 45), 1), unit=""),
]
def _gen_heatpump_data(self, device: Device, now: datetime, hour: int) -> list[EnergyData]:
"""热泵机组数据"""
# 冬季供暖模式
is_heating_season = now.month in [1, 2, 3, 10, 11, 12]
if is_heating_season:
outdoor_temp = random.uniform(-5, 10)
cop = random.uniform(2.5, 3.8)
inlet_temp = random.uniform(35, 42)
outlet_temp = inlet_temp + random.uniform(5, 10)
power = random.uniform(20, 35)
flow_rate = random.uniform(8, 15)
else:
outdoor_temp = random.uniform(15, 35)
cop = random.uniform(3.5, 5.0)
inlet_temp = random.uniform(8, 12)
outlet_temp = inlet_temp - random.uniform(3, 6)
power = random.uniform(15, 28)
flow_rate = random.uniform(8, 15)
return [
EnergyData(device_id=device.id, timestamp=now, data_type="power", value=round(power, 2), unit="kW"),
EnergyData(device_id=device.id, timestamp=now, data_type="cop", value=round(cop, 2), unit=""),
EnergyData(device_id=device.id, timestamp=now, data_type="inlet_temp", value=round(inlet_temp, 1), unit=""),
EnergyData(device_id=device.id, timestamp=now, data_type="outlet_temp", value=round(outlet_temp, 1), unit=""),
EnergyData(device_id=device.id, timestamp=now, data_type="flow_rate", value=round(flow_rate, 1), unit="m³/h"),
EnergyData(device_id=device.id, timestamp=now, data_type="outdoor_temp", value=round(outdoor_temp, 1), unit=""),
]
def _gen_meter_data(self, device: Device, now: datetime, hour: int) -> list[EnergyData]:
"""电表数据"""
# 负荷曲线: 白天高, 夜间低
base_load = 50 # 基础负荷kW
if 8 <= hour <= 18:
load_factor = random.uniform(1.2, 2.0)
elif 18 <= hour <= 22:
load_factor = random.uniform(0.8, 1.3)
else:
load_factor = random.uniform(0.3, 0.6)
power = base_load * load_factor + random.uniform(-5, 5)
return [
EnergyData(device_id=device.id, timestamp=now, data_type="power", value=round(power, 2), unit="kW"),
EnergyData(device_id=device.id, timestamp=now, data_type="voltage", value=round(random.uniform(218, 225), 1), unit="V"),
EnergyData(device_id=device.id, timestamp=now, data_type="current", value=round(power / 0.38 / random.uniform(0.85, 0.95), 1), unit="A"),
EnergyData(device_id=device.id, timestamp=now, data_type="power_factor", value=round(random.uniform(0.88, 0.98), 3), unit=""),
]
def _gen_sensor_data(self, device: Device, now: datetime, hour: int) -> list[EnergyData]:
"""温湿度传感器数据"""
# 室内温度根据供暖状态
indoor_temp = random.uniform(20, 24) if now.month in [1, 2, 3, 10, 11, 12] else random.uniform(22, 28)
humidity = random.uniform(35, 65)
return [
EnergyData(device_id=device.id, timestamp=now, data_type="temperature", value=round(indoor_temp, 1), unit=""),
EnergyData(device_id=device.id, timestamp=now, data_type="humidity", value=round(humidity, 1), unit="%"),
]