Vector vs. Scalar comparison

ION MagNav Workshop, PLANS 2023, Monterey, CA

Author

Aaron Nielsen

The views expressed in this article are those of the author and do not necessarily reflect the official policy or position of the United States Government, Department of Defense, United States Air Force or Air University.
Distribution A: Authorized for public release. Distribution is unlimited. Case No. 2023-0427.

How-to

There’s a docker container with a jupyter notebook that contains this exercise:

docker run  -p 8888:8888 anielsen/magnav-plans-workshop:latest

Then select work/vector_v_scalar.ipynb

Vector vs. Scalar sensor comparison

How to interpret the addition of two vectors where measured with a scalar sensor. This scenario occurs several times:

  • Earth’s magnetic anomaly and core field
  • Airplane’s magnetic field and external magnetic field

What does this mean for aircraft calibration as you travel from one part of the world to another?

  • Earth’s magnetic field points in different directions
  • Northern latitudes - points downward
  • Equatorial regions - parallel to surface
  • Southern latitudes - points upwards

Scalar magnetic anomaly

We often talk about measuring magnetic field differences. But the magnetic field is a vector field, so when we talk about differences, it can be unclear what we mean.

\[ \vec{B}_\text{a+b} = \vec{B}_\text{a} + \vec{B}_\text{b} \]

\[ \vec{B}_\text{total} = \vec{B}_\text{earth} + \vec{B}_\text{anomaly} \]

\[ |\vec{B}_\text{total}| = \sqrt{\left|\vec{B}_\text{earth} + \vec{B}_\text{anomaly}\right|^2} \]

The exact solution: \[ |\vec{B}_\text{total}| = |\vec{B}_\text{earth}| \sqrt{1 + 2 \frac{\vec{B}_\text{earth}\cdot\vec{B}_\text{anomaly}}{|\vec{B}_\text{earth}|^2} + \frac{|\vec{B}_\text{anomaly}|^2}{|\vec{B}_\text{earth}|^2} } \]

Usually we say \[ \frac{|\vec{B}_\text{anomaly}|^2}{|\vec{B}_\text{earth}|^2} \ll 1 \tag{1}\] and throw it away. This is the first approximation.

Then we make a Taylor series expansion or the remaining terms using \(\sqrt{1+x} = 1 + \frac{x}{2} - \frac{x^2}{8} + \frac{x^3}{16}\cdots\) \[ |\vec{B}_\text{total}| = |\vec{B}_\text{earth}|\left[ 1 + \frac{\vec{B}_\text{earth}\cdot\vec{B}_\text{anomaly}}{|\vec{B}_\text{earth}|^2} - \frac{1}{4}\left(\frac{\vec{B}_\text{earth}\cdot\vec{B}_\text{anomaly}}{|\vec{B}_\text{earth}|^2}\right)^2 + \frac{1}{8}\left(\frac{\vec{B}_\text{earth}\cdot\vec{B}_\text{anomaly}}{|\vec{B}_\text{earth}|^2}\right)^3 + \cdots \right] \]

Consistent with Equation 1 \[ \left(\frac{\vec{B}_\text{earth}\cdot\vec{B}_\text{anomaly}}{|\vec{B}_\text{earth}|^2}\right)^2 \ll 1 \] and we ignore it and higher order terms.

Code
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter
Code
# Creating plot
fig, ax = plt.subplots()

# Creating Earth core field
Be_pos_x = 0
Be_pos_y = 0
Be_length = 50_000
Be_angle = np.radians(45)
Be_end_x = Be_length * np.cos(Be_angle)
Be_end_y = Be_length * np.sin(Be_angle)
ax.arrow(
    Be_pos_x,Be_pos_y,Be_end_x,Be_end_y,
    width=.01,
    color='b',
    label=r'$B_\mathrm{Earth}$',
)

