Skip to content

Commit 416ff57

Browse files
esaruohoclaude
andcommitted
Require sustained coil current before relay switches (#67)
Brief back-EMF transients from one relay coil could incorrectly trigger another relay because the model switched instantly when current crossed the threshold. Now the coil current must remain above/below the on/off threshold for at least half the switching time before the relay starts moving, matching real relay inertia. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7755622 commit 416ff57

File tree

1 file changed

+26
-8
lines changed

1 file changed

+26
-8
lines changed

src/com/lushprojects/circuitjs1/client/RelayElm.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ class RelayElm extends CircuitElm {
6161
int poleCount;
6262
int openhs, dflip;
6363
boolean onState;
64+
65+
// track time current has been above/below threshold to filter transients
66+
double onThresholdTime, offThresholdTime;
6467
final int nSwitch0 = 0;
6568
final int nSwitch1 = 1;
6669
final int nSwitch2 = 2;
@@ -331,6 +334,7 @@ void reset() {
331334
for (i = 0; i != poleCount; i++)
332335
switchCurrent[i] = switchCurCount[i] = 0;
333336
d_position = i_position = 0;
337+
onThresholdTime = offThresholdTime = 0;
334338

335339
// preserve onState because if we don't, Relay Flip-Flop gets left in a weird state on reset.
336340
// onState = false;
@@ -355,30 +359,44 @@ void startIteration() {
355359
}
356360
ind.startIteration(volts[nCoil1]-volts[nCoil3]);
357361
double absCurrent = Math.abs(coilCurrent);
358-
362+
363+
// require current to be sustained above/below threshold for a minimum
364+
// time before switching, to filter brief transients like back-EMF spikes
365+
double minHoldTime = switchingTime * 0.5;
366+
359367
if (onState) {
360368
// on or turning on. check if we need to turn off
361369
if (absCurrent < offCurrent) {
362-
// turning off, set switch to intermediate position
363-
onState = false;
364-
i_position = 2;
370+
offThresholdTime += sim.timeStep;
371+
onThresholdTime = 0;
372+
if (offThresholdTime >= minHoldTime) {
373+
// turning off, set switch to intermediate position
374+
onState = false;
375+
i_position = 2;
376+
}
365377
} else {
378+
offThresholdTime = 0;
366379
d_position += sim.timeStep/switchingTime;
367380
if (d_position >= 1)
368381
d_position = i_position = 1;
369382
}
370383
} else {
371384
// off or turning off. check if we need to turn on
372385
if (absCurrent > onCurrent) {
373-
// turning on, set switch to intermediate position
374-
onState = true;
375-
i_position = 2;
386+
onThresholdTime += sim.timeStep;
387+
offThresholdTime = 0;
388+
if (onThresholdTime >= minHoldTime) {
389+
// turning on, set switch to intermediate position
390+
onState = true;
391+
i_position = 2;
392+
}
376393
} else {
394+
onThresholdTime = 0;
377395
d_position -= sim.timeStep/switchingTime;
378396
if (d_position <= 0)
379397
d_position = i_position = 0;
380398
}
381-
399+
382400
}
383401
}
384402

0 commit comments

Comments
 (0)