Skip to content

feat: Add Magnetometer Calibration#12

Open
yrevash wants to merge 3 commits intoossia:masterfrom
yrevash:feat/magnetometer-calibration
Open

feat: Add Magnetometer Calibration#12
yrevash wants to merge 3 commits intoossia:masterfrom
yrevash:feat/magnetometer-calibration

Conversation

@yrevash
Copy link
Contributor

@yrevash yrevash commented Jun 17, 2025

This PR introduces the magnetometer calibration feature, which improves the accuracy of orientation detection in the PUARA system.

  • Adds calibration utility for the magnetometer
  • Updates relevant processing logic
  • Includes minor refactoring where needed

@yrevash yrevash requested review from edumeneses and jcelerier June 17, 2025 17:46
@yrevash yrevash self-assigned this Jun 17, 2025
Copy link

@edumeneses edumeneses left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that you are counting on Eigen3 being installed systemwide to compile score.

In a machine without it, I have:

CMake Error at src/addons/score-addon-puara/CMakeLists.txt:13 (find_package):
  By not providing "FindEigen3.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "Eigen3", but
  CMake did not find one.

  Could not find a package configuration file provided by "Eigen3" with any
  of the following names:

    Eigen3Config.cmake
    eigen3-config.cmake

Which is expected. I assume you will have to add it as a 3rd party submodule, but I'll wait for @jcelerier's final word on how to organize the repo's dependencies

@jcelerier
Copy link
Member

actually eigen is already part of the score dependencies! It's the most common linear algebra library in C++, that's useful in multiple places. It's in score/3rdparty/eigen.
Let me check why it isn't found, I'll try the pr

@jcelerier
Copy link
Member

one thing I wonder is - how this object is going to be used? e.g. what will be the workflow for the artist in terms of "getting data in and out" of it. Do we want to use it for instance for automated calibration on, say, a RPi with a magnetometer directly plugged-in to the SPI or I2C bus?

@jcelerier
Copy link
Member

ok, pushed a fix @edumeneses

@edumeneses
Copy link

one thing I wonder is - how this object is going to be used? e.g. what will be the workflow for the artist in terms of "getting data in and out" of it. Do we want to use it for instance for automated calibration on, say, a RPi with a magnetometer directly plugged-in to the SPI or I2C bus?

