|
@@ -13,25 +13,40 @@ All source is ASCII.
|
|
|
from __future__ import annotations
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
import math
|
|
import math
|
|
|
|
|
+import os
|
|
|
|
|
+import sys
|
|
|
from typing import Any
|
|
from typing import Any
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ---------------------------------------------------------------------------
|
|
|
# Metric definitions (for display and analysis)
|
|
# Metric definitions (for display and analysis)
|
|
|
# ---------------------------------------------------------------------------
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
+# Single source of truth: src/afmcore/metrics.py METRIC_DEFINITIONS. This
|
|
|
|
|
+# module must NOT keep its own copy (historical drift: an 11-metric
|
|
|
|
|
+# electromagnetic-only list silently dropped thermal + structural metrics).
|
|
|
|
|
+# Make src/afmcore importable, then derive the display dict below.
|
|
|
|
|
+
|
|
|
|
|
+_ANALYTICS_DIR = os.path.dirname(
|
|
|
|
|
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
|
+)
|
|
|
|
|
+# web/backend/app/services/analytics.py -> <repo>/src
|
|
|
|
|
+_SRC_DIR = os.path.normpath(os.path.join(_ANALYTICS_DIR, "..", "..", "src"))
|
|
|
|
|
+if _SRC_DIR not in sys.path and os.path.isdir(_SRC_DIR):
|
|
|
|
|
+ sys.path.insert(0, _SRC_DIR)
|
|
|
|
|
+
|
|
|
|
|
+from afmcore.metrics import METRIC_DEFINITIONS # noqa: E402
|
|
|
|
|
+
|
|
|
|
|
+# direction "neutral" maps to True to preserve the historical pareto behavior
|
|
|
|
|
+# (neutral metrics are not optimization targets but were never excluded here).
|
|
|
|
|
+_DIRECTION_TO_BETTER = {"higher": True, "lower": False, "neutral": True}
|
|
|
|
|
|
|
|
METRIC_DEFS = {
|
|
METRIC_DEFS = {
|
|
|
- "tavg_nm": {"label": "Average Torque", "unit": "Nm", "higher_is_better": True},
|
|
|
|
|
- "ripple_pct": {"label": "Torque Ripple", "unit": "%", "higher_is_better": False},
|
|
|
|
|
- "efficiency_pct": {"label": "Efficiency", "unit": "%", "higher_is_better": True},
|
|
|
|
|
- "total_losses_w": {"label": "Total Losses", "unit": "W", "higher_is_better": False},
|
|
|
|
|
- "copper_loss_w": {"label": "Copper Loss", "unit": "W", "higher_is_better": False},
|
|
|
|
|
- "iron_loss_w": {"label": "Iron Loss", "unit": "W", "higher_is_better": False},
|
|
|
|
|
- "magnet_loss_w": {"label": "Magnet Loss", "unit": "W", "higher_is_better": False},
|
|
|
|
|
- "back_emf_v": {"label": "Back EMF", "unit": "V", "higher_is_better": True},
|
|
|
|
|
- "output_power_w": {"label": "Output Power", "unit": "W", "higher_is_better": True},
|
|
|
|
|
- "input_power_w": {"label": "Input Power", "unit": "W", "higher_is_better": True},
|
|
|
|
|
- "no_load_speed_rpm": {"label": "No-Load Speed", "unit": "rpm", "higher_is_better": True},
|
|
|
|
|
|
|
+ m["key"]: {
|
|
|
|
|
+ "label": m["label"],
|
|
|
|
|
+ "unit": m["unit"],
|
|
|
|
|
+ "higher_is_better": _DIRECTION_TO_BETTER.get(m.get("direction"), True),
|
|
|
|
|
+ }
|
|
|
|
|
+ for m in METRIC_DEFINITIONS
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|