deriva 0.0.15 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/docs/guide.md +1 -0
- package/examples/output/spacecraft-battery-diagnosis.pl +4 -0
- package/examples/proof/spacecraft-battery-diagnosis.pl +300 -0
- package/examples/spacecraft-battery-diagnosis.pl +79 -0
- package/package.json +1 -1
- package/playground.html +1 -0
- package/test/run-examples.mjs +1 -0
package/README.md
CHANGED
|
@@ -51,6 +51,22 @@ npm link
|
|
|
51
51
|
deriva --version
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
## STEM showcase: evidence-backed diagnosis
|
|
55
|
+
|
|
56
|
+
The spacecraft battery example combines sensor telemetry, the physical relation
|
|
57
|
+
`P = I²R`, engineering limits, redundant measurements, and causal rules to
|
|
58
|
+
derive a diagnosis and safety action:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node bin/deriva.js examples/spacecraft-battery-diagnosis.pl
|
|
62
|
+
node bin/deriva.js -p examples/spacecraft-battery-diagnosis.pl
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The normal output reports computed metrics, a thermal-runaway precursor, and an
|
|
66
|
+
`isolate_and_cool` action. With `-p`, every conclusion carries machine-readable
|
|
67
|
+
evidence back to telemetry facts, arithmetic operations, threshold comparisons,
|
|
68
|
+
and the independent temperature channel.
|
|
69
|
+
|
|
54
70
|
## JavaScript API
|
|
55
71
|
|
|
56
72
|
```js
|
package/docs/guide.md
CHANGED
|
@@ -479,6 +479,7 @@ Use `holds/2` when you want to match the member term directly, for example `name
|
|
|
479
479
|
| [`socket-age.pl`](../examples/socket-age.pl) | Shows socket-declared age reasoning inputs and plugs. | [`output/socket-age.pl`](../examples/output/socket-age.pl) |
|
|
480
480
|
| [`socket-family.pl`](../examples/socket-family.pl) | Shows socket-declared family-source inputs and ancestry rules. | [`output/socket-family.pl`](../examples/output/socket-family.pl) |
|
|
481
481
|
| [`socrates.pl`](../examples/socrates.pl) | Derives that Socrates is mortal. | [`output/socrates.pl`](../examples/output/socrates.pl) |
|
|
482
|
+
| [`spacecraft-battery-diagnosis.pl`](../examples/spacecraft-battery-diagnosis.pl) | Combines telemetry, resistive-heating physics, thresholds, and redundant sensing into an evidence-backed diagnosis and safety action. | [`output/spacecraft-battery-diagnosis.pl`](../examples/output/spacecraft-battery-diagnosis.pl) |
|
|
482
483
|
| [`stable-marriage.pl`](../examples/stable-marriage.pl) | Finds stable matchings by excluding blocking pairs. | [`output/stable-marriage.pl`](../examples/output/stable-marriage.pl) |
|
|
483
484
|
| [`statistics-summary.pl`](../examples/statistics-summary.pl) | Computes population statistics for a sample. | [`output/statistics-summary.pl`](../examples/output/statistics-summary.pl) |
|
|
484
485
|
| [`stirling-bell-numbers.pl`](../examples/stirling-bell-numbers.pl) | Computes Stirling numbers and Bell numbers. | [`output/stirling-bell-numbers.pl`](../examples/output/stirling-bell-numbers.pl) |
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
metric(bp1, thermal_margin_c, -18.0).
|
|
2
|
+
why(
|
|
3
|
+
metric(bp1, thermal_margin_c, -18.0),
|
|
4
|
+
proof(
|
|
5
|
+
goal(metric(bp1, thermal_margin_c, -18.0)),
|
|
6
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(14))),
|
|
7
|
+
bindings([binding("Pack", bp1), binding("Margin", -18.0), binding("Maximum", 60.0), binding("Temperature", 78.0)]),
|
|
8
|
+
uses([
|
|
9
|
+
proof(
|
|
10
|
+
goal(limit(max_safe_temperature_c, 60.0)),
|
|
11
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(10)))
|
|
12
|
+
),
|
|
13
|
+
proof(
|
|
14
|
+
goal(telemetry(bp1, temperature_c, 78.0)),
|
|
15
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(4)))
|
|
16
|
+
),
|
|
17
|
+
proof(
|
|
18
|
+
goal(sub(60.0, 78.0, -18.0)),
|
|
19
|
+
by(builtin(sub, 3))
|
|
20
|
+
)
|
|
21
|
+
])
|
|
22
|
+
)
|
|
23
|
+
).
|
|
24
|
+
|
|
25
|
+
metric(bp1, resistive_heating_w, 16.0).
|
|
26
|
+
why(
|
|
27
|
+
metric(bp1, resistive_heating_w, 16.0),
|
|
28
|
+
proof(
|
|
29
|
+
goal(metric(bp1, resistive_heating_w, 16.0)),
|
|
30
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(15))),
|
|
31
|
+
bindings([binding("Pack", bp1), binding("Heating", 16.0), binding("Current", 32.0), binding("Resistance", 0.015625), binding("CurrentSquared", 1024.0)]),
|
|
32
|
+
uses([
|
|
33
|
+
proof(
|
|
34
|
+
goal(telemetry(bp1, current_a, 32.0)),
|
|
35
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(6)))
|
|
36
|
+
),
|
|
37
|
+
proof(
|
|
38
|
+
goal(telemetry(bp1, internal_resistance_ohm, 0.015625)),
|
|
39
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(7)))
|
|
40
|
+
),
|
|
41
|
+
proof(
|
|
42
|
+
goal(mul(32.0, 32.0, 1024.0)),
|
|
43
|
+
by(builtin(mul, 3))
|
|
44
|
+
),
|
|
45
|
+
proof(
|
|
46
|
+
goal(mul(1024.0, 0.015625, 16.0)),
|
|
47
|
+
by(builtin(mul, 3))
|
|
48
|
+
)
|
|
49
|
+
])
|
|
50
|
+
)
|
|
51
|
+
).
|
|
52
|
+
|
|
53
|
+
diagnosis(bp1, thermal_runaway_precursor).
|
|
54
|
+
why(
|
|
55
|
+
diagnosis(bp1, thermal_runaway_precursor),
|
|
56
|
+
proof(
|
|
57
|
+
goal(diagnosis(bp1, thermal_runaway_precursor)),
|
|
58
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(21))),
|
|
59
|
+
bindings([binding("Pack", bp1)]),
|
|
60
|
+
uses([
|
|
61
|
+
proof(
|
|
62
|
+
goal(over_temperature(bp1)),
|
|
63
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(16))),
|
|
64
|
+
bindings([binding("Pack", bp1), binding("Temperature", 78.0), binding("Maximum", 60.0)]),
|
|
65
|
+
uses([
|
|
66
|
+
proof(
|
|
67
|
+
goal(telemetry(bp1, temperature_c, 78.0)),
|
|
68
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(4)))
|
|
69
|
+
),
|
|
70
|
+
proof(
|
|
71
|
+
goal(limit(max_safe_temperature_c, 60.0)),
|
|
72
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(10)))
|
|
73
|
+
),
|
|
74
|
+
proof(
|
|
75
|
+
goal(gt(78.0, 60.0)),
|
|
76
|
+
by(builtin(gt, 2))
|
|
77
|
+
)
|
|
78
|
+
])
|
|
79
|
+
),
|
|
80
|
+
proof(
|
|
81
|
+
goal(rapid_heating(bp1)),
|
|
82
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(17))),
|
|
83
|
+
bindings([binding("Pack", bp1), binding("Rate", 4.2), binding("Maximum", 1.5)]),
|
|
84
|
+
uses([
|
|
85
|
+
proof(
|
|
86
|
+
goal(telemetry(bp1, temperature_rise_c_per_min, 4.2)),
|
|
87
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(5)))
|
|
88
|
+
),
|
|
89
|
+
proof(
|
|
90
|
+
goal(limit(max_temperature_rise_c_per_min, 1.5)),
|
|
91
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(11)))
|
|
92
|
+
),
|
|
93
|
+
proof(
|
|
94
|
+
goal(gt(4.2, 1.5)),
|
|
95
|
+
by(builtin(gt, 2))
|
|
96
|
+
)
|
|
97
|
+
])
|
|
98
|
+
),
|
|
99
|
+
proof(
|
|
100
|
+
goal(cell_imbalance(bp1)),
|
|
101
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(18))),
|
|
102
|
+
bindings([binding("Pack", bp1), binding("Delta", 0.19), binding("Maximum", 0.08)]),
|
|
103
|
+
uses([
|
|
104
|
+
proof(
|
|
105
|
+
goal(telemetry(bp1, cell_delta_v, 0.19)),
|
|
106
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(8)))
|
|
107
|
+
),
|
|
108
|
+
proof(
|
|
109
|
+
goal(limit(max_cell_delta_v, 0.08)),
|
|
110
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(12)))
|
|
111
|
+
),
|
|
112
|
+
proof(
|
|
113
|
+
goal(gt(0.19, 0.08)),
|
|
114
|
+
by(builtin(gt, 2))
|
|
115
|
+
)
|
|
116
|
+
])
|
|
117
|
+
),
|
|
118
|
+
proof(
|
|
119
|
+
goal(heating_exceeds_cooling(bp1)),
|
|
120
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(19))),
|
|
121
|
+
bindings([binding("Pack", bp1), binding("Heating", 16.0), binding("Capacity", 12.0)]),
|
|
122
|
+
uses([
|
|
123
|
+
proof(
|
|
124
|
+
goal(metric(bp1, resistive_heating_w, 16.0)),
|
|
125
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(15))),
|
|
126
|
+
bindings([binding("Pack", bp1), binding("Heating", 16.0), binding("Current", 32.0), binding("Resistance", 0.015625), binding("CurrentSquared", 1024.0)]),
|
|
127
|
+
uses([
|
|
128
|
+
proof(
|
|
129
|
+
goal(telemetry(bp1, current_a, 32.0)),
|
|
130
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(6)))
|
|
131
|
+
),
|
|
132
|
+
proof(
|
|
133
|
+
goal(telemetry(bp1, internal_resistance_ohm, 0.015625)),
|
|
134
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(7)))
|
|
135
|
+
),
|
|
136
|
+
proof(
|
|
137
|
+
goal(mul(32.0, 32.0, 1024.0)),
|
|
138
|
+
by(builtin(mul, 3))
|
|
139
|
+
),
|
|
140
|
+
proof(
|
|
141
|
+
goal(mul(1024.0, 0.015625, 16.0)),
|
|
142
|
+
by(builtin(mul, 3))
|
|
143
|
+
)
|
|
144
|
+
])
|
|
145
|
+
),
|
|
146
|
+
proof(
|
|
147
|
+
goal(cooling_capacity_w(bp1, 12.0)),
|
|
148
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(13)))
|
|
149
|
+
),
|
|
150
|
+
proof(
|
|
151
|
+
goal(gt(16.0, 12.0)),
|
|
152
|
+
by(builtin(gt, 2))
|
|
153
|
+
)
|
|
154
|
+
])
|
|
155
|
+
)
|
|
156
|
+
])
|
|
157
|
+
)
|
|
158
|
+
).
|
|
159
|
+
|
|
160
|
+
action(bp1, isolate_and_cool).
|
|
161
|
+
why(
|
|
162
|
+
action(bp1, isolate_and_cool),
|
|
163
|
+
proof(
|
|
164
|
+
goal(action(bp1, isolate_and_cool)),
|
|
165
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(22))),
|
|
166
|
+
bindings([binding("Pack", bp1)]),
|
|
167
|
+
uses([
|
|
168
|
+
proof(
|
|
169
|
+
goal(diagnosis(bp1, thermal_runaway_precursor)),
|
|
170
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(21))),
|
|
171
|
+
bindings([binding("Pack", bp1)]),
|
|
172
|
+
uses([
|
|
173
|
+
proof(
|
|
174
|
+
goal(over_temperature(bp1)),
|
|
175
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(16))),
|
|
176
|
+
bindings([binding("Pack", bp1), binding("Temperature", 78.0), binding("Maximum", 60.0)]),
|
|
177
|
+
uses([
|
|
178
|
+
proof(
|
|
179
|
+
goal(telemetry(bp1, temperature_c, 78.0)),
|
|
180
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(4)))
|
|
181
|
+
),
|
|
182
|
+
proof(
|
|
183
|
+
goal(limit(max_safe_temperature_c, 60.0)),
|
|
184
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(10)))
|
|
185
|
+
),
|
|
186
|
+
proof(
|
|
187
|
+
goal(gt(78.0, 60.0)),
|
|
188
|
+
by(builtin(gt, 2))
|
|
189
|
+
)
|
|
190
|
+
])
|
|
191
|
+
),
|
|
192
|
+
proof(
|
|
193
|
+
goal(rapid_heating(bp1)),
|
|
194
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(17))),
|
|
195
|
+
bindings([binding("Pack", bp1), binding("Rate", 4.2), binding("Maximum", 1.5)]),
|
|
196
|
+
uses([
|
|
197
|
+
proof(
|
|
198
|
+
goal(telemetry(bp1, temperature_rise_c_per_min, 4.2)),
|
|
199
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(5)))
|
|
200
|
+
),
|
|
201
|
+
proof(
|
|
202
|
+
goal(limit(max_temperature_rise_c_per_min, 1.5)),
|
|
203
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(11)))
|
|
204
|
+
),
|
|
205
|
+
proof(
|
|
206
|
+
goal(gt(4.2, 1.5)),
|
|
207
|
+
by(builtin(gt, 2))
|
|
208
|
+
)
|
|
209
|
+
])
|
|
210
|
+
),
|
|
211
|
+
proof(
|
|
212
|
+
goal(cell_imbalance(bp1)),
|
|
213
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(18))),
|
|
214
|
+
bindings([binding("Pack", bp1), binding("Delta", 0.19), binding("Maximum", 0.08)]),
|
|
215
|
+
uses([
|
|
216
|
+
proof(
|
|
217
|
+
goal(telemetry(bp1, cell_delta_v, 0.19)),
|
|
218
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(8)))
|
|
219
|
+
),
|
|
220
|
+
proof(
|
|
221
|
+
goal(limit(max_cell_delta_v, 0.08)),
|
|
222
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(12)))
|
|
223
|
+
),
|
|
224
|
+
proof(
|
|
225
|
+
goal(gt(0.19, 0.08)),
|
|
226
|
+
by(builtin(gt, 2))
|
|
227
|
+
)
|
|
228
|
+
])
|
|
229
|
+
),
|
|
230
|
+
proof(
|
|
231
|
+
goal(heating_exceeds_cooling(bp1)),
|
|
232
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(19))),
|
|
233
|
+
bindings([binding("Pack", bp1), binding("Heating", 16.0), binding("Capacity", 12.0)]),
|
|
234
|
+
uses([
|
|
235
|
+
proof(
|
|
236
|
+
goal(metric(bp1, resistive_heating_w, 16.0)),
|
|
237
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(15))),
|
|
238
|
+
bindings([binding("Pack", bp1), binding("Heating", 16.0), binding("Current", 32.0), binding("Resistance", 0.015625), binding("CurrentSquared", 1024.0)]),
|
|
239
|
+
uses([
|
|
240
|
+
proof(
|
|
241
|
+
goal(telemetry(bp1, current_a, 32.0)),
|
|
242
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(6)))
|
|
243
|
+
),
|
|
244
|
+
proof(
|
|
245
|
+
goal(telemetry(bp1, internal_resistance_ohm, 0.015625)),
|
|
246
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(7)))
|
|
247
|
+
),
|
|
248
|
+
proof(
|
|
249
|
+
goal(mul(32.0, 32.0, 1024.0)),
|
|
250
|
+
by(builtin(mul, 3))
|
|
251
|
+
),
|
|
252
|
+
proof(
|
|
253
|
+
goal(mul(1024.0, 0.015625, 16.0)),
|
|
254
|
+
by(builtin(mul, 3))
|
|
255
|
+
)
|
|
256
|
+
])
|
|
257
|
+
),
|
|
258
|
+
proof(
|
|
259
|
+
goal(cooling_capacity_w(bp1, 12.0)),
|
|
260
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(13)))
|
|
261
|
+
),
|
|
262
|
+
proof(
|
|
263
|
+
goal(gt(16.0, 12.0)),
|
|
264
|
+
by(builtin(gt, 2))
|
|
265
|
+
)
|
|
266
|
+
])
|
|
267
|
+
)
|
|
268
|
+
])
|
|
269
|
+
),
|
|
270
|
+
proof(
|
|
271
|
+
goal(corroborated_over_temperature(bp1)),
|
|
272
|
+
by(rule("spacecraft-battery-diagnosis.pl", clause(20))),
|
|
273
|
+
bindings([binding("Pack", bp1), binding("Primary", 78.0), binding("Redundant", 76.0), binding("Maximum", 60.0)]),
|
|
274
|
+
uses([
|
|
275
|
+
proof(
|
|
276
|
+
goal(telemetry(bp1, temperature_c, 78.0)),
|
|
277
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(4)))
|
|
278
|
+
),
|
|
279
|
+
proof(
|
|
280
|
+
goal(redundant_telemetry(bp1, temperature_c, 76.0)),
|
|
281
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(9)))
|
|
282
|
+
),
|
|
283
|
+
proof(
|
|
284
|
+
goal(limit(max_safe_temperature_c, 60.0)),
|
|
285
|
+
by(fact("spacecraft-battery-diagnosis.pl", clause(10)))
|
|
286
|
+
),
|
|
287
|
+
proof(
|
|
288
|
+
goal(gt(78.0, 60.0)),
|
|
289
|
+
by(builtin(gt, 2))
|
|
290
|
+
),
|
|
291
|
+
proof(
|
|
292
|
+
goal(gt(76.0, 60.0)),
|
|
293
|
+
by(builtin(gt, 2))
|
|
294
|
+
)
|
|
295
|
+
])
|
|
296
|
+
)
|
|
297
|
+
])
|
|
298
|
+
)
|
|
299
|
+
).
|
|
300
|
+
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
% Evidence-backed spacecraft battery diagnosis.
|
|
2
|
+
%
|
|
3
|
+
% This compact engineering model combines telemetry, derived physical
|
|
4
|
+
% quantities, threshold checks, redundant sensing, diagnosis, and response.
|
|
5
|
+
% The values and limits are illustrative; they are not operational flight
|
|
6
|
+
% rules.
|
|
7
|
+
|
|
8
|
+
materialize(metric, 3).
|
|
9
|
+
materialize(diagnosis, 2).
|
|
10
|
+
materialize(action, 2).
|
|
11
|
+
|
|
12
|
+
% Primary telemetry for battery pack bp1.
|
|
13
|
+
telemetry(bp1, temperature_c, 78.0).
|
|
14
|
+
telemetry(bp1, temperature_rise_c_per_min, 4.2).
|
|
15
|
+
telemetry(bp1, current_a, 32.0).
|
|
16
|
+
telemetry(bp1, internal_resistance_ohm, 0.015625).
|
|
17
|
+
telemetry(bp1, cell_delta_v, 0.19).
|
|
18
|
+
|
|
19
|
+
% An independent temperature channel provides corroborating evidence.
|
|
20
|
+
redundant_telemetry(bp1, temperature_c, 76.0).
|
|
21
|
+
|
|
22
|
+
% Illustrative engineering limits and available cooling power.
|
|
23
|
+
limit(max_safe_temperature_c, 60.0).
|
|
24
|
+
limit(max_temperature_rise_c_per_min, 1.5).
|
|
25
|
+
limit(max_cell_delta_v, 0.08).
|
|
26
|
+
cooling_capacity_w(bp1, 12.0).
|
|
27
|
+
|
|
28
|
+
% Thermal margin is positive below the limit and negative above it.
|
|
29
|
+
metric(Pack, thermal_margin_c, Margin) :-
|
|
30
|
+
limit(max_safe_temperature_c, Maximum),
|
|
31
|
+
telemetry(Pack, temperature_c, Temperature),
|
|
32
|
+
sub(Maximum, Temperature, Margin).
|
|
33
|
+
|
|
34
|
+
% Resistive heating follows P = I^2 R.
|
|
35
|
+
metric(Pack, resistive_heating_w, Heating) :-
|
|
36
|
+
telemetry(Pack, current_a, Current),
|
|
37
|
+
telemetry(Pack, internal_resistance_ohm, Resistance),
|
|
38
|
+
mul(Current, Current, CurrentSquared),
|
|
39
|
+
mul(CurrentSquared, Resistance, Heating).
|
|
40
|
+
|
|
41
|
+
over_temperature(Pack) :-
|
|
42
|
+
telemetry(Pack, temperature_c, Temperature),
|
|
43
|
+
limit(max_safe_temperature_c, Maximum),
|
|
44
|
+
gt(Temperature, Maximum).
|
|
45
|
+
|
|
46
|
+
rapid_heating(Pack) :-
|
|
47
|
+
telemetry(Pack, temperature_rise_c_per_min, Rate),
|
|
48
|
+
limit(max_temperature_rise_c_per_min, Maximum),
|
|
49
|
+
gt(Rate, Maximum).
|
|
50
|
+
|
|
51
|
+
cell_imbalance(Pack) :-
|
|
52
|
+
telemetry(Pack, cell_delta_v, Delta),
|
|
53
|
+
limit(max_cell_delta_v, Maximum),
|
|
54
|
+
gt(Delta, Maximum).
|
|
55
|
+
|
|
56
|
+
heating_exceeds_cooling(Pack) :-
|
|
57
|
+
metric(Pack, resistive_heating_w, Heating),
|
|
58
|
+
cooling_capacity_w(Pack, Capacity),
|
|
59
|
+
gt(Heating, Capacity).
|
|
60
|
+
|
|
61
|
+
% Require two independent temperature channels above the same safety limit.
|
|
62
|
+
corroborated_over_temperature(Pack) :-
|
|
63
|
+
telemetry(Pack, temperature_c, Primary),
|
|
64
|
+
redundant_telemetry(Pack, temperature_c, Redundant),
|
|
65
|
+
limit(max_safe_temperature_c, Maximum),
|
|
66
|
+
gt(Primary, Maximum),
|
|
67
|
+
gt(Redundant, Maximum).
|
|
68
|
+
|
|
69
|
+
% A diagnosis needs multiple independent signatures, not one threshold alone.
|
|
70
|
+
diagnosis(Pack, thermal_runaway_precursor) :-
|
|
71
|
+
over_temperature(Pack),
|
|
72
|
+
rapid_heating(Pack),
|
|
73
|
+
cell_imbalance(Pack),
|
|
74
|
+
heating_exceeds_cooling(Pack).
|
|
75
|
+
|
|
76
|
+
% The safety action additionally requires redundant temperature corroboration.
|
|
77
|
+
action(Pack, isolate_and_cool) :-
|
|
78
|
+
diagnosis(Pack, thermal_runaway_precursor),
|
|
79
|
+
corroborated_over_temperature(Pack).
|
package/package.json
CHANGED
package/playground.html
CHANGED