-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FIX: ensure np.interp gets an increasing sequence in LUTs #1282
Changes from all commits
e6a10fa
8babfea
120a573
97820c4
a8362b0
260f47e
3946143
3eb5b83
7799050
1a6f120
50b3686
8aa11e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
1282 fix_decr_lut | ||
################# | ||
|
||
API Breaks | ||
---------- | ||
- N/A | ||
|
||
Library Features | ||
---------------- | ||
- N/A | ||
|
||
Device Features | ||
--------------- | ||
- N/A | ||
|
||
New Devices | ||
----------- | ||
- N/A | ||
|
||
Bugfixes | ||
-------- | ||
- Fix an issue where the LookupTablePositioner would fail silently if the | ||
lookup table was not strictly increasing in both axes. | ||
Lookup tables that are strictly decreasing in either axis | ||
will now be supported. | ||
Lookup tables that have inconsistent ordering in either axis will | ||
log a warning when the conversion is done. | ||
|
||
Maintenance | ||
----------- | ||
- N/A | ||
|
||
Contributors | ||
------------ | ||
- zllentz |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ | |
|
||
from ..pseudopos import (DelayBase, LookupTablePositioner, OffsetMotorBase, | ||
PseudoSingleInterface, SimDelayStage, SyncAxesBase, | ||
SyncAxis, SyncAxisOffsetMode) | ||
SyncAxis, SyncAxisOffsetMode, is_strictly_increasing) | ||
from ..sim import FastMotor | ||
|
||
logger = logging.getLogger(__name__) | ||
|
@@ -190,8 +190,19 @@ def test_subcls_warning(): | |
OffsetMotorBase('prefix', name='name') | ||
|
||
|
||
def test_lut_positioner(): | ||
logger.debug('test_lut_positioner') | ||
@pytest.mark.parametrize( | ||
"real_sign,pseudo_sign", | ||
( | ||
(1, 1), | ||
(1, -1), | ||
(-1, 1), | ||
(-1, -1), | ||
) | ||
) | ||
def test_lut_positioner(real_sign: bool, pseudo_sign: bool): | ||
logger.debug('test_lut_positioner_normal') | ||
rs = real_sign | ||
ps = pseudo_sign | ||
|
||
class LimitSettableSoftPositioner(SoftPositioner): | ||
@property | ||
|
@@ -206,6 +217,7 @@ class MyLUTPositioner(LookupTablePositioner): | |
pseudo = Cpt(PseudoSingleInterface) | ||
real = Cpt(LimitSettableSoftPositioner) | ||
|
||
signs = np.asarray([[rs, ps]] * 8) | ||
table = np.asarray( | ||
[[0, 40], | ||
[1, 50], | ||
|
@@ -216,21 +228,35 @@ class MyLUTPositioner(LookupTablePositioner): | |
[8, 300], | ||
[9, 400], | ||
] | ||
) | ||
) * signs | ||
column_names = ['real', 'pseudo'] | ||
lut = MyLUTPositioner('', table=table, column_names=column_names, | ||
name='lut') | ||
|
||
np.testing.assert_allclose(lut.forward(60)[0], 2) | ||
np.testing.assert_allclose(lut.inverse(7)[0], 200) | ||
np.testing.assert_allclose(lut.inverse(1.5)[0], 55) | ||
|
||
lut.move(100, wait=True) | ||
np.testing.assert_allclose(lut.pseudo.position, 100) | ||
np.testing.assert_allclose(lut.real.position, 6) | ||
|
||
assert lut.real.limits == (0, 9) | ||
assert lut.pseudo.limits == (40, 400) | ||
np.testing.assert_allclose(lut.forward(60 * ps)[0], 2 * rs) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how did I not know There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You know, I didn't actually read the functions I was adding the sign swaps to, I was only looking for numbers and figuring out whether they were the real positions or the pseudo positions, so I also didn't realize My test here is just using the pre-existing test from Ken but adding the cases where either side is decreasing instead of increasing. |
||
np.testing.assert_allclose(lut.inverse(7 * rs)[0], 200 * ps) | ||
np.testing.assert_allclose(lut.inverse(1.5 * rs)[0], 55 * ps) | ||
|
||
lut.move(100 * ps, wait=True) | ||
np.testing.assert_allclose(lut.pseudo.position, 100 * ps) | ||
np.testing.assert_allclose(lut.real.position, 6 * rs) | ||
|
||
assert lut.real.limits == tuple(sorted([0 * rs, 9 * rs])) | ||
assert lut.pseudo.limits == tuple(sorted([40 * ps, 400 * ps])) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"input,expected", | ||
( | ||
(np.asarray((0, 1, 2, 3, 4, 5)), True), | ||
(np.asarray((0, 1, 2, 3, 4, 4)), False), | ||
(np.asarray((0, -1, -2, -3, -4, -5)), False), | ||
(np.asarray((0, 2, 4, -3, 5, 10)), False), | ||
), | ||
) | ||
def test_increasing_helper(input: np.ndarray, expected: bool): | ||
logger.debug("test_increasing_helper") | ||
assert is_strictly_increasing(input) == expected | ||
|
||
|
||
FakeDelayBase = make_fake_device(DelayBase) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess monotonically increasing does mean strictly increasing (never decreasing or staying the same). We just had the wrong idea of "monotonically increasing" before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually re-read the docs and found that they specified strictly increasing instead of monotonically increasing, the difference being that a monotonic sequence is allowed to repeat adjacent numbers or have a zero slope.