# Create anomaly field
Ba_pos_x = Be_end_x
Ba_pos_y = Be_end_y
Ba_length = 10000
Ba_angle = np.radians(20)
Ba_end_x = Ba_length * np.cos(Ba_angle)
Ba_end_y = Ba_length * np.sin(Ba_angle)
ax.arrow(
    Ba_pos_x,Ba_pos_y,Ba_end_x,Ba_end_y,
    width=.01,
    color='g',
    label=r'$B_\mathrm{anomaly}$', 
)

# draw total
Btot_x = Be_end_x + Ba_end_x
Btot_y = Be_end_y + Ba_end_y
ax.arrow(
    Be_pos_x,Be_pos_y,Btot_x,Btot_y,
    width=.01,
    color='k',
    label=r'$B_\mathrm{total}$'  
)

# draw projection of Ba into Be
Bprj_pos_x = Be_end_x
Bprj_pos_y = Be_end_y
Bprj_angle = Be_angle
Bprj_length = (Ba_end_x * Be_end_x + Ba_end_y * Be_end_y)/Be_length
Bprj_end_x = Bprj_length * np.cos(Bprj_angle)
Bprj_end_y = Bprj_length * np.sin(Bprj_angle)
ax.arrow(
    Bprj_pos_x,Bprj_pos_y,Bprj_end_x,Bprj_end_y,
    width=.01,
    color='r',
    label='Scalar anomaly'
)

ax.set_xlabel(r'$B_x$')
ax.set_ylabel(r'$B_y$')
ax.grid()
ax.legend()
<matplotlib.legend.Legend at 0x7fbaca07a130>

Code
fig, ax = plt.subplots()

def animate(i):

    ax.clear()

    Ba_angles = np.arange(360)

    # Creating Earth core field
    Be_pos_x = 0
    Be_pos_y = 0
    Be_length = 50_000
    Be_angle = np.radians(45)
    Be_end_x = Be_length * np.cos(Be_angle)
    Be_end_y = Be_length * np.sin(Be_angle)
    ax.arrow(
        Be_pos_x,Be_pos_y,Be_end_x,Be_end_y,
        width=.01,
        color='b',
        label=r'$B_\mathrm{Earth}$',
    )

    # Create anomaly field
    Ba_pos_x = Be_end_x
    Ba_pos_y = Be_end_y
    Ba_length = 10000
    #Ba_angle = np.radians(20)
    Ba_angle = np.radians(Ba_angles[i])
    Ba_end_x = Ba_length * np.cos(Ba_angle)
    Ba_end_y = Ba_length * np.sin(Ba_angle)
    ax.arrow(
        Ba_pos_x,Ba_pos_y,Ba_end_x,Ba_end_y,
        width=.01,
        color='g',
        label=r'$B_\mathrm{anomaly}$', 
    )

    # draw total
    Btot_x = Be_end_x + Ba_end_x
    Btot_y = Be_end_y + Ba_end_y
    ax.arrow(
        Be_pos_x,Be_pos_y,Btot_x,Btot_y,
        width=.01,
        color='k',
        label=r'$B_\mathrm{total}$'  
    )

    # draw projection of Ba into Be
    Bprj_pos_x = Be_end_x
    Bprj_pos_y = Be_end_y
    Bprj_angle = Be_angle
    Bprj_length = (Ba_end_x * Be_end_x + Ba_end_y * Be_end_y)/Be_length
    Bprj_end_x = Bprj_length * np.cos(Bprj_angle)
    Bprj_end_y = Bprj_length * np.sin(Bprj_angle)
    ax.arrow(
        Bprj_pos_x,Bprj_pos_y,Bprj_end_x,Bprj_end_y,
        width=.01,
        color='r',
        label='Scalar anomaly'
    )

    ax.set_xlabel(r'$B_x$')
    ax.set_ylabel(r'$B_y$')
    ax.set_xlim([0,50_000])
    ax.set_ylim([0,50_000])
    #ax.grid()
    #ax.legend()

ani = FuncAnimation(fig,animate,frames=360,interval=100, repeat=True)
from IPython.display import HTML
HTML(ani.to_jshtml())