Skip to content

Add relay contact switching delay with hard step resistance#289

Open
esaruoho wants to merge 3 commits intopfalstad:devfrom
esaruoho:fix-relay-contact-timing
Open

Add relay contact switching delay with hard step resistance#289
esaruoho wants to merge 3 commits intopfalstad:devfrom
esaruoho:fix-relay-contact-timing

Conversation

@esaruoho
Copy link
Copy Markdown

@esaruoho esaruoho commented Mar 3, 2026

Summary

  • RelayCoilElm keeps the configurable switching time delay (states 1 and 3 in the state machine wait for the configured time before transitioning). But d_position is now binary (0 or 1), snapping to the new value only when the delay expires and switchPosition actually changes. This models real relay behavior: armature travel time followed by an abrupt contact state change.
  • Separate Release Time: Normal and Latching relay types now have an independent Release Time parameter. Real relays release faster than they engage because the spring force assists the armature return. When Release Time is 0 (default), it falls back to the Switching Time for backwards compatibility.
  • RelayContactElm resistance is always either r_on (closed) or r_off (open), never intermediate. The hard step produces realistic inductive voltage spikes when relay contacts open (e.g. >500V with 7H coil inductance), matching measured behavior with real relays.
  • MotorProtectionSwitchElm unchanged (already passes binary d_position for instant transitions).
  • setSwitchPositions() is now only called when the position actually changes, not on every tick during the delay period, improving simulation performance.

Rationale (based on community feedback): Real relay contacts have a delay (armature/contact travel time) followed by a hard step in contact resistance. Smooth interpolation was suppressing realistic inductive voltage spikes and adding unnecessary computation. Real relays also release faster than they engage due to spring-assisted armature return; the separate Release Time parameter models this asymmetry. See feedback from @MatNieuw.

Addresses sharpie7#983.

Test plan

  • Place a relay coil and linked relay contacts (NO and NC), verify contacts snap between on/off after the configured switching delay
  • Verify inductive voltage spikes occur when a relay driving an inductive load (e.g. another relay coil) is de-energized
  • Verify built-in RelayElm still works correctly (not changed)
  • Test on-delay relay: contacts should snap on after delay, snap back instantly on release
  • Test off-delay relay: contacts should snap on instantly, snap off after delay on release
  • Test latching relay: contacts should snap on each toggle after delay, hold position when de-energized
  • Test motor protection switch with linked contacts: instant switching preserved
  • Verify NC contacts invert correctly (closed at rest, opens on energize)
  • Verify reset behavior: contacts return to correct rest position
  • Test Release Time: set Release Time shorter than Switching Time, verify contacts open faster than they close
  • Verify Release Time field only appears for Normal and Latching types
  • Verify backwards compatibility: circuits without Release Time attribute load correctly (defaults to Switching Time)

@MatNieuw
Copy link
Copy Markdown

MatNieuw commented Mar 3, 2026

The smooth interpolation does not reflect real relay contact behaviour. If one relay controls a second relay and the first relay is de-energized, I expect (without extra circuitry over the coil of the second relay) a large voltage spike on the coil of the second relay. Measuring with HK19F-24V relays, coil self-inductance 7H and coil resistance 2880 ohm, 6 sm switch time, I measured spikes well over 500 V.
In addition, won´t this slow down simulation? If there is a hard step function, then for most of the switching time there won't be any changes, I assume this then is quicker to suimulate.

@esaruoho esaruoho changed the title Smooth relay contact resistance during switching transition Add relay contact switching delay with hard step resistance Mar 3, 2026
@esaruoho
Copy link
Copy Markdown
Author

esaruoho commented Mar 3, 2026

@MatNieuw Thank you for this excellent feedback! You're absolutely right on both counts.

Voltage spikes: Real relay contacts have a delay (armature travel time) followed by an abrupt open/close. The smooth resistance interpolation was suppressing the very inductive voltage spikes that make relay behavior interesting and important to simulate correctly. With your HK19F-24V example (7H coil, 2880 ohm, 6ms switch time), the >500V spikes are exactly what should happen when the contact resistance jumps from near-zero to megaohms — not a gentle ramp that lets the inductor current decay gradually.

Simulation performance: You're also right that the smooth ramp was calling setSwitchPositions() on every simulation tick during the entire switching delay, even though the gradual resistance change added no value. With the hard step, setSwitchPositions() is only called once when the position actually changes.

I've updated the PR to use a hard step:

  • The switching time delay is preserved (the relay still waits the configured time before switching)
  • But d_position is now binary (0 or 1) — it stays at the old value during the delay, then snaps to the new value when the delay expires
  • Contact resistance is always either r_on or r_off, never intermediate
  • setSwitchPositions() is only called when position actually changes

