-
Notifications
You must be signed in to change notification settings - Fork 6
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
docs: rework force calibration documentation #699
base: lazy_power
Are you sure you want to change the base?
Conversation
ea3b65b
to
e94fbfc
Compare
e94fbfc
to
ffd54fd
Compare
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.
Really nice! Good documentation on the force calibration was really missing.
The comments I added mostly focus on being more explicit about the content of a tutorial or a figure.
Redoing a Bluelake calibration | ||
------------------------------ | ||
|
||
We can directly slice the channel by the calibration item we want to reproduce to extract the relevant data:: |
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.
You touch on this in the previous section, but I would add the following, as this is a very common misconception:
In order to redo the Bluelake calibration, the force data that was used for calibration has to be included in the h5 file. Note that this force data is not exported nor marked by default; it has to be explicitly added to the exported file.
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.
Good point! It's indeed a good idea to re-emphasize this, thanks!
plt.subplot(2, 2, 3) | ||
calibration1.plot_spectrum_residual() | ||
plt.ylim([0, 2]) | ||
plt.title(f"Stiffness: {calibration1.stiffness:.3f}, Force sensi: {calibration1.displacement_sensitivity:.2f}") |
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.
plt.title(f"Residual\nStiffness: {calibration1.stiffness:.3f}, Force sensi: {calibration1.displacement_sensitivity:.2f}")
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.
Good catch!
plt.subplot(2, 2, 4) | ||
calibration2.plot_spectrum_residual() | ||
plt.tight_layout() | ||
plt.title(f"Stiffness: {calibration2.stiffness:.3f}, Force sensi: {calibration2.displacement_sensitivity:.2f}") |
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.
plt.title(f"Residual\nStiffness: {calibration2.stiffness:.3f}, Force sensi: {calibration2.displacement_sensitivity:.2f}")
>>> calibration1.backing | ||
0.0 | ||
|
||
>>> calibration1.backing |
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.
calibration2.backing
.. only:: html | ||
|
||
:nbexport:`Download this page as a Jupyter notebook <self>` | ||
|
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.
'Pylake has many options to optimize force calibration depending on the specific conditions of your experiments. The number of options.... etc'
@@ -0,0 +1,216 @@ | |||
Getting good calibrations |
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.
This title could be more specific, eg
'Optimizing force calibration parameters'
.. only:: html | ||
|
||
:nbexport:`Download this page as a Jupyter notebook <self>` | ||
|
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.
First sentence should be something like this, as this is what the tutorial is really about:
'Pylake can be used to recalibrate the force using active calibration data.'
.. only:: html | ||
|
||
:nbexport:`Download this page as a Jupyter notebook <self>` | ||
|
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.
The current introduction triggers a lot of questions like 'why did we not use this method for peak detection before' and 'when should I use this method'. I see you answer these questions a bit further down the tutorial. Instead, I would just mention at the very start that this method is less ideal for fitting a power spectrum, but very convenient for identifying spurious peaks. Maybe even call this tutorial 'automatic detection of spurious peaks'.
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.
To be completely honest, we are currently still evaluating whether we should make the switch to this method (and make it the default), as it requires less work from FSEs in the field and it runs less risk of problems if identified peaks shift or new ones appear.
It's a really good point though, we should already clarify the limitations / what we are going to do in the intro. How about the following?
So far, we have been using least-squares fitting routines for force calibration.
In that case, we assume that the error in the power at each frequency is distributed according to a Gaussian distribution.
:ref:`Blocking or windowing<blocking_windowing>` the power spectrum ensures that this assumption is close enough to the truth such that the fit provides accurate estimates of the unknown parameters.
Occasionally, the power spectrum might show a spurious noise peak.
Such a peak is an outlier in the expected behavior of the spectrum and therefore interferes with the assumption of having a Gaussian error distribution.
As a result, the fit is skewed. In those cases, it can be beneficial to do a robust fit.
When a robust fit is performed, one assumes that the probability of encountering one or multiple outliers is non-negligible.
By taking this into account during fitting, the fit can be made more robust to outliers in the data.
One downside of this approach is that the current implementation does not readily provide standard errors on the parameter estimates and that it leads to a small bias in the fit results for which Pylake has no correction.
Robust fitting can be used in combination with a least-squares fit, to identify outliers automatically, in order to exclude these from a second regular least-squares fit.
9387c17
to
ac7e97d
Compare
867865e
to
8cc0ad8
Compare
ac7e97d
to
6973345
Compare
8cc0ad8
to
1ee98bd
Compare
6973345
to
8795922
Compare
f3f539a
to
647d027
Compare
647d027
to
6fac34e
Compare
6fac34e
to
96a9319
Compare
1ee98bd
to
c37465a
Compare
96a9319
to
f7f9da6
Compare
c37465a
to
f725db9
Compare
f7f9da6
to
2f96587
Compare
Why this PR?
Many people have trouble finding relevant information in the force calibration docs and given the scope of the whole thing, it's entirely understandable. I've attempted to thin the theory in the tutorials, and flesh out the fundamentals section a bit.
At the same time, we've made quite a few changes to the recommended API (providing more properties, so people don't have to poke around the raw dictionaries anymore). These are all documented in this PR.
Docs builds here: tutorial and theory.
What to look out for?
I have attempted to add a more intuitive explanation for the power spectral shape in the opening of the theory section. This is a bit more handwavey right now. I found it challenging to strike a balance between correctness and intuition there. Initially, I was writing it more along the lines of integration white noise, but then I felt that was likely still too mathematical to be a friendly introduction so I went with this instead (this was partly inspired by how Loïc dealt with this topic during his training as well). I would be happy to get some comments on it.