sfwa / TRICAL

Straightforward UKF-based scale and bias calibration for magnetometers (and other tri-axial field sensors).

Home Page:http://au.tono.my/log/20131213-trical-magnetometer-calibration.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Clarification about using TRICAL_estimate_update()

RafigRzayev opened this issue · comments

Hi,

I am getting X, Y, Z values from magnetometer in uT units.

I am using following tool to identify magnetic field in my location, and the value is 50uT (though my calibrated reading are usually around ~55uT).

I don't understand which value should be used for expected_field argument in TRICAL_estimate_update(&global_instance, sensor_reading, expected_field). Can you please tell me what values should be put there?

Below is the pseudocode that I am using, can you please check that the usage is correct?

TRICAL_instance_t global_instance;

int main(void) {
  TRICAL_init(&global_instance);
  TRICAL_norm_set(&global_instance, 50.0);
  TRICAL_noise_set(&global_instance, 1.5);

  float bias_estimate[3];
  float scale_estimate[9];
  float sensor_reading[3];
  float expected_field[3];

  // for holding data received from magnetometer, in uT.
  float mag_x, mag_y, mag_z;

  while(true) {
    // get the latest sensor reading
    read_magnetometer(mag_x, mag_y, mag_z);
    sensor_reading[0] = mag_x;
    sensor_reading[1] = mag_y;
    sensor_reading[2] = mag_z;

    // What should be passed to expected field?
    TRICAL_estimate_update(&global_instance, sensor_reading, expected_field);

    TRICAL_estimate_get(&global_instance, bias_estimate, scale_estimate);

    printf("[%f %f %f]\n", bias_estimate[0], bias_estimate[1], bias_estimate[2]);
   }

return 0;
}

@bobayka can you please help? Looks like the repository is not very active.

Here you wrote that your input range is [-1,1]. Did you scale the input by the maximum?

Also, you said that no zeros are allowed in the input. It is strange :( . Did you write if statement to avoid zeros?

@Lelelo1 Maybe you can help? Do you know which values to pass to the function?

As far as I came to understand it. The expected field is from world magnetic model. You can check what the earth magnetic field is supposed to be in your location with Launch Single Point Calculator

If you point your device to north it should print that vector when there is none or little magnetic distortion. The coordinate system of the vector from world magnetic model and the measurement in the application needs to match.

Its used in a kalman filter, in _trical_measurement_calibrate method in filter.c. It means deviating values are filtered out.

Thank you very much for your help. I was using the same calculator and for me the "Total field" is calculated as 50,325.0 nT, which is ~50uT.

That's why I did following:
TRICAL_norm_set(&global_instance, 50.0);

But in the TRICAL_estimate_update function, it expects a 3-element vector, not a single value:

/*
TRICAL_estimate_update
Updates the calibration estimate of `instance` based on the new data in
`measurement`, and the current field direction estimate `reference_field`.
Call this function with each reading you receive from your sensor.
*/
void TRICAL_estimate_update(TRICAL_instance_t *instance,
float measurement[3], float reference_field[3]);

I tried with reference_field = {50,50,50}, but the calculated bias was always [0,0,0].

I found one repo which uses the function, but is really difficult to understand what is going on there.

Which values did you use for the reference_field[3](expected field)?

X: North Component
Y: East Component
Z: Vertical Component

√(x2 + y2 + z2). Is same as norm (50)

It could look like this the vector:
16,505.3, -1,509.8, 47,844.4
total field (norm) 50,611.4

For latitude: 57.698745, longitude: 11.966936

So I can make up any combination of 3 values which by formula will provide 50?

Can I use fixed vector always? Or should it be updated according to something else?

In the repository mentioned above, they use following:

TRICAL_estimate_update(instance, mag_value_f, expected_field_f);

Where expected_field_f comes from:

    float mag_value_f[3], expected_field_f[3];
...
    quaternion_vector3_multiply_d(expected_field, attitude, wmm_field);
    vector_f_from_d(expected_field_f, expected_field, 3u);

So I can make up any combination of 3 values which by formula will provide 50?

No

That vector represent a arrow pointing the direction earths magnetic field in 3d. For instance ENU coordinate system means east component is x, north component is y, and vertical component is z.

When there is no distortion all measurements become like a sphere, all of them having length(norm) of 50. The norm depend on how near earth's poles you are

I recommend you collect the first measurement and use it as expected field instead. It assumes you are in spot with little magnetic distortion. Then you can test to distort measurement with some metal near sensor of the device. The kalman filter should block those values and application should still be accurate depending how well the Kalman is made

Thank you for clarification. Then, if I understood correctly, I will do following:

  • Adjust sensor so that its axes are aligned according to ENU coordinate system(one of the magnetometer axes will point to geographic north).
  • Place sensor in low distortion area(away from buildings and etc.)
  • Record the measured value and always use it for the expected_field

Can you confirm?

I tried with your values for demo purposes, the bias doesn't change. It is always 0, 0, 0.

I wrote an example which you can run on your pc. I recorded the magnetometer values, and saved them in a header file to be used as an input for the TRICAL.

Here is the link

I am sorry for taking your time. I would appreciate if you can take a look. The program output is not normal: it prints NaN and ones .

I have stopped programming this kind of stuff. So I can’t look at it in detail.

But I can tell you that bias is distortion

Ok, I understand :)

Thank you very much for your help.

If I will get it working I will post updates here.