mirror of
https://github.com/ZGCA-Forge/Elevator.git
synced 2025-12-15 13:34:44 +00:00
fix performance calculation. fix floor error in approaching event. fix passenger board wrongly.
This commit is contained in:
@@ -176,7 +176,7 @@ Dynamic proxy for ``PassengerInfo`` that provides access to passenger informatio
|
|||||||
|
|
||||||
if passenger.status == PassengerStatus.IN_ELEVATOR:
|
if passenger.status == PassengerStatus.IN_ELEVATOR:
|
||||||
print(f"In elevator {passenger.elevator_id}")
|
print(f"In elevator {passenger.elevator_id}")
|
||||||
print(f"Waited {passenger.wait_time} ticks")
|
print(f"Waited {passenger.floor_wait_time} ticks")
|
||||||
|
|
||||||
Read-Only Protection
|
Read-Only Protection
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ Events are generated during tick processing:
|
|||||||
EventType.ELEVATOR_APPROACHING,
|
EventType.ELEVATOR_APPROACHING,
|
||||||
{
|
{
|
||||||
"elevator": elevator.id,
|
"elevator": elevator.id,
|
||||||
"floor": elevator.target_floor,
|
"floor": int(round(elevator.position.current_floor_float)),
|
||||||
"direction": elevator.target_floor_direction.value
|
"direction": elevator.target_floor_direction.value
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -487,28 +487,39 @@ Metrics are calculated from passenger data:
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
def _calculate_metrics(self) -> MetricsResponse:
|
def _calculate_metrics(self) -> PerformanceMetrics:
|
||||||
"""Calculate performance metrics"""
|
"""Calculate performance metrics"""
|
||||||
completed = [p for p in self.state.passengers.values()
|
completed = [p for p in self.state.passengers.values()
|
||||||
if p.status == PassengerStatus.COMPLETED]
|
if p.status == PassengerStatus.COMPLETED]
|
||||||
|
|
||||||
wait_times = [float(p.wait_time) for p in completed]
|
floor_wait_times = [float(p.floor_wait_time) for p in completed]
|
||||||
system_times = [float(p.system_time) for p in completed]
|
arrival_wait_times = [float(p.arrival_wait_time) for p in completed]
|
||||||
|
|
||||||
return MetricsResponse(
|
def average_excluding_top_percent(data: List[float], exclude_percent: int) -> float:
|
||||||
done=len(completed),
|
"""计算排除掉最长的指定百分比后的平均值"""
|
||||||
total=len(self.state.passengers),
|
if not data:
|
||||||
avg_wait=sum(wait_times) / len(wait_times) if wait_times else 0,
|
return 0.0
|
||||||
p95_wait=percentile(wait_times, 95),
|
sorted_data = sorted(data)
|
||||||
avg_system=sum(system_times) / len(system_times) if system_times else 0,
|
keep_count = int(len(sorted_data) * (100 - exclude_percent) / 100)
|
||||||
p95_system=percentile(system_times, 95),
|
if keep_count == 0:
|
||||||
|
return 0.0
|
||||||
|
kept_data = sorted_data[:keep_count]
|
||||||
|
return sum(kept_data) / len(kept_data)
|
||||||
|
|
||||||
|
return PerformanceMetrics(
|
||||||
|
completed_passengers=len(completed),
|
||||||
|
total_passengers=len(self.state.passengers),
|
||||||
|
average_floor_wait_time=sum(floor_wait_times) / len(floor_wait_times) if floor_wait_times else 0,
|
||||||
|
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),
|
||||||
)
|
)
|
||||||
|
|
||||||
Key metrics:
|
Key metrics:
|
||||||
|
|
||||||
- **Wait time**: ``pickup_tick - arrive_tick`` (how long passenger waited)
|
- **Floor wait time**: ``pickup_tick - arrive_tick`` (在楼层等待的时间,从到达到上电梯)
|
||||||
- **System time**: ``dropoff_tick - arrive_tick`` (total time in system)
|
- **Arrival wait time**: ``dropoff_tick - arrive_tick`` (总等待时间,从到达到下电梯)
|
||||||
- **P95**: 95th percentile (worst-case for most passengers)
|
- **P95 metrics**: 排除掉最长的5%时间后,计算剩余95%的平均值
|
||||||
|
|
||||||
Summary
|
Summary
|
||||||
-------
|
-------
|
||||||
|
|||||||
@@ -257,10 +257,10 @@ Tracks simulation performance:
|
|||||||
class PerformanceMetrics(SerializableModel):
|
class PerformanceMetrics(SerializableModel):
|
||||||
completed_passengers: int = 0
|
completed_passengers: int = 0
|
||||||
total_passengers: int = 0
|
total_passengers: int = 0
|
||||||
average_wait_time: float = 0.0
|
average_floor_wait_time: float = 0.0
|
||||||
p95_wait_time: float = 0.0 # 95th percentile
|
p95_floor_wait_time: float = 0.0 # 95th percentile
|
||||||
average_system_time: float = 0.0
|
average_arrival_wait_time: float = 0.0
|
||||||
p95_system_time: float = 0.0 # 95th percentile
|
p95_arrival_wait_time: float = 0.0 # 95th percentile
|
||||||
|
|
||||||
Properties:
|
Properties:
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Unified API Client for Elevator Saga
|
|||||||
import json
|
import json
|
||||||
import urllib.error
|
import urllib.error
|
||||||
import urllib.request
|
import urllib.request
|
||||||
from typing import Any, Dict, Optional, Union
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from elevator_saga.core.models import (
|
from elevator_saga.core.models import (
|
||||||
ElevatorState,
|
ElevatorState,
|
||||||
@@ -63,16 +63,8 @@ class ElevatorAPIClient:
|
|||||||
# 使用服务端返回的metrics数据
|
# 使用服务端返回的metrics数据
|
||||||
metrics_data = response_data.get("metrics", {})
|
metrics_data = response_data.get("metrics", {})
|
||||||
if metrics_data:
|
if metrics_data:
|
||||||
# 转换为PerformanceMetrics格式
|
# 直接从字典创建PerformanceMetrics对象
|
||||||
metrics = PerformanceMetrics(
|
metrics = PerformanceMetrics.from_dict(metrics_data)
|
||||||
completed_passengers=metrics_data.get("done", 0),
|
|
||||||
total_passengers=metrics_data.get("total", 0),
|
|
||||||
average_wait_time=metrics_data.get("avg_wait", 0),
|
|
||||||
p95_wait_time=metrics_data.get("p95_wait", 0),
|
|
||||||
average_system_time=metrics_data.get("avg_system", 0),
|
|
||||||
p95_system_time=metrics_data.get("p95_system", 0),
|
|
||||||
# total_energy_consumption=metrics_data.get("energy_total", 0),
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
metrics = PerformanceMetrics()
|
metrics = PerformanceMetrics()
|
||||||
|
|
||||||
@@ -131,7 +123,7 @@ class ElevatorAPIClient:
|
|||||||
else:
|
else:
|
||||||
raise RuntimeError(f"Step failed: {response_data.get('error')}")
|
raise RuntimeError(f"Step failed: {response_data.get('error')}")
|
||||||
|
|
||||||
def send_elevator_command(self, command: Union[GoToFloorCommand]) -> bool:
|
def send_elevator_command(self, command: GoToFloorCommand) -> bool:
|
||||||
"""发送电梯命令"""
|
"""发送电梯命令"""
|
||||||
endpoint = self._get_elevator_endpoint(command)
|
endpoint = self._get_elevator_endpoint(command)
|
||||||
debug_log(
|
debug_log(
|
||||||
@@ -156,7 +148,7 @@ class ElevatorAPIClient:
|
|||||||
debug_log(f"Go to floor failed: {e}")
|
debug_log(f"Go to floor failed: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _get_elevator_endpoint(self, command: Union[GoToFloorCommand]) -> str:
|
def _get_elevator_endpoint(self, command: GoToFloorCommand) -> str:
|
||||||
"""获取电梯命令端点"""
|
"""获取电梯命令端点"""
|
||||||
base = f"/api/elevators/{command.elevator_id}"
|
base = f"/api/elevators/{command.elevator_id}"
|
||||||
|
|
||||||
|
|||||||
@@ -352,9 +352,7 @@ class ElevatorController(ABC):
|
|||||||
if elevator_id is not None and floor_id is not None and direction is not None:
|
if elevator_id is not None and floor_id is not None and direction is not None:
|
||||||
elevator_proxy = ProxyElevator(elevator_id, self.api_client)
|
elevator_proxy = ProxyElevator(elevator_id, self.api_client)
|
||||||
floor_proxy = ProxyFloor(floor_id, self.api_client)
|
floor_proxy = ProxyFloor(floor_id, self.api_client)
|
||||||
# 服务端发送的direction是字符串,直接使用
|
self.on_elevator_passing_floor(elevator_proxy, floor_proxy, direction)
|
||||||
direction_str = direction if isinstance(direction, str) else direction.value
|
|
||||||
self.on_elevator_passing_floor(elevator_proxy, floor_proxy, direction_str)
|
|
||||||
|
|
||||||
elif event.type == EventType.ELEVATOR_APPROACHING:
|
elif event.type == EventType.ELEVATOR_APPROACHING:
|
||||||
elevator_id = event.data.get("elevator")
|
elevator_id = event.data.get("elevator")
|
||||||
@@ -363,9 +361,7 @@ class ElevatorController(ABC):
|
|||||||
if elevator_id is not None and floor_id is not None and direction is not None:
|
if elevator_id is not None and floor_id is not None and direction is not None:
|
||||||
elevator_proxy = ProxyElevator(elevator_id, self.api_client)
|
elevator_proxy = ProxyElevator(elevator_id, self.api_client)
|
||||||
floor_proxy = ProxyFloor(floor_id, self.api_client)
|
floor_proxy = ProxyFloor(floor_id, self.api_client)
|
||||||
# 服务端发送的direction是字符串,直接使用
|
self.on_elevator_approaching(elevator_proxy, floor_proxy, direction)
|
||||||
direction_str = direction if isinstance(direction, str) else direction.value
|
|
||||||
self.on_elevator_approaching(elevator_proxy, floor_proxy, direction_str)
|
|
||||||
|
|
||||||
elif event.type == EventType.PASSENGER_BOARD:
|
elif event.type == EventType.PASSENGER_BOARD:
|
||||||
elevator_id = event.data.get("elevator")
|
elevator_id = event.data.get("elevator")
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class ElevatorBusExampleController(ElevatorController):
|
|||||||
|
|
||||||
def on_passenger_call(self, passenger: ProxyPassenger, floor: ProxyFloor, direction: str) -> None:
|
def on_passenger_call(self, passenger: ProxyPassenger, floor: ProxyFloor, direction: str) -> None:
|
||||||
self.all_passengers.append(passenger)
|
self.all_passengers.append(passenger)
|
||||||
|
print(f"乘客 {passenger.id} F{floor.floor} 请求 {passenger.origin} -> {passenger.destination} ({direction})")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_elevator_idle(self, elevator: ProxyElevator) -> None:
|
def on_elevator_idle(self, elevator: ProxyElevator) -> None:
|
||||||
@@ -60,10 +61,10 @@ class ElevatorBusExampleController(ElevatorController):
|
|||||||
elevator.go_to_floor(elevator.current_floor - 1)
|
elevator.go_to_floor(elevator.current_floor - 1)
|
||||||
|
|
||||||
def on_passenger_board(self, elevator: ProxyElevator, passenger: ProxyPassenger) -> None:
|
def on_passenger_board(self, elevator: ProxyElevator, passenger: ProxyPassenger) -> None:
|
||||||
pass
|
print(f" 乘客{passenger.id} E{elevator.id}⬆️ F{elevator.current_floor} -> F{passenger.destination}")
|
||||||
|
|
||||||
def on_passenger_alight(self, elevator: ProxyElevator, passenger: ProxyPassenger, floor: ProxyFloor) -> None:
|
def on_passenger_alight(self, elevator: ProxyElevator, passenger: ProxyPassenger, floor: ProxyFloor) -> None:
|
||||||
pass
|
print(f" 乘客{passenger.id} E{elevator.id}⬇️ F{floor.floor}")
|
||||||
|
|
||||||
def on_elevator_passing_floor(self, elevator: ProxyElevator, floor: ProxyFloor, direction: str) -> None:
|
def on_elevator_passing_floor(self, elevator: ProxyElevator, floor: ProxyFloor, direction: str) -> None:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -174,13 +174,13 @@ class PassengerInfo(SerializableModel):
|
|||||||
return PassengerStatus.WAITING
|
return PassengerStatus.WAITING
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wait_time(self) -> int:
|
def floor_wait_time(self) -> int:
|
||||||
"""等待时间"""
|
"""在楼层等待的时间(从到达到上电梯)"""
|
||||||
return self.pickup_tick - self.arrive_tick
|
return self.pickup_tick - self.arrive_tick
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def system_time(self) -> int:
|
def arrival_wait_time(self) -> int:
|
||||||
"""系统时间(总时间)"""
|
"""总等待时间(从到达到下电梯)"""
|
||||||
return self.dropoff_tick - self.arrive_tick
|
return self.dropoff_tick - self.arrive_tick
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -331,10 +331,10 @@ class PerformanceMetrics(SerializableModel):
|
|||||||
|
|
||||||
completed_passengers: int = 0
|
completed_passengers: int = 0
|
||||||
total_passengers: int = 0
|
total_passengers: int = 0
|
||||||
average_wait_time: float = 0.0
|
average_floor_wait_time: float = 0.0
|
||||||
p95_wait_time: float = 0.0
|
p95_floor_wait_time: float = 0.0
|
||||||
average_system_time: float = 0.0
|
average_arrival_wait_time: float = 0.0
|
||||||
p95_system_time: float = 0.0
|
p95_arrival_wait_time: float = 0.0
|
||||||
# total_energy_consumption: float = 0.0
|
# total_energy_consumption: float = 0.0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from elevator_saga.core.models import (
|
|||||||
FloorState,
|
FloorState,
|
||||||
PassengerInfo,
|
PassengerInfo,
|
||||||
PassengerStatus,
|
PassengerStatus,
|
||||||
|
PerformanceMetrics,
|
||||||
SerializableModel,
|
SerializableModel,
|
||||||
SimulationEvent,
|
SimulationEvent,
|
||||||
SimulationState,
|
SimulationState,
|
||||||
@@ -89,19 +90,6 @@ def json_response(data: Any, status: int = 200) -> Response | tuple[Response, in
|
|||||||
return response, status
|
return response, status
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MetricsResponse(SerializableModel):
|
|
||||||
"""性能指标响应"""
|
|
||||||
|
|
||||||
done: int
|
|
||||||
total: int
|
|
||||||
avg_wait: float
|
|
||||||
p95_wait: float
|
|
||||||
avg_system: float
|
|
||||||
p95_system: float
|
|
||||||
energy_total: float
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PassengerSummary(SerializableModel):
|
class PassengerSummary(SerializableModel):
|
||||||
"""乘客摘要"""
|
"""乘客摘要"""
|
||||||
@@ -120,7 +108,7 @@ class SimulationStateResponse(SerializableModel):
|
|||||||
elevators: List[ElevatorState]
|
elevators: List[ElevatorState]
|
||||||
floors: List[FloorState]
|
floors: List[FloorState]
|
||||||
passengers: Dict[int, PassengerInfo]
|
passengers: Dict[int, PassengerInfo]
|
||||||
metrics: MetricsResponse
|
metrics: PerformanceMetrics
|
||||||
|
|
||||||
|
|
||||||
class ElevatorSimulation:
|
class ElevatorSimulation:
|
||||||
@@ -292,33 +280,32 @@ class ElevatorSimulation:
|
|||||||
# Return events generated this tick
|
# Return events generated this tick
|
||||||
return self.state.events[events_start:]
|
return self.state.events[events_start:]
|
||||||
|
|
||||||
def _process_passenger_in(self) -> None:
|
def _process_passenger_in(self, elevator: ElevatorState) -> None:
|
||||||
for elevator in self.elevators:
|
current_floor = elevator.current_floor
|
||||||
current_floor = elevator.current_floor
|
# 处于Stopped状态,方向也已经清空,说明没有调度。
|
||||||
# 处于Stopped状态,方向也已经清空,说明没有调度。
|
floor = self.floors[current_floor]
|
||||||
floor = self.floors[current_floor]
|
passengers_to_board: List[int] = []
|
||||||
passengers_to_board: List[int] = []
|
available_capacity = elevator.max_capacity - len(elevator.passengers)
|
||||||
available_capacity = elevator.max_capacity - len(elevator.passengers)
|
# Board passengers going up (if up indicator is on or no direction set)
|
||||||
# Board passengers going up (if up indicator is on or no direction set)
|
if elevator.target_floor_direction == Direction.UP:
|
||||||
if elevator.target_floor_direction == Direction.UP:
|
passengers_to_board.extend(floor.up_queue[:available_capacity])
|
||||||
passengers_to_board.extend(floor.up_queue[:available_capacity])
|
floor.up_queue = floor.up_queue[available_capacity:]
|
||||||
floor.up_queue = floor.up_queue[available_capacity:]
|
|
||||||
|
|
||||||
# Board passengers going down (if down indicator is on or no direction set)
|
# Board passengers going down (if down indicator is on or no direction set)
|
||||||
if elevator.target_floor_direction == Direction.DOWN:
|
if elevator.target_floor_direction == Direction.DOWN:
|
||||||
passengers_to_board.extend(floor.down_queue[:available_capacity])
|
passengers_to_board.extend(floor.down_queue[:available_capacity])
|
||||||
floor.down_queue = floor.down_queue[available_capacity:]
|
floor.down_queue = floor.down_queue[available_capacity:]
|
||||||
|
|
||||||
# Process boarding
|
# Process boarding
|
||||||
for passenger_id in passengers_to_board:
|
for passenger_id in passengers_to_board:
|
||||||
passenger = self.passengers[passenger_id]
|
passenger = self.passengers[passenger_id]
|
||||||
passenger.pickup_tick = self.tick
|
passenger.pickup_tick = self.tick
|
||||||
passenger.elevator_id = elevator.id
|
passenger.elevator_id = elevator.id
|
||||||
elevator.passengers.append(passenger_id)
|
elevator.passengers.append(passenger_id)
|
||||||
self._emit_event(
|
self._emit_event(
|
||||||
EventType.PASSENGER_BOARD,
|
EventType.PASSENGER_BOARD,
|
||||||
{"elevator": elevator.id, "floor": current_floor, "passenger": passenger_id},
|
{"elevator": elevator.id, "floor": current_floor, "passenger": passenger_id},
|
||||||
)
|
)
|
||||||
|
|
||||||
def _update_elevator_status(self) -> None:
|
def _update_elevator_status(self) -> None:
|
||||||
"""更新电梯运行状态"""
|
"""更新电梯运行状态"""
|
||||||
@@ -331,7 +318,7 @@ class ElevatorSimulation:
|
|||||||
if elevator.next_target_floor is not None:
|
if elevator.next_target_floor is not None:
|
||||||
self._set_elevator_target_floor(elevator, elevator.next_target_floor)
|
self._set_elevator_target_floor(elevator, elevator.next_target_floor)
|
||||||
|
|
||||||
self._process_passenger_in()
|
self._process_passenger_in(elevator)
|
||||||
elevator.next_target_floor = None
|
elevator.next_target_floor = None
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
@@ -411,7 +398,7 @@ class ElevatorSimulation:
|
|||||||
EventType.ELEVATOR_APPROACHING,
|
EventType.ELEVATOR_APPROACHING,
|
||||||
{
|
{
|
||||||
"elevator": elevator.id,
|
"elevator": elevator.id,
|
||||||
"floor": elevator.target_floor,
|
"floor": int(round(elevator.position.current_floor_float)),
|
||||||
"direction": elevator.target_floor_direction.value,
|
"direction": elevator.target_floor_direction.value,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -547,41 +534,45 @@ class ElevatorSimulation:
|
|||||||
metrics=metrics,
|
metrics=metrics,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _calculate_metrics(self) -> MetricsResponse:
|
def _calculate_metrics(self) -> PerformanceMetrics:
|
||||||
"""Calculate performance metrics"""
|
"""Calculate performance metrics"""
|
||||||
# 直接从state中筛选已完成的乘客
|
# 直接从state中筛选已完成的乘客
|
||||||
completed = [p for p in self.state.passengers.values() if p.status == PassengerStatus.COMPLETED]
|
completed = [p for p in self.state.passengers.values() if p.status == PassengerStatus.COMPLETED]
|
||||||
|
|
||||||
total_passengers = len(self.state.passengers)
|
total_passengers = len(self.state.passengers)
|
||||||
if not completed:
|
if not completed:
|
||||||
return MetricsResponse(
|
return PerformanceMetrics(
|
||||||
done=0,
|
completed_passengers=0,
|
||||||
total=total_passengers,
|
total_passengers=total_passengers,
|
||||||
avg_wait=0,
|
average_floor_wait_time=0,
|
||||||
p95_wait=0,
|
p95_floor_wait_time=0,
|
||||||
avg_system=0,
|
average_arrival_wait_time=0,
|
||||||
p95_system=0,
|
p95_arrival_wait_time=0,
|
||||||
energy_total=sum(e.energy_consumed for e in self.elevators),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
wait_times = [float(p.wait_time) for p in completed]
|
floor_wait_times = [float(p.floor_wait_time) for p in completed]
|
||||||
system_times = [float(p.system_time) for p in completed]
|
arrival_wait_times = [float(p.arrival_wait_time) for p in completed]
|
||||||
|
|
||||||
def percentile(data: List[float], p: int) -> float:
|
def average_excluding_top_percent(data: List[float], exclude_percent: int) -> float:
|
||||||
|
"""计算排除掉最长的指定百分比后的平均值"""
|
||||||
if not data:
|
if not data:
|
||||||
return 0.0
|
return 0.0
|
||||||
sorted_data = sorted(data)
|
sorted_data = sorted(data)
|
||||||
index = int(len(sorted_data) * p / 100)
|
# 计算要保留的数据数量(排除掉最长的 exclude_percent)
|
||||||
return sorted_data[min(index, len(sorted_data) - 1)]
|
keep_count = int(len(sorted_data) * (100 - exclude_percent) / 100)
|
||||||
|
if keep_count == 0:
|
||||||
|
return 0.0
|
||||||
|
# 只保留前 keep_count 个数据,排除最长的部分
|
||||||
|
kept_data = sorted_data[:keep_count]
|
||||||
|
return sum(kept_data) / len(kept_data)
|
||||||
|
|
||||||
return MetricsResponse(
|
return PerformanceMetrics(
|
||||||
done=len(completed),
|
completed_passengers=len(completed),
|
||||||
total=total_passengers,
|
total_passengers=total_passengers,
|
||||||
avg_wait=sum(wait_times) / len(wait_times) if wait_times else 0,
|
average_floor_wait_time=sum(floor_wait_times) / len(floor_wait_times) if floor_wait_times else 0,
|
||||||
p95_wait=percentile(wait_times, 95),
|
p95_floor_wait_time=average_excluding_top_percent(floor_wait_times, 5),
|
||||||
avg_system=sum(system_times) / len(system_times) if system_times else 0,
|
average_arrival_wait_time=sum(arrival_wait_times) / len(arrival_wait_times) if arrival_wait_times else 0,
|
||||||
p95_system=percentile(system_times, 95),
|
p95_arrival_wait_time=average_excluding_top_percent(arrival_wait_times, 5),
|
||||||
energy_total=sum(e.energy_consumed for e in self.elevators),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_events(self, since_tick: int = 0) -> List[SimulationEvent]:
|
def get_events(self, since_tick: int = 0) -> List[SimulationEvent]:
|
||||||
|
|||||||
Reference in New Issue
Block a user