mirror of
https://github.com/ZGCA-Forge/Elevator.git
synced 2025-12-15 13:34:44 +00:00
Compare commits
10 Commits
0.0.5
...
83459923e8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83459923e8 | ||
|
|
b4b99daead | ||
|
|
d44ba8b6cd | ||
|
|
71e8f2a451 | ||
|
|
4b60359894 | ||
|
|
0157496e6f | ||
|
|
1031e677e1 | ||
|
|
889d554f19 | ||
|
|
ee3c4bab7e | ||
|
|
99524eee3d |
@@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 0.0.5
|
||||
current_version = 0.0.9
|
||||
commit = True
|
||||
tag = True
|
||||
tag_name = v{new_version}
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
# ================================
|
||||
# Python-related files
|
||||
# ================================
|
||||
elevator_saga/traffic/test_cases.py
|
||||
|
||||
# Compiled Python files
|
||||
__pycache__/
|
||||
|
||||
@@ -284,6 +284,7 @@ The controller provides these event handlers:
|
||||
- ``on_passenger_alight(elevator, passenger, floor)``: Passenger alights
|
||||
- ``on_elevator_passing_floor(elevator, floor, direction)``: Elevator passes floor
|
||||
- ``on_elevator_approaching(elevator, floor, direction)``: Elevator about to arrive
|
||||
- ``on_elevator_move(elevator, from_position, to_position, direction, status)``: Elevator moves
|
||||
|
||||
Complete Example
|
||||
----------------
|
||||
|
||||
@@ -65,6 +65,8 @@ Response format:
|
||||
"passengers": [101, 102],
|
||||
"max_capacity": 10,
|
||||
"run_status": "constant_speed",
|
||||
"energy_consumed": 38.5,
|
||||
"energy_rate": 1.0,
|
||||
"..."
|
||||
}
|
||||
],
|
||||
@@ -81,7 +83,8 @@ Response format:
|
||||
"avg_wait": 15.2,
|
||||
"p95_wait": 30.0,
|
||||
"avg_system": 25.5,
|
||||
"p95_system": 45.0
|
||||
"p95_system": 45.0,
|
||||
"total_energy_consumption": 156.0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ Event System
|
||||
Event Types
|
||||
~~~~~~~~~~~
|
||||
|
||||
The simulation generates 8 types of events defined in ``EventType`` enum:
|
||||
The simulation generates 9 types of events defined in ``EventType`` enum:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -215,6 +215,7 @@ The simulation generates 8 types of events defined in ``EventType`` enum:
|
||||
IDLE = "idle"
|
||||
PASSENGER_BOARD = "passenger_board"
|
||||
PASSENGER_ALIGHT = "passenger_alight"
|
||||
ELEVATOR_MOVE = "elevator_move"
|
||||
|
||||
Event Generation
|
||||
~~~~~~~~~~~~~~~~
|
||||
@@ -260,6 +261,19 @@ Events are generated during tick processing:
|
||||
for elevator in self.elevators:
|
||||
# ... movement logic ...
|
||||
|
||||
# Elevator moves
|
||||
if elevator.target_floor_direction != Direction.STOPPED:
|
||||
self._emit_event(
|
||||
EventType.ELEVATOR_MOVE,
|
||||
{
|
||||
"elevator": elevator.id,
|
||||
"from_position": old_position,
|
||||
"to_position": elevator.position.current_floor_float,
|
||||
"direction": elevator.target_floor_direction.value,
|
||||
"status": elevator.run_status.value,
|
||||
}
|
||||
)
|
||||
|
||||
# Passing a floor
|
||||
if old_floor != new_floor and new_floor != target_floor:
|
||||
self._emit_event(
|
||||
@@ -363,6 +377,14 @@ The ``ElevatorController`` base class automatically routes events to handler met
|
||||
elevator = self.elevators[event.data["elevator"]]
|
||||
self.on_elevator_idle(elevator)
|
||||
|
||||
elif event.type == EventType.ELEVATOR_MOVE:
|
||||
elevator = self.elevators[event.data["elevator"]]
|
||||
from_position = event.data["from_position"]
|
||||
to_position = event.data["to_position"]
|
||||
direction = event.data["direction"]
|
||||
status = event.data["status"]
|
||||
self.on_elevator_move(elevator, from_position, to_position, direction, status)
|
||||
|
||||
# ... other event types ...
|
||||
|
||||
Control Flow: Bus Example
|
||||
|
||||
@@ -28,7 +28,9 @@ Features
|
||||
|
||||
🔌 **Client-Server Model**: Separate simulation server from control logic for clean architecture
|
||||
|
||||
📊 **Performance Metrics**: Track wait times, system times, and completion rates
|
||||
📊 **Performance Metrics**: Track wait times, system times, completion rates, and energy consumption
|
||||
|
||||
⚡ **Energy Tracking**: Monitor and optimize energy consumption with configurable per-elevator energy rates
|
||||
|
||||
🎯 **Flexible Control**: Implement your own algorithms using a simple controller interface
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ Complete state information for an elevator:
|
||||
indicators: ElevatorIndicators = field(default_factory=ElevatorIndicators)
|
||||
passenger_destinations: Dict[int, int] = {} # passenger_id -> floor
|
||||
energy_consumed: float = 0.0
|
||||
energy_rate: float = 1.0 # Energy consumption rate per tick
|
||||
last_update_tick: int = 0
|
||||
|
||||
Key Properties:
|
||||
@@ -142,6 +143,11 @@ Key Properties:
|
||||
- ``pressed_floors``: List of destination floors for current passengers
|
||||
- ``load_factor``: Current load as fraction of capacity (0.0 to 1.0)
|
||||
|
||||
Energy Tracking:
|
||||
|
||||
- ``energy_consumed``: Total energy consumed by this elevator during the simulation
|
||||
- ``energy_rate``: Energy consumption rate per tick when moving (default: 1.0). Can be customized in traffic configuration files to simulate different elevator types (e.g., older elevators with higher rates, newer energy-efficient elevators with lower rates)
|
||||
|
||||
FloorState
|
||||
~~~~~~~~~~
|
||||
|
||||
@@ -261,11 +267,16 @@ Tracks simulation performance:
|
||||
p95_floor_wait_time: float = 0.0 # 95th percentile
|
||||
average_arrival_wait_time: float = 0.0
|
||||
p95_arrival_wait_time: float = 0.0 # 95th percentile
|
||||
total_energy_consumption: float = 0.0 # Total energy consumed by all elevators
|
||||
|
||||
Properties:
|
||||
|
||||
- ``completion_rate``: Fraction of passengers completed (0.0 to 1.0)
|
||||
|
||||
Energy Metrics:
|
||||
|
||||
- ``total_energy_consumption``: Sum of energy consumed by all elevators in the system. Each elevator consumes ``energy_rate`` units of energy per tick when moving.
|
||||
|
||||
API Models
|
||||
----------
|
||||
|
||||
@@ -345,3 +356,75 @@ All models support JSON serialization:
|
||||
restored = ElevatorState.from_dict(data)
|
||||
|
||||
This enables seamless transmission over HTTP between client and server.
|
||||
|
||||
Energy System
|
||||
-------------
|
||||
|
||||
Overview
|
||||
~~~~~~~~
|
||||
|
||||
The energy system tracks energy consumption of elevators to help optimize control algorithms for both passenger service and energy efficiency.
|
||||
|
||||
How Energy Works
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
**Energy Consumption:**
|
||||
|
||||
- Each elevator has an ``energy_rate`` attribute (default: 1.0)
|
||||
- When an elevator moves (any tick where it's not stopped), it consumes energy equal to its ``energy_rate``
|
||||
- Energy consumption is independent of speed, direction, or load
|
||||
- Total system energy is the sum of all individual elevator energy consumption
|
||||
|
||||
**Configuration:**
|
||||
|
||||
Energy rates are configured in traffic JSON files via the ``elevator_energy_rates`` field:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"building": {
|
||||
"floors": 10,
|
||||
"elevators": 3,
|
||||
"elevator_capacity": 10,
|
||||
"elevator_energy_rates": [1.0, 1.0, 1.2],
|
||||
"scenario": "custom_scenario",
|
||||
"duration": 600
|
||||
},
|
||||
"traffic": []
|
||||
}
|
||||
|
||||
In this example, elevators 0 and 1 have standard energy rates (1.0), while elevator 2 consumes 20% more energy (1.2), perhaps representing an older or less efficient unit.
|
||||
|
||||
**Use Cases:**
|
||||
|
||||
1. **Algorithm Optimization**: Balance passenger wait times against energy consumption
|
||||
2. **Heterogeneous Fleets**: Model buildings with elevators of different ages/efficiencies
|
||||
3. **Cost Analysis**: Evaluate the energy cost of different control strategies
|
||||
4. **Green Building Simulation**: Optimize for minimal energy while maintaining service quality
|
||||
|
||||
Example Usage
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Get current state
|
||||
state = api_client.get_state()
|
||||
|
||||
# Check individual elevator energy
|
||||
for elevator in state.elevators:
|
||||
print(f"Elevator {elevator.id}: {elevator.energy_consumed} units consumed")
|
||||
print(f" Energy rate: {elevator.energy_rate} units/tick")
|
||||
|
||||
# Check total system energy
|
||||
metrics = state.metrics
|
||||
print(f"Total system energy: {metrics.total_energy_consumption} units")
|
||||
print(f"Completed passengers: {metrics.completed_passengers}")
|
||||
|
||||
# Calculate energy per passenger
|
||||
if metrics.completed_passengers > 0:
|
||||
energy_per_passenger = metrics.total_energy_consumption / metrics.completed_passengers
|
||||
print(f"Energy per passenger: {energy_per_passenger:.2f} units")
|
||||
|
||||
**Default Behavior:**
|
||||
|
||||
If ``elevator_energy_rates`` is not specified in the traffic file, all elevators default to an energy rate of 1.0, ensuring backward compatibility with existing traffic files.
|
||||
|
||||
@@ -6,5 +6,5 @@ A Python implementation of the Elevator Saga game with event-driven architecture
|
||||
realistic elevator dispatch algorithm development and testing.
|
||||
"""
|
||||
|
||||
__version__ = "0.0.5"
|
||||
__version__ = "0.0.9"
|
||||
__author__ = "ZGCA Team"
|
||||
|
||||
@@ -7,7 +7,7 @@ import os
|
||||
import time
|
||||
from abc import ABC, abstractmethod
|
||||
from pprint import pprint
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from elevator_saga.client.api_client import ElevatorAPIClient
|
||||
from elevator_saga.client.proxy_models import ProxyElevator, ProxyFloor, ProxyPassenger
|
||||
@@ -171,6 +171,22 @@ class ElevatorController(ABC):
|
||||
"""
|
||||
pass
|
||||
|
||||
# @abstractmethod 为了兼容性暂不强制要求elevator_move必须实现
|
||||
def on_elevator_move(
|
||||
self, elevator: ProxyElevator, from_position: float, to_position: float, direction: str, status: str
|
||||
) -> None:
|
||||
"""
|
||||
电梯移动时的回调 - 可选实现
|
||||
|
||||
Args:
|
||||
elevator: 电梯代理对象
|
||||
from_position: 起始位置(浮点数表示楼层)
|
||||
to_position: 目标位置(浮点数表示楼层)
|
||||
direction: 移动方向
|
||||
status: 电梯运行状态
|
||||
"""
|
||||
pass
|
||||
|
||||
def _internal_init(self, elevators: List[Any], floors: List[Any]) -> None:
|
||||
"""内部初始化方法"""
|
||||
self.elevators = elevators
|
||||
@@ -218,7 +234,7 @@ class ElevatorController(ABC):
|
||||
# 获取初始状态并初始化,默认从0开始
|
||||
try:
|
||||
state = self.api_client.get_state()
|
||||
except ConnectionResetError as ex:
|
||||
except ConnectionResetError as _: # noqa: F841
|
||||
print(f"模拟器可能并没有开启,请检查模拟器是否启动 {self.api_client.base_url}")
|
||||
os._exit(1)
|
||||
if state.tick > 0:
|
||||
@@ -381,6 +397,22 @@ class ElevatorController(ABC):
|
||||
floor_proxy = ProxyFloor(floor_id, self.api_client)
|
||||
self.on_passenger_alight(elevator_proxy, passenger_proxy, floor_proxy)
|
||||
|
||||
elif event.type == EventType.ELEVATOR_MOVE:
|
||||
elevator_id = event.data.get("elevator")
|
||||
from_position = event.data.get("from_position")
|
||||
to_position = event.data.get("to_position")
|
||||
direction = event.data.get("direction")
|
||||
status = event.data.get("status")
|
||||
if (
|
||||
elevator_id is not None
|
||||
and from_position is not None
|
||||
and to_position is not None
|
||||
and direction is not None
|
||||
and status is not None
|
||||
):
|
||||
elevator_proxy = ProxyElevator(elevator_id, self.api_client)
|
||||
self.on_elevator_move(elevator_proxy, from_position, to_position, direction, status)
|
||||
|
||||
def _reset_and_reinit(self) -> None:
|
||||
"""重置并重新初始化"""
|
||||
try:
|
||||
|
||||
@@ -72,6 +72,11 @@ class ElevatorBusExampleController(ElevatorController):
|
||||
def on_elevator_approaching(self, elevator: ProxyElevator, floor: ProxyFloor, direction: str) -> None:
|
||||
pass
|
||||
|
||||
def on_elevator_move(
|
||||
self, elevator: ProxyElevator, from_position: float, to_position: float, direction: str, status: str
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
algorithm = ElevatorBusExampleController()
|
||||
|
||||
@@ -139,6 +139,17 @@ class ElevatorBusController(ElevatorController):
|
||||
elevator.go_to_floor(elevator.target_floor + 1, immediate=True)
|
||||
print(f" 不让0号电梯上行停站,设定新目标楼层 {elevator.target_floor + 1}")
|
||||
|
||||
def on_elevator_move(
|
||||
self, elevator: ProxyElevator, from_position: float, to_position: float, direction: str, status: str
|
||||
) -> None:
|
||||
"""
|
||||
电梯移动时的回调
|
||||
可以在这里记录电梯移动信息,用于调试或性能分析
|
||||
"""
|
||||
# 取消注释以显示电梯移动信息
|
||||
# print(f"🚀 电梯 E{elevator.id} 移动: {from_position:.1f} -> {to_position:.1f} ({direction}, {status})")
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
algorithm = ElevatorBusController(debug=True)
|
||||
|
||||
@@ -8,7 +8,7 @@ import uuid
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar, Union
|
||||
from typing import Any, Dict, List, Optional, Tuple, Type, TypeVar, Union
|
||||
|
||||
# 类型变量
|
||||
T = TypeVar("T", bound="SerializableModel")
|
||||
@@ -55,6 +55,7 @@ class EventType(Enum):
|
||||
IDLE = "idle"
|
||||
PASSENGER_BOARD = "passenger_board"
|
||||
PASSENGER_ALIGHT = "passenger_alight"
|
||||
ELEVATOR_MOVE = "elevator_move" # 电梯移动事件
|
||||
|
||||
|
||||
class SerializableModel:
|
||||
@@ -113,7 +114,7 @@ class Position(SerializableModel):
|
||||
|
||||
@property
|
||||
def current_floor_float(self) -> float:
|
||||
return self.current_floor + self.floor_up_position / 10
|
||||
return round(self.current_floor + self.floor_up_position / 10, 1)
|
||||
|
||||
def floor_up_position_add(self, num: int) -> int:
|
||||
self.floor_up_position += num
|
||||
@@ -161,12 +162,13 @@ class PassengerInfo(SerializableModel):
|
||||
arrive_tick: int
|
||||
pickup_tick: int = 0
|
||||
dropoff_tick: int = 0
|
||||
arrived: bool = False
|
||||
elevator_id: Optional[int] = None
|
||||
|
||||
@property
|
||||
def status(self) -> PassengerStatus:
|
||||
"""乘客状态"""
|
||||
if self.dropoff_tick > 0:
|
||||
if self.arrived:
|
||||
return PassengerStatus.COMPLETED
|
||||
elif self.pickup_tick > 0:
|
||||
return PassengerStatus.IN_ELEVATOR
|
||||
@@ -209,6 +211,7 @@ class ElevatorState(SerializableModel):
|
||||
indicators: ElevatorIndicators = field(default_factory=ElevatorIndicators)
|
||||
passenger_destinations: Dict[int, int] = field(default_factory=dict) # 乘客ID -> 目的地楼层映射
|
||||
energy_consumed: float = 0.0
|
||||
energy_rate: float = 1.0 # 能耗率:每tick消耗的能量单位
|
||||
last_update_tick: int = 0
|
||||
|
||||
@property
|
||||
@@ -335,7 +338,7 @@ class PerformanceMetrics(SerializableModel):
|
||||
p95_floor_wait_time: float = 0.0
|
||||
average_arrival_wait_time: float = 0.0
|
||||
p95_arrival_wait_time: float = 0.0
|
||||
# total_energy_consumption: float = 0.0
|
||||
total_energy_consumption: float = 0.0
|
||||
|
||||
@property
|
||||
def completion_rate(self) -> float:
|
||||
@@ -344,13 +347,6 @@ class PerformanceMetrics(SerializableModel):
|
||||
return 0.0
|
||||
return self.completed_passengers / self.total_passengers
|
||||
|
||||
# @property
|
||||
# def energy_per_passenger(self) -> float:
|
||||
# """每位乘客能耗"""
|
||||
# if self.completed_passengers == 0:
|
||||
# return 0.0
|
||||
# return self.total_energy_consumption / self.completed_passengers
|
||||
|
||||
|
||||
@dataclass
|
||||
class SimulationState(SerializableModel):
|
||||
|
||||
@@ -138,6 +138,17 @@ class ElevatorBusController(ElevatorController):
|
||||
elevator.go_to_floor(elevator.target_floor + 1, immediate=True)
|
||||
print(f" 不让0号电梯上行停站,设定新目标楼层 {elevator.target_floor + 1}")
|
||||
|
||||
def on_elevator_move(
|
||||
self, elevator: ProxyElevator, from_position: float, to_position: float, direction: str, status: str
|
||||
) -> None:
|
||||
"""
|
||||
电梯移动时的回调
|
||||
可以在这里记录电梯移动信息,用于调试或性能分析
|
||||
"""
|
||||
# 取消注释以显示电梯移动信息
|
||||
# print(f"🚀 电梯 E{elevator.id} 移动: {from_position:.1f} -> {to_position:.1f} ({direction}, {status})")
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
algorithm = ElevatorBusController(debug=True)
|
||||
|
||||
@@ -10,7 +10,7 @@ import threading
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, cast
|
||||
from typing import Any, Dict, List, cast
|
||||
|
||||
from flask import Flask, Response, request
|
||||
|
||||
@@ -180,6 +180,14 @@ class ElevatorSimulation:
|
||||
building_config["elevators"], building_config["floors"], building_config["elevator_capacity"]
|
||||
)
|
||||
self.reset()
|
||||
|
||||
# 设置电梯能耗率
|
||||
elevator_energy_rates = building_config.get("elevator_energy_rates", [1.0] * building_config["elevators"])
|
||||
for i, elevator in enumerate(self.state.elevators):
|
||||
if i < len(elevator_energy_rates):
|
||||
elevator.energy_rate = elevator_energy_rates[i]
|
||||
server_debug_log(f"电梯 E{elevator.id} 能耗率设置为: {elevator.energy_rate}")
|
||||
|
||||
self.max_duration_ticks = building_config["duration"]
|
||||
traffic_data: list[Dict[str, Any]] = file_data["traffic"]
|
||||
traffic_data.sort(key=lambda t: cast(int, t["tick"]))
|
||||
@@ -274,7 +282,7 @@ class ElevatorSimulation:
|
||||
# 2. Move elevators
|
||||
self._move_elevators()
|
||||
|
||||
# 3. Process elevator stops and passenger boarding/alighting
|
||||
# 3. Process elevator stops and passenger alighting
|
||||
self._process_elevator_stops()
|
||||
|
||||
# Return events generated this tick
|
||||
@@ -310,7 +318,6 @@ class ElevatorSimulation:
|
||||
def _update_elevator_status(self) -> None:
|
||||
"""更新电梯运行状态"""
|
||||
for elevator in self.elevators:
|
||||
current_floor = elevator.position.current_floor
|
||||
target_floor = elevator.target_floor
|
||||
old_status = elevator.run_status.value
|
||||
# 没有移动方向,说明电梯已经到达目标楼层
|
||||
@@ -378,14 +385,32 @@ class ElevatorSimulation:
|
||||
|
||||
# 根据状态和方向调整移动距离
|
||||
elevator.last_tick_direction = elevator.target_floor_direction
|
||||
old_position = elevator.position.current_floor_float
|
||||
if elevator.target_floor_direction == Direction.UP:
|
||||
new_floor = elevator.position.floor_up_position_add(movement_speed)
|
||||
# 电梯移动时增加能耗,每tick增加电梯的能耗率
|
||||
elevator.energy_consumed += elevator.energy_rate
|
||||
elif elevator.target_floor_direction == Direction.DOWN:
|
||||
new_floor = elevator.position.floor_up_position_add(-movement_speed)
|
||||
# 电梯移动时增加能耗,每tick增加电梯的能耗率
|
||||
elevator.energy_consumed += elevator.energy_rate
|
||||
else:
|
||||
# 之前的状态已经是到站了,清空上一次到站的方向
|
||||
pass
|
||||
|
||||
# 发送电梯移动事件
|
||||
if elevator.target_floor_direction != Direction.STOPPED:
|
||||
self._emit_event(
|
||||
EventType.ELEVATOR_MOVE,
|
||||
{
|
||||
"elevator": elevator.id,
|
||||
"from_position": old_position,
|
||||
"to_position": elevator.position.current_floor_float,
|
||||
"direction": elevator.target_floor_direction.value,
|
||||
"status": elevator.run_status.value,
|
||||
},
|
||||
)
|
||||
|
||||
# 移动后检测是否即将到站,从匀速状态切换到减速
|
||||
if elevator.run_status == ElevatorStatus.CONSTANT_SPEED:
|
||||
# 检查是否需要开始减速,这里加速减速设置路程为1,匀速路程为2,这样能够保证不会匀速恰好到达,必须加减速
|
||||
@@ -422,7 +447,6 @@ class ElevatorSimulation:
|
||||
self._emit_event(
|
||||
EventType.STOPPED_AT_FLOOR, {"elevator": elevator.id, "floor": new_floor, "reason": "move_reached"}
|
||||
)
|
||||
# elevator.energy_consumed += abs(direction * elevator.speed_pre_tick) * 0.5
|
||||
|
||||
def _process_elevator_stops(self) -> None:
|
||||
"""
|
||||
@@ -444,6 +468,7 @@ class ElevatorSimulation:
|
||||
passenger = self.passengers[passenger_id]
|
||||
if passenger.destination == current_floor:
|
||||
passenger.dropoff_tick = self.tick
|
||||
passenger.arrived = True
|
||||
passengers_to_remove.append(passenger_id)
|
||||
|
||||
# Remove passengers who alighted
|
||||
@@ -465,7 +490,6 @@ class ElevatorSimulation:
|
||||
[SERVER-DEBUG] 电梯 E0 被设定为前往 F1
|
||||
说明电梯处于stop状态,这个tick直接采用下一个目的地运行了
|
||||
"""
|
||||
original_target_floor = elevator.target_floor
|
||||
elevator.position.target_floor = floor
|
||||
server_debug_log(f"电梯 E{elevator.id} 被设定为前往 F{floor}")
|
||||
new_target_floor_should_accel = self._should_start_deceleration(elevator)
|
||||
@@ -540,6 +564,10 @@ class ElevatorSimulation:
|
||||
completed = [p for p in self.state.passengers.values() if p.status == PassengerStatus.COMPLETED]
|
||||
|
||||
total_passengers = len(self.state.passengers)
|
||||
|
||||
# 计算总能耗
|
||||
total_energy = sum(elevator.energy_consumed for elevator in self.state.elevators)
|
||||
|
||||
if not completed:
|
||||
return PerformanceMetrics(
|
||||
completed_passengers=0,
|
||||
@@ -548,6 +576,7 @@ class ElevatorSimulation:
|
||||
p95_floor_wait_time=0,
|
||||
average_arrival_wait_time=0,
|
||||
p95_arrival_wait_time=0,
|
||||
total_energy_consumption=total_energy,
|
||||
)
|
||||
|
||||
floor_wait_times = [float(p.floor_wait_time) for p in completed]
|
||||
@@ -573,6 +602,7 @@ class ElevatorSimulation:
|
||||
p95_floor_wait_time=average_excluding_top_percent(floor_wait_times, 5),
|
||||
average_arrival_wait_time=sum(arrival_wait_times) / len(arrival_wait_times) if arrival_wait_times else 0,
|
||||
p95_arrival_wait_time=average_excluding_top_percent(arrival_wait_times, 5),
|
||||
total_energy_consumption=total_energy,
|
||||
)
|
||||
|
||||
def get_events(self, since_tick: int = 0) -> List[SimulationEvent]:
|
||||
|
||||
@@ -290,7 +290,7 @@ def generate_fire_evacuation_traffic(
|
||||
for floor in range(1, floors):
|
||||
# 每层随机数量的人需要疏散
|
||||
num_people = random.randint(people_per_floor[0], people_per_floor[1])
|
||||
for i in range(num_people):
|
||||
for _ in range(num_people):
|
||||
# 在10个tick内陆续到达,模拟疏散的紧急性
|
||||
arrival_tick = alarm_tick + random.randint(0, min(10, duration - alarm_tick - 1))
|
||||
if arrival_tick < duration:
|
||||
@@ -791,10 +791,12 @@ def generate_traffic_file(scenario: str, output_file: str, scale: Optional[str]
|
||||
traffic_data = generator_func(**generator_params)
|
||||
|
||||
# 准备building配置
|
||||
num_elevators = params["elevators"]
|
||||
building_config = {
|
||||
"floors": params["floors"],
|
||||
"elevators": params["elevators"],
|
||||
"elevators": num_elevators,
|
||||
"elevator_capacity": params["elevator_capacity"],
|
||||
"elevator_energy_rates": [1.0] * num_elevators, # 每台电梯的能耗率,默认为1.0
|
||||
"scenario": scenario,
|
||||
"scale": scale,
|
||||
"description": f"{config['description']} ({scale}规模)",
|
||||
@@ -835,7 +837,7 @@ def generate_scaled_traffic_files(
|
||||
if custom_building:
|
||||
floors = custom_building.get("floors", BUILDING_SCALES[scale]["floors"][0])
|
||||
elevators = custom_building.get("elevators", BUILDING_SCALES[scale]["elevators"][0])
|
||||
elevator_capacity = custom_building.get("capacity", BUILDING_SCALES[scale]["capacity"][0])
|
||||
_elevator_capacity = custom_building.get("capacity", BUILDING_SCALES[scale]["capacity"][0])
|
||||
|
||||
# 重新确定规模
|
||||
detected_scale = determine_building_scale(floors, elevators)
|
||||
|
||||
Reference in New Issue
Block a user