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 } } } ] } ```