141 lines
4.2 KiB
Markdown
141 lines
4.2 KiB
Markdown
TTE_SPEC_v1
|
|
|
|
```pseudocode
|
|
FUNCTION compute_tte(t_grid, V_term, z, Delta, V_cut):
|
|
// Constants
|
|
PRIORITY = { "DELTA_ZERO": 1, "V_CUTOFF": 2, "SOC_ZERO": 3 }
|
|
EPSILON = 1e-9
|
|
|
|
FOR k FROM 1 TO length(t_grid) - 1:
|
|
// Define event signals
|
|
gV_prev = V_term[k-1] - V_cut
|
|
gV_curr = V_term[k] - V_cut
|
|
gz_prev = z[k-1]
|
|
gz_curr = z[k]
|
|
gD_prev = Delta[k-1]
|
|
gD_curr = Delta[k]
|
|
|
|
candidates = []
|
|
|
|
// Check for crossings: g[k-1] > 0 and g[k] <= 0
|
|
IF gV_prev > 0 AND gV_curr <= 0:
|
|
denom = gV_curr - gV_prev
|
|
t_star_v = (denom == 0) ? t_grid[k] : t_grid[k-1] + (0 - gV_prev) * (t_grid[k] - t_grid[k-1]) / denom
|
|
candidates.push({ time: t_star_v, reason: "V_CUTOFF", priority: PRIORITY["V_CUTOFF"] })
|
|
|
|
IF gz_prev > 0 AND gz_curr <= 0:
|
|
denom = gz_curr - gz_prev
|
|
t_star_z = (denom == 0) ? t_grid[k] : t_grid[k-1] + (0 - gz_prev) * (t_grid[k] - t_grid[k-1]) / denom
|
|
candidates.push({ time: t_star_z, reason: "SOC_ZERO", priority: PRIORITY["SOC_ZERO"] })
|
|
|
|
IF gD_prev > 0 AND gD_curr <= 0:
|
|
denom = gD_curr - gD_prev
|
|
t_star_d = (denom == 0) ? t_grid[k] : t_grid[k-1] + (0 - gD_prev) * (t_grid[k] - t_grid[k-1]) / denom
|
|
candidates.push({ time: t_star_d, reason: "DELTA_ZERO", priority: PRIORITY["DELTA_ZERO"] })
|
|
|
|
IF length(candidates) > 0:
|
|
// Multi-event tie-breaking
|
|
winner = candidates[0]
|
|
FOR i FROM 1 TO length(candidates) - 1:
|
|
IF candidates[i].time < winner.time - EPSILON:
|
|
winner = candidates[i]
|
|
ELSE IF abs(candidates[i].time - winner.time) <= EPSILON:
|
|
IF candidates[i].priority < winner.priority:
|
|
winner = candidates[i]
|
|
|
|
t_star = winner.time
|
|
dt_step = t_grid[k] - t_grid[k-1]
|
|
alpha = (t_star - t_grid[k-1]) / dt_step
|
|
|
|
// Interpolate termination values
|
|
V_star = V_term[k-1] + alpha * (V_term[k] - V_term[k-1])
|
|
z_star = z[k-1] + alpha * (z[k] - z[k-1])
|
|
D_star = Delta[k-1] + alpha * (Delta[k] - Delta[k-1])
|
|
|
|
RETURN {
|
|
TTE_seconds: t_star - t_grid[0],
|
|
termination_reason: winner.reason,
|
|
termination_step_index: k,
|
|
termination_values: { V_term: V_star, z: z_star, Delta: D_star }
|
|
}
|
|
|
|
RETURN { TTE_seconds: null, termination_reason: "NO_EVENT_DETECTED" }
|
|
```
|
|
|
|
TESTS_v1
|
|
|
|
```json
|
|
{
|
|
"tests": [
|
|
{
|
|
"id": 1,
|
|
"description": "Voltage cutoff triggers",
|
|
"params": {
|
|
"V_cut": 3.0
|
|
},
|
|
"data": {
|
|
"t": [0.0, 10.0],
|
|
"V_term": [3.1, 2.8],
|
|
"z": [0.5, 0.4],
|
|
"Delta": [10.0, 9.0]
|
|
},
|
|
"expected": {
|
|
"TTE_seconds": 3.3333333333333335,
|
|
"termination_reason": "V_CUTOFF",
|
|
"termination_step_index": 1,
|
|
"termination_values": {
|
|
"V_term": 3.0,
|
|
"z": 0.4666666666666667,
|
|
"Delta": 9.666666666666666
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"id": 2,
|
|
"description": "SOC hits zero first",
|
|
"params": {
|
|
"V_cut": 3.0
|
|
},
|
|
"data": {
|
|
"t": [0.0, 10.0],
|
|
"V_term": [3.5, 3.4],
|
|
"z": [0.01, -0.02],
|
|
"Delta": [10.0, 9.0]
|
|
},
|
|
"expected": {
|
|
"TTE_seconds": 3.3333333333333335,
|
|
"termination_reason": "SOC_ZERO",
|
|
"termination_step_index": 1,
|
|
"termination_values": {
|
|
"V_term": 3.466666666666667,
|
|
"z": 0.0,
|
|
"Delta": 9.666666666666666
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"id": 3,
|
|
"description": "Delta hits zero first (power infeasible)",
|
|
"params": {
|
|
"V_cut": 3.0
|
|
},
|
|
"data": {
|
|
"t": [0.0, 10.0],
|
|
"V_term": [3.5, 3.4],
|
|
"z": [0.5, 0.4],
|
|
"Delta": [1.0, -2.0]
|
|
},
|
|
"expected": {
|
|
"TTE_seconds": 3.3333333333333335,
|
|
"termination_reason": "DELTA_ZERO",
|
|
"termination_step_index": 1,
|
|
"termination_values": {
|
|
"V_term": 3.466666666666667,
|
|
"z": 0.4666666666666667,
|
|
"Delta": 0.0
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
``` |