Magic Angle Simulator

Magic angle effects (MAE) are well recognized in musculoskeletal (MSK) magnetic resonance (MR) imaging. With pulse sequences with TE $\leq$ 30 msec, the signal intensity of tendons, ligaments, and menisci depends on their orientation to the constant magnetic induction field ($B_{0}$) (Chappell et al, Li et al, Fullerton et al).

These tissues are rich in collagen, which is bound to water. These water protons undergo dipolar interactions whose strength depends on the orientation of the collagen fibers to $B_{0}$. These interactions result in a very short T2. These collagen-rich tissues therefore exhibit little or no signal intensity, and appear dark on many clinical MR sequences. The signal intensity, $S(\theta)$, of these tissues can be expressed by the following equation from Chappell et al:

$$S(\theta) = S_{1} + S_{0} \cdot e^{-TE[\frac{1}{T_{2base}} + \frac{1}{\alpha(3cos^{2}\theta - 1)^{2}}]}$$

However, this equation does not account for the exponential drop-off in MAE signal intensity seen with increasing TE in experimental data from other authors (Li and Mirowitz. To account for this phenomenon, we added an additional exponential term, resulting in the following equation:

$$S(\theta) = S_{1} + S_{0} \cdot e^{-TE[\frac{1}{T_{2base}} + \frac{1}{\alpha(3cos^{2}\theta - 1)^{2}}]} \cdot e^{- \beta (TE - t_{0})}$$

where $\beta$ is a decay constant and $t_{0}$ is the TE time at which maximum signal is observed experimentally.

To account for the effects of the noise floor, Prah et al suggest addeing an additional term:

$$S(\theta) = S_{1} + S_{0} \cdot e^{-TE[\frac{1}{T_{2base}} + \frac{1}{\alpha(3cos^{2}\theta - 1)^{2}}]} \cdot e^{- \beta (TE - t_{0})} + Noise_{floor}$$

References:

  1. Chappell KE, Robson MD, Stonebridge-Foster A, Glover A, Allsop JM, Williams AD, et al. Magic angle effects in MR neurography. AJNR Am J Neuroradiol 2004;25(3):431–40.
  2. Fullerton GD, Rahal A. Collagen structure: the molecular source of the tendon magic angle effect. J Magn Reson Imaging. 2007 Feb;25(2):345–61.
  3. Li T, Mirowitz SA. Manifestation of magic angle phenomenon: comparative study on effects of varying echo time and tendon orientation among various mr sequences. Magn Reson Imaging 2003;21(7):741–4.
  4. Prah DE, Paulson ES, Nencka AS, Schmainda KM. A simple method for rectified noise floor suppression: Phase-corrected real data reconstruction with application to diffusion-weighted imaging. Magn Reson Med. 2010 Aug;64(2):418–29.

The following code uses parameters derived from a non-linear least-squares fit of the experimental data from Li and Mirowitz. This function calculates the signal intensity for a given value of T2 and TE.

  1. Li T, Mirowitz SA. Manifestation of magic angle phenomenon: comparative study on effects of varying echo time and tendon orientation among various mr sequences. Magn Reson Imaging 2003;21(7):741–4.
In [1]:
%matplotlib inline

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Wedge
from ipywidgets import interactive, interact, Label, widgets, Layout, Button, Box
from ipywidgets import FloatSlider, IntSlider
from IPython.display import display

def X_magic(TE, T2base, Noise):
    
    # set up a nice wide figure to contain both plots
    fig = plt.figure(figsize=(10,5))

    # set up parameters for plot of signal intensity vs angle
    rad2deg = 2 * np.pi /360    
    
    # parameters from fit to Li & Mirowitz FSE data
    alpha = 0.125
    S1 = 89.5
    S0 = 427
    t0 = 9
    beta = 0.0504464
    
    theta1 = np.arange(0,90, 2)
    T2_magic_angle = (1/T2base) + (1/(alpha*(3*np.cos(rad2deg*theta1)* np.cos(rad2deg*theta1) - 1)**2))

    S_magic_angle = S1 + S0 * np.exp(-(TE / T2_magic_angle)) * np.exp(-(TE-t0)*beta) + Noise

    # plot signal intensity vs theta in first subplot area
    ax = fig.add_subplot(121)

    plt.axis([0,90,0,800])
    plt.plot(theta1, S_magic_angle)
    plt.ylabel("Signal Intensity (arbitrary units)")
    plt.xlabel("Angle to $B_{0}$ field")
    plt.title("Signal Intensity vs angle to $B_{0}$")
    
    # create tendon gray scale map scaled on min and max signal intensity
    # max signal is mapped to 1.0 (white); minimum signal is mapped to 0.0 (black)

    tendon_map =  np.round((S_magic_angle - np.ndarray.min(S_magic_angle))/(np.ndarray.max(S_magic_angle) - np.ndarray.min(S_magic_angle)), 2)

    #print(np.array_str(tendon_map))
    #print(range(len(theta)-1))

    # create second subplot area for the simulated tendon
    ax2 = fig.add_subplot(122, frameon=False)

    theta2 = np.linspace(180, 270, 45)

    for i in range(len(theta2)-1):
    #    print(np.array_str(tendon_map[i]))
        ax2.add_artist(
            Wedge((0, 0), 1, theta2[i], theta2[i+1], width=0.2, color=np.array_str(tendon_map[i]))
    )
        
    ax2.set_xlim((-1.25,.25))
    ax2.set_ylim((-1.25,.25))
    ax2.axes.get_xaxis().set_visible(False)
    ax2.axes.get_yaxis().set_visible(False)

    ax2.annotate("$B_{0}$",
            xy=(-.3, 0.1), xycoords='data',
            xytext=(-.37, -0.12), textcoords='data',fontsize=19,
            arrowprops=dict(arrowstyle="simple",
                            connectionstyle="arc3"),
            )

    plt.show() 
    

The following Python code creates an interactive widget, allowing one to explore variations in the signal intensity as one varies the T2, TE and noise floor. This signal is shown as a plot of signal vs angle to $B_{0}$ and also as the signal intensity within a simulated ankle tendon.

In [6]:
magic_angle_plot = interactive(X_magic, 
                               TE = IntSlider(value=10, description='TE', max=120, min=1),
                               T2base = IntSlider(value=1.5, description='Tissue T2', max=200, min=1),
                               Noise = IntSlider(value=1.5, description='Noise floor', max=300, min=0),
                               Bzero=FloatSlider(value=1.5, description='Magnetic Field Strength', max=7.0, min=0.1, step=0.1)
                              )

display(magic_angle_plot)