A new feature for FormaK has landed: the Strapdown IMU Reference model. The model is now available for inclusion into new models and use as a reference for implementing future models. This post covers some of the aspects of the design and development that didn't make it into the final design and feature.
If you're interested in the reference model, you can read the launch announcement.
Pull Request: #19
Commit: 16ba541
The Rotation Class¶
A few days into the project I decided it'd be a good idea to develop a general purpose Rotation class that could serve as a simple conceptual object that could also be easily be compiled into different representations for any model.
This was mostly an exercise in learning that I should do a bit of searching around before I make such an attempt. I spent three weeks making this class, testing it to a 80% level of completion, then refactoring to pull it out and replace it with the Sympy Quaternion class that offered the same feature set but in working order and with tests.
N.B. Scipy also has a Rotation class
Pytest Features¶
Pytest has functionality for
skipping failing tests. It
also supports marking tests as
xfail
,
which will run the test and then fail the test run if the test passes.
@pytest.mark.xfail
def test_function():
...
Pytest also supports parameterized tests . While I was implementing a generic Rotation class with multiple underlying representations (Euler angles, rotation matrices and quaternions), I could use the feature to easily run the same test across all representations to make sure it passed. It leads to nicely formatted test outputs (until you multiply your failures then there's just too much text scrolling by).
Abridged Code:
REPRESENTATIONS = ["quaternion", "matrix", "euler"]
@pytest.mark.parametrize("representation", REPRESENTATIONS)
def test_principal_axis(representation):
...
Sample Output:
=========================== short test summary info ============================
FAILED py/test/unit/rotation_test.py::test_principal_axis[matrix] - assert False
FAILED py/test/unit/rotation_test.py::test_construct_to_output_consistency_euler[quaternion]
FAILED py/test/unit/rotation_test.py::test_construct_to_output_consistency_euler[matrix]
FAILED py/test/unit/rotation_test.py::test_construct_to_output_consistency_quaternion[matrix]
FAILED py/test/unit/rotation_test.py::test_construct_to_output_consistency_matrix[quaternion]
FAILED py/test/unit/rotation_test.py::test_construct_to_output_consistency_matrix[euler]
What you don't see here is the absurd amount of log spam I created for myself... we'll let that one blow away into the sands of time.
Simplify Doesn't Scale¶
Something in Sympy's implementation of the
simplify
function leads to excessive runtimes for my development machine (on the order
of 300 seconds / 5 minutes). I suspect it's a loop of iteratively making small
changes, then re-evaluating everything on the small change. This is the second
time (or maybe third?) that I've wanted to include simplification into the
project and each time I manage to wander into a case where it's performance is
a hard block on its usefulness. I love Sympy and want to love simplify, so it
seems like something of an outlier to run into a performance issue like this.