SAFETY-136 round 2: tests for override and direction, true wording
F1 the on-change case is tested as slow, F2 override and direction checks, F3 the 3.75 s rule in the texts, F4 the quarter figures and the live note. No behaviour change. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,7 @@ limit of SAFETY-128's fast meter fit). It counts arrivals, not changes of
|
|||||||
value: on the recorded day at 1-2 s the value-based test (`MeterFit.slow()`)
|
value: on the recorded day at 1-2 s the value-based test (`MeterFit.slow()`)
|
||||||
called 24 % of the cycles slow, because the recorded house repeats a value
|
called 24 % of the cycles slow, because the recorded house repeats a value
|
||||||
for 5 s or more, and the commands then differed from base. So there is no
|
for 5 s or more, and the commands then differed from base. So there is no
|
||||||
option. At a 1-3 s meter it is false, the tuning is never touched and the
|
option. At a meter with a usual gap of 3.75 s or less (1-3 s) it is false, the tuning is never touched and the
|
||||||
commands are those of the tree before. A meter that Home Assistant passes on
|
commands are those of the tree before. A meter that Home Assistant passes on
|
||||||
only when its value changes looks as slow as its changes are far apart, as it
|
only when its value changes looks as slow as its changes are far apart, as it
|
||||||
does to SAFETY-128's fits: a 1-2 s meter with a value that holds for 5 s or
|
does to SAFETY-128's fits: a 1-2 s meter with a value that holds for 5 s or
|
||||||
@@ -63,10 +63,18 @@ from base. Together their export is 10 363 -> 9 559 Wh (-8 %) and import
|
|||||||
8 389 -> 7 835 Wh (-7 %). Only 5 export more than 1 Wh and 14 import more:
|
8 389 -> 7 835 Wh (-7 %). Only 5 export more than 1 Wh and 14 import more:
|
||||||
export by at most 11.5 Wh (a 10 s battery lag, +10 %), import by at most
|
export by at most 11.5 Wh (a 10 s battery lag, +10 %), import by at most
|
||||||
17 Wh (a 12 s dead time, one inverter, +7 %), and the quarter average by at
|
17 Wh (a 12 s dead time, one inverter, +7 %), and the quarter average by at
|
||||||
most 35 W, once 73 W (10 s meter, 10 s dead time, export -59 Wh). Slow
|
most 35 W, except two import quarters: +73 W (10 s meter, 10 s dead time,
|
||||||
|
export -59 Wh) and +40 W (`dead10_p6`, -6 to 34 W, export -68 Wh). Slow
|
||||||
batteries with a dead time of 8-10 s export 5-39 % less; a 12 s dead time is
|
batteries with a dead time of 8-10 s export 5-39 % less; a 12 s dead time is
|
||||||
the same. `READINGS_LATE` holds are the same seconds in every run.
|
the same. `READINGS_LATE` holds are the same seconds in every run.
|
||||||
|
|
||||||
|
**Live, a 1-2 s meter can be judged slow.** Through Home Assistant on change,
|
||||||
|
a value that holds for 4-10 s makes a 1 s meter slow. In 20 rig scenarios the
|
||||||
|
commands were those of base. On the recorded day (1 s, N=1, 1 day, repeats
|
||||||
|
dropped; its values hold about 5 s) it was slow in 33 % of cycles, half gain
|
||||||
|
in 83 cycles, 15 422 commands in both trees, 4 016 with another value (at
|
||||||
|
most 190 W apart), cost 0.61 EUR in both (review of SAFETY-136).
|
||||||
|
|
||||||
**Does not change.** Meters of 1-2 s: the same commands in all 63 runs (34
|
**Does not change.** Meters of 1-2 s: the same commands in all 63 runs (34
|
||||||
at 1 s, 29 at 2 s), and the recorded-day digests (see the report). The late
|
at 1 s, 29 at 2 s), and the recorded-day digests (see the report). The late
|
||||||
verdict, the hold and the freeze tests. 15 s late is only partly helped, and
|
verdict, the hold and the freeze tests. 15 s late is only partly helped, and
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
"""SAFETY-136: on a slow meter, follow the meter gently until the last move shows.
|
"""SAFETY-136: on a slow meter, follow the meter gently until the last move shows.
|
||||||
|
|
||||||
A meter whose readings come 4 s or more apart, read through Home Assistant, can
|
A meter whose usual gap between readings is over 3.75 s (a 4-5 s meter), read
|
||||||
be 10-15 s late. The loop then answers the same error again at each cycle
|
through Home Assistant, can be 10-15 s late. The loop then answers the same error again at each cycle
|
||||||
and overshoots. After a move of MOVE_W or more the loop therefore runs at
|
and overshoots. After a move of MOVE_W or more the loop therefore runs at
|
||||||
WAIT_SHARE of its gain until the meter has fallen SHOWN of the move, or for at
|
WAIT_SHARE of its gain until the meter has fallen SHOWN of the move, or for at
|
||||||
most WAIT_CYCLES cycles. Off for a meter under 4 s, so those sites run as
|
most WAIT_CYCLES cycles. Off for a meter with a usual gap of 3.75 s or less, so those sites run as
|
||||||
before. DECISIONS/SAFETY-136-slow-meter-settle.md.
|
before. DECISIONS/SAFETY-136-slow-meter-settle.md.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,14 @@ check("the meter fell 200 W of 600 W: still half the gain",
|
|||||||
check("two cycles waited: the third has the whole gain",
|
check("two cycles waited: the third has the whole gain",
|
||||||
s.tuning(T, 300.0, True) is T and s.pend is None)
|
s.tuning(T, 300.0, True) is T and s.pend is None)
|
||||||
s.moved(500.0, 0.0, 600.0, True)
|
s.moved(500.0, 0.0, 600.0, True)
|
||||||
|
check("the meter went the other way by half the move: the wait stands",
|
||||||
|
s.tuning(T, 800.0, True).gain == T.gain * 0.5)
|
||||||
|
s.reset()
|
||||||
|
s.moved(500.0, 0.0, -600.0, True)
|
||||||
|
check("a move down, the meter rose half the move: the whole gain",
|
||||||
|
s.tuning(T, 800.0, True) is T)
|
||||||
|
s.reset()
|
||||||
|
s.moved(500.0, 0.0, 600.0, True)
|
||||||
check("the meter fell half the move: the whole gain at once",
|
check("the meter fell half the move: the whole gain at once",
|
||||||
s.tuning(T, 200.0, True) is T and s.pend is None)
|
s.tuning(T, 200.0, True) is T and s.pend is None)
|
||||||
s.moved(500.0, 0.0, -600.0, True)
|
s.moved(500.0, 0.0, -600.0, True)
|
||||||
@@ -148,6 +156,38 @@ print(f" sum: {tot_on:.1f} Wh, off {tot_off:.1f} Wh")
|
|||||||
check("the four together export at most 65 % of the run with it off",
|
check("the four together export at most 65 % of the run with it off",
|
||||||
tot_on <= 0.65 * tot_off)
|
tot_on <= 0.65 * tot_off)
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
print("\n2b. Another writer overrides the loop: the wait ends")
|
||||||
|
halved = []
|
||||||
|
real_tuning = settle.Settle.tuning
|
||||||
|
|
||||||
|
|
||||||
|
def watch_tuning(self, tuning, grid_w, slow):
|
||||||
|
r = real_tuning(self, tuning, grid_w, slow)
|
||||||
|
halved.append(r is not tuning)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
settle.Settle.tuning = watch_tuning
|
||||||
|
try:
|
||||||
|
mark = []
|
||||||
|
|
||||||
|
def bump(rig, c, t):
|
||||||
|
# right after a cycle that started a wait, another writer moves the
|
||||||
|
# command, so the next cycle sees `target != loop_w`
|
||||||
|
if not mark and c.settle.pend and t > 330.0:
|
||||||
|
mark.append(len(halved))
|
||||||
|
c.target = c.target + 300.0
|
||||||
|
|
||||||
|
r = R.Rig(house=oven, noise=80.0, p1_s=5.0, lag_s=10.0, lag_on=ON,
|
||||||
|
lag_off=900.0)
|
||||||
|
r.run(500.0, bump)
|
||||||
|
finally:
|
||||||
|
settle.Settle.tuning = real_tuning
|
||||||
|
nxt = nth(halved, mark[0] if mark else 10 ** 6)
|
||||||
|
check("the cycle after an override has the whole gain",
|
||||||
|
bool(mark) and present(nxt) and nxt is False)
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
print("\n3. 5 s meter, no lag")
|
print("\n3. 5 s meter, no lag")
|
||||||
for name in ("oven", "kettle", "step", "stepup"):
|
for name in ("oven", "kettle", "step", "stepup"):
|
||||||
@@ -202,15 +242,19 @@ for p1, expect in ((1.0, False), (2.0, False), (3.0, False), (4.0, True),
|
|||||||
last = nth(seen, -1)
|
last = nth(seen, -1)
|
||||||
check(f"{p1:.0f} s meter: slow is {expect}",
|
check(f"{p1:.0f} s meter: slow is {expect}",
|
||||||
present(last) and last is expect)
|
present(last) and last is expect)
|
||||||
# A 1 s meter on a house that changes every 5 s repeats its value 4 times in 5:
|
# A 1 s meter on a house that changes every 5 s repeats its value 4 times in 5.
|
||||||
# the fit that counts changed values calls that slow, the readings do not (the
|
# Where every reading arrives (the rig, a polled meter) it is not slow; where
|
||||||
# recorded day at 1-2 s showed it).
|
# Home Assistant sends a reading only when the value changes (ha_signed) the
|
||||||
s, m = settle.Settle(), MeterFit()
|
# same meter is slow (T3 of the review; DECISIONS).
|
||||||
|
s, m, h = settle.Settle(), MeterFit(), settle.Settle()
|
||||||
for k in range(60):
|
for k in range(60):
|
||||||
s.arrive(float(k), k)
|
s.arrive(float(k), k)
|
||||||
|
h.arrive(float(k), k // 5)
|
||||||
m.add(float(k), 0.0, 1800.0 + 100.0 * (k // 5))
|
m.add(float(k), 0.0, 1800.0 + 100.0 * (k // 5))
|
||||||
check("a 1 s meter whose value changes every 5 s: not slow, though its value "
|
check("every reading arrives, value changes every 5 s: not slow (the value "
|
||||||
"repeats", not s.slow() and m.slow())
|
"fit says slow)", not s.slow() and m.slow())
|
||||||
|
check("the same meter through Home Assistant on change (a reading per "
|
||||||
|
"change): slow", h.slow())
|
||||||
|
|
||||||
print()
|
print()
|
||||||
if fails:
|
if fails:
|
||||||
|
|||||||
Reference in New Issue
Block a user