Code
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter
ION MagNav Workshop, PLANS 2023, Monterey, CA
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.
There’s a docker container with a jupyter notebook that contains this exercise:
Then select work/vector_v_scalar.ipynb
How to interpret the addition of two vectors where measured with a scalar sensor. This scenario occurs several times:
What does this mean for aircraft calibration as you travel from one part of the world to another?
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.
# 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>
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())