To me, the great advantage is using Score to generate the Matrix that will live on the NIME/DMI. The way I see it, the instruments we create with Puara will store this Matrix (we can feed it via puara-module's web interface). It will replace MotionCal, which is outdated (although it might work if you manage to make it run on your system).

When this is working, the next logic step to me is to create a shader to visualize that data and check if the calibration works before copy/paste the matrix to the device. Iddeally, we would have another process in score to apply the matrix in RT, using the applyMagnetometerCalibration function.

@yrevash
Copy link
Contributor Author

yrevash commented Jun 18, 2025

one thing I wonder is - how this object is going to be used? e.g. what will be the workflow for the artist in terms of "getting data in and out" of it. Do we want to use it for instance for automated calibration on, say, a RPi with a magnetometer directly plugged-in to the SPI or I2C bus?

@jcelerier

Hi @jcelerier ,

My current implementation is focused on the interactive workflow for an artist using a phone:

  • The user streams raw magnetometer data into the processor.

  • They use a toggle in the UI to record a cloud of data points while moving the device.

  • They press a "Generate" button, which calculates and stores the calibration matrix.

  • The processor then outputs a corrected, real-time magnetometer stream that can be used in other objects.

The idea of an automated calibration for a dedicated device like a Raspberry Pi is very interesting. Would that involve a different mode for the processor, perhaps one that runs the recording and generation sequence automatically on startup without user interaction? I'd be interested to hear more about how you envision that working

.

@jcelerier
Copy link
Member

I see !
@edumeneses what would you think of turning this into a small standalone GUI software instead?

@edumeneses
Copy link

I see ! @edumeneses what would you think of turning this into a small standalone GUI software instead?

I think both options are useful (standalone and process on score). I see a use case for having a process on score: receiving raw data from an off-the-shelf device that we want to calibrate and user in score and we cannot embed the calibration matrix

@yrevash yrevash requested a review from edumeneses June 22, 2025 10:45
@edumeneses
Copy link

Hello @pyandcpp-coder and @jcelerier,

Although the process looks like it's working fine, I cannot access the generated data.

Screenshot from 2025-06-23 11-02-52

Screenshot from 2025-06-23 10-53-53

Screenshot from 2025-06-23 11-08-54

From the 3 screenshots: I can record the data, generate the matrix, and apply it to the signal (screenshot 3). However, the outlets that output the calibration matrix are always 0 (screenshots 2 and 3).

Additionally, it seems that score doesn't update the OSC device based on the outlet when I have a Value Display attached to it. @jcelerier, is that expected? Anyways, Value Display will not show such small values, so I created an OSC bi-directional device/child to display them. I assume I can use it as a buffer to store the matrix, as it apparently vanishes when we press Stop on the score, and it is helpful to keep that matrix stored on the score. Is there an official method to store data that I'm missing?

@yrevash
Copy link
Contributor Author

yrevash commented Jun 23, 2025

Hey @edumeneses ,

So I do understand the issue, though while testing I did not seem to find such no output, though there was an instance where I did face such an issue, and like the only major intuition was that there were not enough points, in the recorded data,
regarding your's can I get some guidance on how to look at this problem and what could be the solution? Like, what approach should I be looking at? The approach towards the solution seems not so clear to me.

@edumeneses
Copy link

How many points did you feed before generating the matrix?

@yrevash
Copy link
Contributor Author

yrevash commented Jun 23, 2025

@edumeneses ,
So, like I was trying to get the gist of calibration. And there I saw a better range of 1.5 k points and moving the phone in like an 8 path, so I was able to get around 700 800 points, and get the calibrated and saw a minute change. And then I thought I needed more points to get a significant change, sort of.

@edumeneses
Copy link

I used approximately 3,000 points to generate the matrix, but I think (based on the comparison between raw data and calibrated data) that the matrix is being generated and applied correctly, regardless. The problem seems to be with the outlets. Did you manage to extract data from your outlets in score?

@yrevash
Copy link
Contributor Author

yrevash commented Jun 23, 2025

@edumeneses

Yes I was able to see the change in the output on the score but not on all outlets, the very second output was seen. Tough for next outlets I thought I need more points.
Also can I know how can I also generate like 3k points.
Though regarding output yes I was able to see change.

@jcelerier
Copy link
Member

heya,
I think here we're hitting limits of the data processing pipeline which is meant for processing small number of values on the real-time audio thread, and not allocating 3000 floats.

To fix this score should introduce a "global" buffer type a bit like Max buffer~ or puredata arrays which isn't going to be copied from one object to another but instead be modified in place.
That said are we sure we really want this in score? as it really makes everything messier for the end user I believe...

@edumeneses
Copy link

I would like to have at least a process to apply the calibration matrix to raw data. We don't necessarily need to generate the matrix on the same process or in score, although I like the idea of using score to create the calibration matrix: a power user could have devices connected to the network, e.g., T-Sticks, and reliably use orientation from them, even if they cannot do sensor fusion internally.

I propose:

  • We have an object that accepts a matrix (as an array with 9 elements, not multiple vec3s) and another array with 3 elements for the hard Iron Bias (not a vec3) to calibrate the magnetometer data. This is essentially already implemented by @pyandcpp-coder.
  • We have either a standalone software to generate the soft iron matrix / hard iron array, or another score object to calculate those arrays (which would be helpful in the case above).

I also suggest that these processes should be categorized under the Utility category (not under gestures).

Would that work for you @jcelerier? If you still don't think these processes should be included in score we can just make a standalone tool for calibration.

@yrevash
Copy link
Contributor Author

yrevash commented Jun 25, 2025

@jcelerier @edumeneses , What should I be implementing and changing now for this processor? Or do we plan for something else

@jcelerier jcelerier force-pushed the master branch 3 times, most recently from 397d5c4 to fa25dea Compare July 29, 2025 18:36
@jcelerier
Copy link
Member

if you can, rebase it and remove the now-unnecessary eigen include in cmake

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants