File size: 2,994 Bytes
ebd57ea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import numpy as np


def process_inputs(X: np.ndarray) -> np.ndarray:
    """Convert inputs from natural units to normalized model inputs.

    Index | Name                  | Natural unit | Notes
    ------|-----------------------|--------------|--------------------------------
    0     | ambient_temperature_c | °C           | Kelvin ratio — never 0
    1     | build_chamber_temp_c  | °C           | Kelvin ratio — never 0
    2     | ambient_humidity_pct  | %            | floor 0.25 — dry air still allows degradation
    3     | powder_contamination  | AQI [0–500]  | floor 0.15 — even clean air causes wear
    4     | print_hours           | h            | 0 → 0 (machine not running)
    5     | build_volume_cm3      | cm³          | 0 → 0 (no active build)
    6     | recoating_speed_mm_s  | mm/s         | 0 → 0 (recoater stationary)
    7     | recoating_cycles      | count        | 0 → 0 (no recoating done)
    8     | maintenance_level     | [0, 1]       | floor 0.2 — even perfect maintenance
          |                       |              | cannot eliminate physical wear

    The model uses P = ∏ I_c; only a 0 output produces P = 0 (no degradation).
    Inputs whose zero value merely means "minimal stress" (temperatures, humidity,
    contamination, maintenance) carry a non-zero floor so they never falsely gate
    off all degradation.  Inputs that are truly "off" when zero (machine not
    running, recoater stationary) map 0 → 0.

    All outputs are non-negative.  The mapping is linear throughout.
    """
    X = np.asarray(X, dtype=float)
    out = np.empty(9)

    # --- Temperatures: T_K / T_ref (Kelvin ratio, never 0 above absolute zero) ---
    # Reference points chosen so the maximum expected operating temperature ≈ 1.0.
    # Ambient reference: 70 °C = 343.15 K  (factory floor upper bound)
    # Chamber reference: 350 °C = 623.15 K (upper bound for powder-bed processes)
    out[0] = (np.maximum(X[0], -273.15) + 273.15) / 343.15
    out[1] = (np.maximum(X[1], -273.15) + 273.15) / 623.15

    # --- Humidity: non-zero floor, linear ---
    # floor=0.25 at 0 %, reaching 1.0 at 100 %.
    out[2] = 0.25 + 0.75 * np.clip(X[2], 0.0, 100.0) / 100.0

    # --- Powder contamination (AQI 0–500): non-zero floor, linear ---
    # floor=0.15 at AQI=0; reaches 1.0 at AQI=500.
    out[3] = 0.15 + 0.85 * np.clip(X[3], 0.0, 500.0) / 500.0
    out[4] = np.clip(X[4], 0.0, 168.0)   / 168.0    # print hours  (max 168 h/week)
    out[5] = np.clip(X[5], 0.0, 15000.0) / 15000.0  # build volume (max 15 000 cm³/week)
    out[6] = np.clip(X[6], 0.0, 150.0)   / 150.0    # recoating speed (max 150 mm/s)
    out[7] = np.clip(X[7], 0.0, 15000.0) / 15000.0  # recoating cycles (max 15 000/week)

    # --- Maintenance: non-zero floor, linear ---
    # level=0 (perfect) → 0.2 baseline; level=1 (no maintenance) → 1.0.
    out[8] = 0.2 + 0.8 * np.clip(X[8], 0.0, 1.0)

    return np.maximum(out, 0.0)  # guarantee non-negative