python3draspberry-piphysicswgs84

Normalising angled Earth magnetic field


Me and my team are participating in ESA Astro Pi challenge. Our program will ran on the ISS for 3 hours and we will our results back and analyze them.


We want to investigate the connection between the magnetic intensity measurements from Sense HAT magnetometer and predictions from the World Magnetic Model (WMM). We want to research the accuracy of the magnetometer on Sense HAT.

The program will get raw magnetometer data (X, Y and Z) in microteslas from Sense HAT and calculate values H and F as described in British geological survey's article (section 2.1). It will then save them to CSV file, along with timestamp and location calculated with ephem.

We will then compare values Z, H and F from ISS and WMM and create maps with our data and differences (like figures 6, 8 and 10). We will then research, how accurate are Sense HAT magnetometer data.


We want to compare our data with data from WMM to see how accurate is Sense HAT magnetometer, but we have a problem that orientation of magnetometer will always be different. Because of that, our data will always be (very) different from WMM so we won't be able to compare them correctly.

We talked with Astro Pi support team and they suggested to "normalise the angled measurements so it looks like they were taken by a device aligned North/South".

Unfortunately, we (and they) don't know how to do this, so they suggested to ask this question on Stack Exchange. I asked it on Math Stack Exchange, Physics Stack Exchange and Raspberry Pi Forums. Unforcenetly, they didn't received any answers, so I am asking this question again.

How can we do this? We have data for timestamp, ISS location (latitude, longitude, elevation), magnetic data (X, Y and Z) and also direction from the North.

We want to normalise our data so we will be able to correctly compare them with data from WMM.


Here is part of our program that calculates magnetometer values (which gets not normalised data):

compass = sense.get_compass_raw()

try:
    # Get raw data (values are swapped because Sense HAT on ISS is in different position)
    # x: northerly intensity
    # y: easterly intensity
    #  z: vertical intensity
    x = float(compass['z'])
    y = float(compass['y'])
    z = float(compass['x'])

except (ValueError, KeyError) as err:
    # Write error to log (excluded from this snippet)
    pass

try:
    # h: horizontal intensity
    # f: total intensity
    # d: declination
    # i: inclination
    h = sqrt(x ** 2 + y ** 2)
    f = sqrt(h ** 2 + z ** 2)
    d = degrees(atan(y / x))
    i = degrees(atan(z / h))

except (TypeError, ValueError, ZeroDivisionError) as err:
    # Write error to log (excluded from this snippet)
    pass

There is also some simple simulator available with our code: https://trinket.io/library/trinkets/cc87813ce7


Part of email from Astro Pi team about location and position of magnetometer:

  • Z is going down through the middle of the Sense Hat.
  • X runs between the USB ports and SD card slot.
  • Y runs across from the HDMI port to the 40 way pin header.

On the ISS the AstroPi orientation is that the Ethernet + USB ports face the deck and the SD card slot is towards the sky. So, that's basically a rotation around the Y axis from flat. So you keep the Y axis the same and swap around Z and X.


It can help to look at the Google Street view of the interior of the ISS Columbus module to get a better idea how the AstroPi is positioned; https://www.google.com/streetview/#international-space-station/columbus-research-laboratory

If you pan the camera down and to the right, you'll see a green light - that's the AstroPi. The direction of travel for the whole space station is towards the inflatable Earth ball you can see on the left.

ISS

So, broadly speaking, the SD card slot points towards azimuth as in away from the centre of the Earth (so the X axis). The LED matrix is facing the direction of travel of the space station (the Z axis).

Because of the orbital path of the ISS the Z and Y axes will continually change direction relative to the poles as it moves around the Earth.

location

So, I am guessing you want to normalise the angled measurements so it looks like they were taken by a device aligned North/South?


Solution

  • I think you need to create local reference coordinate system similar to NEH (north,east,height/altitude/up) something like

    Its commonly used in aviation as a reference frame (heading is derived from it) so your reference frame is computed from your geo location and its axises pointing to North, East and Up.

    Now the problem is what does it mean aligned North/South and normalizing.. ?

    If reference device measure just projection than you would need to do something like this:

    dot(measured_vector,reference_unit_direction)
    

    where the direction would be the North direction but as unit vector.

    If the reference device measure a full 3D too then you need to transform both reference and tested measured data into the same coordinate system. That is done by using

    So simple matrix * vector multiplication will do ... Only then compute the values H,F,Z which I do not know what they are and too lazy to go through papers ... would expect E,H or B vectors instead.

    However if you do not have the geo location at moment of measure then you have just the North direction in respect to the ISS in form of Euler angles so you can not construct 3D reference frame at all (unless you got 2 known vectors instead of just one like UP). In such case you need to go with the option 1 projection (using dot product and north direction vector). So you will handle just scalar values instead of 3D vectors afterwards.

    [Edit1]

    From the link of yours:

    The geomagnetic field vector, B, is described by the orthogonal components X (northerly intensity), Y (easterly intensity) and Z (vertical intensity, positive downwards);

    This is not my field of expertise so I might be wrong here but this is how I understand it:


    B(Bx,By,Bz) - magnetic field vector
    a(ax,ay,az) - acceleration

    Now F is a magnitude of B so its invariant on rotation:

    F = |B| = sqrt( Bx*Bx + By*By + Bz*Bz )
    

    you need to compute the X,Y,Z values of B in the NED reference frame (North,East,Down) so you need the basis vectors first:

    Down = a/|a|  // gravity points down
    North = B/|B| // north is close to B direction
    East = cross(Down,North) // East is perpendicular to Down and North
    North = cross(East,Down) // north is perpendicular to Down and East, this should convert North to the horizontal plane
    

    You should render them to visually check if they point to correct directions if not negate them by reordering the cross operands (I might have the order wrong I am used to use Up vector instead). Now just convert B to NED :

    X = dot(North,B)
    Y = dot(East,B)
    Z = dot(Down,B)
    

    And now you can compute the H

    H = sqrt( X*X +Y*Y )
    

    The vector math needed for this you will find in the transform matrix link above.

    beware this will work only if no accelerations are present (the sensor is not on a robotic arm during its operation, or ISS is not doing a burn...) Otherwise you need to obtain the NED frame differently (like from onboard systems)

    If this not work correctly then you can compute NED from your ISS position but for that you would need to know the exact orientation and displacement of the sensor in respect to your simulation model that provide your location. I do not know what rotations ISS do so I would not touch that subject unless as a last resort.

    I am afraid that I will not have time for coding for some time ... anyway coding without sample input data nor the coordinate system expalnations and all the input/output variables is insanity ... simple negation of axis will invalidate the whole thing and there is a lot of duplicities along the ways and to cover all of them you would end up with many many versions to try to...

    Apps should be build up incrementally but I am afraid that without the access to simulation or real HW that is not possible. And there is a whole bunch of things that could go wrong ... making even simple programs a magnitude harder to code... I would first check the F as it does not require any "normalization" first to see if the results are off or not. If off it might suggest different units or god knows what ...