FA-11946 / Discrete control systems / Open access
A setpoint step produces an unwanted derivative kick · case 01
A setpoint step produces an unwanted derivative kick.
ROOT CAUSE
The derivative uses error differences including setpoint changes.
VERIFIED REPAIR
Differentiate measurement with negative sign.
Unsuccessful approach: Suppressing derivative whenever the setpoint changes loses simultaneous measurement movement.
Case contract
Return the derivative contribution -gain*(measurement-previous_measurement) for unit sample time, independent of setpoint motion.
Why this case matters
An offline discrete controller model isolates this state or arithmetic fault; it makes no physical plant or safety claim.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(sp, old_sp, y, old_y, gain):
return gain*((sp-y)-(old_sp-old_y))
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('setpoint only', solve(N, 0, 0, 0, 2), 0)
check('both move', solve(N, 0, N, 0, 2), -2*N)
check('measurement rises', solve(0, 0, N, 0, 3), -3*N)
check('measurement falls', solve(0, 0, 0, N, 3), 3*N)
check('stationary', solve(N, N, N, N, 2), 0)
check('disabled gain', solve(N, 0, N, 0, 0), 0)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| setpoint only | 2 | 0 | Failed |
| both move | 0 | -2 | Failed |
| measurement rises | -3 | -3 | Passed |
| measurement falls | 3 | 3 | Passed |
| stationary | 0 | 0 | Passed |
| disabled gain | 0 | 0 | Passed |
SHA-256 / 05f1064264843596e7db4fd9ac4bf6ab960c181cba24701dd7fcad97e2c4a6ee
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(sp, old_sp, y, old_y, gain):
return 0 if sp != old_sp else -gain*(y-old_y)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('setpoint only', solve(N, 0, 0, 0, 2), 0)
check('both move', solve(N, 0, N, 0, 2), -2*N)
check('measurement rises', solve(0, 0, N, 0, 3), -3*N)
check('measurement falls', solve(0, 0, 0, N, 3), 3*N)
check('stationary', solve(N, N, N, N, 2), 0)
check('disabled gain', solve(N, 0, N, 0, 0), 0)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| setpoint only | 0 | 0 | Passed |
| both move | 0 | -2 | Failed |
| measurement rises | -3 | -3 | Passed |
| measurement falls | 3 | 3 | Passed |
| stationary | 0 | 0 | Passed |
| disabled gain | 0 | 0 | Passed |
SHA-256 / d509d4ed0dc1d219c1cd6766c54da5ac925a8c5c6df044c844dff1924c94d092
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(sp, old_sp, y, old_y, gain):
return -gain*(y-old_y)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('setpoint only', solve(N, 0, 0, 0, 2), 0)
check('both move', solve(N, 0, N, 0, 2), -2*N)
check('measurement rises', solve(0, 0, N, 0, 3), -3*N)
check('measurement falls', solve(0, 0, 0, N, 3), 3*N)
check('stationary', solve(N, N, N, N, 2), 0)
check('disabled gain', solve(N, 0, N, 0, 0), 0)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| setpoint only | 0 | 0 | Passed |
| both move | -2 | -2 | Passed |
| measurement rises | -3 | -3 | Passed |
| measurement falls | 3 | 3 | Passed |
| stationary | 0 | 0 | Passed |
| disabled gain | 0 | 0 | Passed |
SHA-256 / ec5a836357b1383910906369e5455109f4e31f71341c68f3c4b84fadde347b8f
Verification & scope
Integer-valued controlled examples only; no physical plant, stability guarantee, timing jitter, or hardware behavior is modeled. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:38:52.391774+00:00.
Case digest / b6125313a6f12f541fa194f01f83c31198657c9c45c9ded23b39ae83fb3456ab