This should now produce the realistic inductive spikes you'd expect.

@MatNieuw
Copy link
Copy Markdown

MatNieuw commented Mar 3, 2026 via email

@esaruoho
Copy link
Copy Markdown
Author

esaruoho commented Mar 3, 2026

@MatNieuw Thank you for the detailed analysis of asymmetric relay timing! You're right that the previous update was incomplete.

What the model already handles:

  • The coil inductance means current builds up slowly (L/R time constant) but collapses faster when the driving source is removed
  • Separate on/off current thresholds (default 20 mA / 15 mA, configurable) -- so the relay starts releasing sooner because the lower off-current threshold is reached faster during collapse
  • These two effects together already create inherently faster release than engage, even with identical mechanical switching times

What is new in this update -- separate Release Time:
The mechanical armature travel time is also asymmetric in real relays (spring-assisted return). I have added a Release Time parameter to RelayCoilElm:

  • Shown in the edit dialog for Normal and Latching relay types
  • Defaults to the Switching Time value (backwards compatible)
  • When set to a shorter value, the relay contacts open faster than they close
  • Combined with the inductor + lower off-current threshold, this gives full control over the timing asymmetry

For your HK19F relay example (6.3 mA on / 0.8 mA off), you could set:

  • On Current: 6.3 mA
  • Off Current: 0.8 mA
  • Switching Time: 2.5 ms (engage travel)
  • Release Time: ~1 ms (faster spring-assisted return)

This would give realistic break-before-make behavior where relay A releases well before relay B engages.

@MatNieuw
Copy link
Copy Markdown

MatNieuw commented Mar 3, 2026

Looks very good. I'll test it after Paul has merged this PR.

@Joerg-rw
Copy link
Copy Markdown

Joerg-rw commented Mar 3, 2026

unclear to me if there's a travel time now in which neither the NO nor the NC contact are closed (let aside contact bouncing). I'd think this should exactly be the switching time

@MatNieuw
Copy link
Copy Markdown

MatNieuw commented Mar 3, 2026

Travel time is specified from when the nominal voltage is applied until the NO contact is closed inclusive bounce, therefore it includes the time to build up the current/magnetic field, not just the actual travel time between NC and NO.

@Joerg-rw
Copy link
Copy Markdown

Joerg-rw commented Mar 3, 2026

@MatNieuw The travel time in the sim model starts when coil current trips the threshold. This is correct for a sim, if your relay data sheets specs cite some other composite value, you need to do the math on your own.
switching moment, contact to neither endpoint
The interpolation between contact on and contact off must get fixed, there's no such thing in a real relay - however the relay contact moving between NO endpoint and NC endpoint is ok, how fast it moves through this "neither NO nor NC" state is depending on the switching time

@esaruoho esaruoho changed the base branch from v3-dev to dev April 15, 2026 09:50
esaruoho and others added 3 commits April 15, 2026 13:30
Relay contacts (RelayContactElm) now interpolate resistance smoothly
over the switching time instead of snapping instantly between r_on and
r_off.  The coil (RelayCoilElm) computes a fractional d_position that
ramps linearly during state transitions, and passes it to linked
contacts via setPosition().  Each contact derives its own fractional
position (accounting for normally-closed inversion) and uses:

  resistance = r_on + (r_off - r_on) * d_position

This gives a smooth visual and electrical transition matching the
built-in relay behavior.  Latching relay direction and motor
protection switch instant-switching are handled correctly.

Addresses sharpie7#983.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…ation

Based on community feedback from @MatNieuw: real relay contacts have a
delay (armature travel time) followed by an abrupt open/close, not a
smooth resistance ramp. The smooth interpolation was suppressing
realistic inductive voltage spikes (e.g. >500V when de-energizing a
relay coil with 7H inductance) and adding unnecessary per-tick
computation during the delay period.

The switching time delay is preserved (states 1 and 3 still wait for
the configured time before changing switchPosition), but d_position is
now binary (0 or 1) and resistance snaps between r_on and r_off.
setSwitchPositions() is only called when the position actually changes.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Real relays release faster than they engage because the spring force
assists the armature return.  Add a configurable Release Time parameter
(shown for Normal and Latching relay types) so users can model this
asymmetry.  When Release Time is 0 (default), it falls back to the
Switching Time for backwards compatibility.

Based on feedback from @MatNieuw with measured HK19F relay behavior.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@esaruoho esaruoho force-pushed the fix-relay-contact-timing branch from f2c6ddd to 907576a Compare April 15, 2026 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants