In [1]:
cd ~/Workspace/gm2/studies/field-shimming/ring-geometry
/Users/matthias/Workspace/gm2/studies/field-shimming/ring-geometry
In [2]:
%matplotlib inline

from IPython.display import display, Markdown
import numpy as np
from scipy.optimize import curve_fit
from scipy.interpolate import interp1d
import matplotlib as mpl
import matplotlib.pyplot as plt
import ROOT as r
import seaborn as sns

# Set the figure size to span the notebook.
mpl.rcParams['figure.figsize'] = (18, 6)
mpl.style.use('fivethirtyeight')
mpl.rcParams['axes.grid'] = False

colors = sns.hls_palette(10, l=0.3, s=0.8)

def finish_plot(ylabel=r'z [$\mu$ m]'):
    plt.xlabel(r'$\theta$ [deg]')
    plt.xlim(0, 360)
    plt.ylabel(ylabel)
    
    yoke_label = ord('A')
    
    for i in xrange(0, 37):

        x = (i * 10.0 - 15.0 - 0.1012) % 360.0

        if i % 3 == 0:
            plt.axvline(x, linestyle='-', color='k', alpha=0.2)

        else:
            plt.axvline(x, linestyle='--', color='k', alpha=0.2)
        
        if i is not 0:
            if i < 10:
                s = str(i) + ' '
            else:
                s = str(i)
                
            plt.figtext(0.052 + i * (0.868 / 36.0), 0.86, s, color='k', alpha=0.4)
            
        if (i % 3) == 1:
            plt.figtext(0.052 + i * (0.868 / 36.0), 0.82, chr(yoke_label), color='k', alpha=0.4)
            yoke_label += 1
            
    plt.show()


def tilt_plane(phi, amp=832.173, baseline=1.059, phase=171.41):
    return amp * (np.cos((phi - phase) * np.pi / 180.0) + baseline)

def sinusoid(phi, amp, baseline, phase):
    return amp * np.cos((phi - phase) * np.pi / 180.0) + baseline

def pole2(x, c1, c2, a0, a1, a2):
    v = (a0 + c1 - a1 * 5.0 + a2 * 5.0**2) * (x < -5.0)
    v += (a0 + c2 + a1 * 5.0 + a2 * 5.0**2) * (x > 5.0)
    v += (a0 + a1 * x + a2 * x**2) * (x >= -5.0) * (x <= 5.0)
    return v

def pole3(x, c1, c2, a0, a1, a2, a3):
    v = (a0 + c1 - a1 * 5.0 + a2 * 5.0**2 - a3 * 5.0**3) * (x < -5.0)
    v += (a0 + c2 + a1 * 5.0 + a2 * 5.0**2 + a3 * 5.0**3) * (x > 5.0)
    v += (a0 + a1 * x + a2 * x**2 + a3 * x**3) * (x >= -5.0) * (x <= 5.0)
    return v

def pole4(x, c1, c2, a0, a1, a2, a3, a4):
    return a0 + a1 * x + a2 * x**2 + a3 * x**3 + a4 * x**4

def pole5(x, c1, c2, a0, a1, a2, a3, a4, a5):
    v = (a0 + c1 - a1 * 5.0 + a2 * 5.0**2 - a3 * 5.0**3 + a4 * 5.0**4 - a5 * 5.0**5) * (x < -5.0)
    v += (a0 + c2 + a1 * 5.0 + a2 * 5.0**2 + a3 * 5.0**3 + a4 * 5.0**4 + a5 * 5.0**5) * (x > 5.0)
    v += (a0 + a1 * x + a2 * x**2 + a3 * x**3 + a4 * x**4 + a5 * x**5) * (x >= -5.0) * (x <= 5.0)
    return v
Welcome to ROOTaaS 6.06/02

Global Bottom Pole Adjustment Plan

With the ring leveling complete, we are about to start a program of adjusting all the poles. The plan needs to make heavy use of our tilt measurements and laser tracker, since those devices are calibrated to gravity.

In [3]:
display(Markdown('## The Data'))

# Open the laser data from the last full scan.
f = r.TFile('data-in/full_scan_025.root')
t = f.Get('t')

z_laser = np.empty(t.GetEntries())
phi_laser = np.empty(t.GetEntries())

for i in xrange(t.GetEntries()):
    t.GetEntry(i)
    z_laser[i] = t.z_2 * 1e6 # Convert inches to microns
    phi_laser[i] = (t.phi_2 + 0.368) % 360

# Remove points with bad data.    
indices = np.where(z_laser > 0.5)
z_laser = z_laser[indices]
phi_laser = phi_laser[indices]
    
# Subtract the height offset to put things in the same space as our reconstruction.
z_laser -= z_laser.mean()
z_laser -= z_laser.min() + 110

# Construct weights based on azimuthal spacing
w_laser = np.empty(phi_laser.shape)
t_phi = (phi_laser - 0.368) % 360
w_laser[1:-1] = 0.5 * (t_phi[2:] - 2 * t_phi[1:-1] + t_phi[:-2])
w_laser[0] = 0.5 * (t_phi[1] - 2 * t_phi[0] + t_phi[-1] - 360.0)
w_laser[-1] = 0.5 * (t_phi[0] + 360.0 - 2 * t_phi[-1] + t_phi[-2])
w_laser = np.abs(w_laser)

plt.plot(w_laser)
plt.show()

display(Markdown('### Laser Height vs Azimuth'))
plt.scatter(phi_laser, z_laser, color=colors[0], alpha=0.5)
finish_plot()

# Open the data for pole boundaries (elog 432) and azimuthal tilts (elog 430)
d_pb = np.genfromtxt('data-in/tilt_pole_boundaries_02_22_2016.csv', skip_header=True)
d_tilt_cal = np.genfromtxt('data-in/rad_tilt_cal_03_13_2016.csv', skip_header=True)
d_tilt = np.genfromtxt('data-in/pole_tilts_03_13_2016.csv', skip_header=True)

d_tilt_azi = (d_tilt[:, 2] - d_tilt_cal[:, 2].mean()) * 1.29

# Take the average of the two steps.
dz = (2 * d_pb[:, 4] - d_pb[:, 2] - d_pb[:, 6]) * 0.5
dz *= 1.29 * 2.25 * 0.0254 # Convert the value to microns
drad = (d_pb[:, 5] - d_pb[:, 3]) * 1.29 * 11.75 * 0.0254

dz += 0.5 * drad
dz_outer = dz - 0.5 * drad

# plt.plot(np.linspace(5, 355, 36), dz)
# plt.plot(np.linspace(5, 355, 36), dz - 0.5 * drad)
# plt.plot(np.linspace(5, 355, 36), dz + 0.5 * drad)
# finish_plot()

dzds = np.array(d_tilt_azi)

# Refill the z values and shift into [0, 360]
z = np.empty(dz.shape[0] * 100)
phi = np.linspace(0, 360, z.shape[0])

for i in xrange(z.shape[0]):
    # To set between [0, 360] instead of [-5, 355]
    idx = (i - 50) % z.shape[0]
    z[idx] = dz[:i/100].sum()
    z[idx] += dzds[i/100] * 0.012 * (i % 100)
    z[idx] += dzds[:i/100].sum() * 1.2
    
# Divide the different by the number of weight of pieces in between z_i and z_f
dzds0 = (z[-51] - z[-50] - dz[-1]) / (1.2 * 35.99)

# Add the offset to the slopes
dzds -= dzds0

# Refill the z values and shift into [0, 360]
z = np.empty(dz.shape[0] * 100)
phi = np.linspace(0, 360, z.shape[0])

for i in xrange(z.shape[0]):
    # To set between [0, 360] instead of [-5, 355]
    idx = (i - 50) % z.shape[0]
    z[idx] = dz[:i/100].sum()
    z[idx] += dzds[i/100] * 0.012 * (i % 100)
    z[idx] += dzds[:i/100].sum() * 1.2

display(Markdown('### Tilt Model (With Closure)'))
plt.scatter(phi_laser, z_laser, color=colors[2], alpha=0.5)
plt.plot(phi, z, c=colors[0])
finish_plot()

The Data

Laser Height vs Azimuth

Tilt Model (With Closure)

Dealing with the ring tilt plane and laser tilt plane

One can observe from differencing the simple tilt model and laser data, that there are residual tilt planes still involved in this story. One tilt plane is the ring with respect to gravity which we can get a proxy for by comparing the tilt model with a flat plane. The second tilt plane is the laser tracker with respect to the ring tilt plane (or gravity, but we are using the ring as our basis). This one we tease out by looking for one omega between the laser data and the corrected tilt sensor model. I ignore yoke D in both of these calculations, since we know it to live above the plane by our choice.

In [4]:
display(Markdown('### Ring Tilt Plane'))

# Pick out all points besides yoke D
idx1 = np.where((phi - 75.0) % 360 > 30.0)
f_z = z[idx1]
f_phi = phi[idx1]

p, cov = curve_fit(sinusoid, f_phi, f_z)
print "(amp, baseline, phase) => (%.2f, %.2f, %.2f)" % (p[0], p[1], p[2] % 360.0)

plt.plot(phi, z, color=colors[0], alpha=0.3)
plt.plot(phi, z - sinusoid(phi, p[0], p[1], p[2]), color=colors[0])
finish_plot()

z_corr = np.array(z - sinusoid(phi, p[0], p[1], p[2]))

display(Markdown('### Laser Height vs Tilt Model (Ring Tilt Plane Removed)'))

f = interp1d(phi, z_corr)

plt.scatter(phi_laser, z_laser, color=colors[0])
plt.scatter(phi_laser, f(phi_laser), color=colors[2])
finish_plot()

display(Markdown('### Laser Tilt Plane (Difference of Laser Height and Tilt Model)'))

# Put the data onto an evenly spaced grid
f_z_laser = interp1d(phi_laser, z_laser - f(phi_laser))
phi_laser_grid = np.linspace(0.5, 359.5, 5001)
z_laser_grid = f_z_laser(phi_laser_grid)

p, cov = curve_fit(sinusoid, phi_laser_grid, z_laser_grid)
print "(amp, baseline, phase) => (%.2f, %.2f, %.2f)" % (p[0], p[1], p[2] % 360.0)

plt.plot(phi_laser_grid, sinusoid(phi_laser_grid, p[0], p[1], p[2]), color=colors[2])
plt.plot(phi_laser_grid, z_laser_grid, color=colors[0])
finish_plot()

plt.scatter(phi_laser, z_laser - sinusoid(phi_laser, p[0], p[1], p[2]), color=colors[0])
plt.scatter(phi, z_corr, color=colors[2])
finish_plot()

z_laser_corr = np.array(z_laser - sinusoid(phi_laser, p[0], p[1], p[2]))

Ring Tilt Plane

(amp, baseline, phase) => (-56.87, 32.70, 61.61)

Laser Height vs Tilt Model (Ring Tilt Plane Removed)

Laser Tilt Plane (Difference of Laser Height and Tilt Model)

(amp, baseline, phase) => (-43.05, 57.49, 269.72)

Fitting for Curvature of Poles

We need to estimate how to fix the curvature of each pole. About the best we can do here is use the laser data.

In [5]:
# Try fitting each pole to a parabola

fit_params = np.empty([36, 8])
fit_tilt = np.empty(36)

bounds = (np.array([-200, -200, -250.0, -50, -4, -0.4, -0.16, -0.032]), np.array([200, 200, 250.0, 50, 0, 0.4, 0.0, 0.032]))

for i in xrange(36):
    f_phi = (phi_laser - i * 10 + 10) % 360
    f_z = np.array(z_laser_corr)
    indices = np.where(f_phi > 0.0)
    f_phi = f_phi[indices]
    f_z = f_z[indices]
    f_w = w_laser[indices]
    indices = np.where(f_phi < 20.0)
    f_phi = f_phi[indices]
    f_z = f_z[indices]
    f_w = f_w[indices]

    indices = f_phi.argsort()
    f_phi = f_phi[indices]
    f_z = f_z[indices]
    
    f_phi -= 10.0
    
    if f_phi.shape[0] == 0:
        continue
        fit_params[i, :] = np.array([0, 0, 0, 0, 0, 0, 0, 0])
        
    else:
        bounds[0][0] = -dz[i-1]
        bounds[1][0] = -dz[i-1] + 0.001
        bounds[0][1] = dz[i]
        bounds[1][1] = dz[i] + 0.001
        ff = interp1d(f_phi, f_z)
        f_phi = np.linspace(-6.0, 6.0, 501)
        f_z = ff(f_phi)
        sigma = np.ones(f_phi.shape[0])
        sigma[np.where(f_phi < -5.0)] *= 0.01
        sigma[np.where(f_phi > 5.0)] *= 0.01
        p, pcor = curve_fit(pole5, f_phi, f_z, bounds=bounds, sigma=sigma, max_nfev=10000)
        plt.scatter(f_phi, f_z, color=colors[i%10], alpha=0.8)
        fit_params[i, :] = p

display(Markdown('### Laser Data For All Poles'))     
plt.show()
    
for i in xrange(36):
    f_phi = np.linspace(10.0 * i - 4.99, 10.0 * i + 4.99, 100)
    p_phi = np.linspace(-4.99, 4.99, 100)
    par = fit_params[i, :]
    plt.plot(f_phi, pole5(p_phi, par[0], par[1], par[2], par[3], par[4], par[5], par[6], par[7]), color=colors[0])
    
    fit_tilt[i] = pole5(1.2214, par[0], par[1], par[2], par[3], par[4], par[5], par[6], par[7])
    fit_tilt[i] -= pole5(-1.2214, par[0], par[1], par[2], par[3], par[4], par[5], par[6], par[7])
    fit_tilt[i] /= 0.29845

display(Markdown('### Quintic Fits to Each Pole Curvature'))
plt.scatter(phi_laser, z_laser_corr, color=colors[2], alpha=0.5)
finish_plot()

Laser Data For All Poles

Quintic Fits to Each Pole Curvature

Radial Pole Tilts

The last piece of the puzzle here is inflecting the correct radial pole tilt on the bottom pole pieces. We have data from field off measurements, and we began the process of taking field on measurements today, 3/15/2016. Comparing the two and knowing that we want to shoot for 45 $\mu rad$ of radial closure with the field on, we can make a plan for the radial adjustment in our bottom pole movement program.

In [6]:
# Load the data for round two.
d1_tilt_rad_cal = np.genfromtxt('data-in/rad_tilt_cal_1_03_07_2016.csv')
d1_tilt_rad_cal_2 = np.genfromtxt('data-in/rad_tilt_cal_2_03_07_2016.csv')
d1_tilt = np.genfromtxt('data-in/pole_tilts_03_07_2016.csv', skip_header=True)

# Set the tilts from day 4 where we measured the radial tilt well, and the azimuthal symbiotically.
d1_tilt_rad = (d1_tilt[:, 1] - d1_tilt_rad_cal[:, 2].mean()) * 1.29
d1_tilt_rad[:9] = (d1_tilt[:9, 1] - d1_tilt_rad_cal[:, 2].mean()) * 1.29
d1_tilt_rad[9:19] = (d1_tilt[9:19, 1] - d1_tilt_rad_cal_2[:, 2].mean()) * 1.29
d1_tilt_rad[19:] = (d1_tilt[19:, 1] - d1_tilt_rad_cal[:, 2].mean()) * 1.29


d2_tilt_rad_cal = np.genfromtxt('data-in/rad_tilt_cal_03_16_2016.csv', skip_header=True)
d2_tilt = np.genfromtxt('data-in/pole_tilts_03_16_2016.csv', skip_header=True)

#d2_tilt_rad = (d2_tilt[:, 2] - 31053.5) * 1.29
d2_tilt_rad = (d2_tilt[:, 2] - d2_tilt_rad_cal[:, 2].mean()) * 1.29

plt.plot(np.linspace(0, 350, 36), d1_tilt_rad, color=colors[0])
plt.plot(np.linspace(0, 350, 36), d2_tilt_rad, color=colors[2])
display(Markdown('### Measured Radial Tilts with Field On/Off'))
finish_plot('radial tilt [$\mu rad$]')

display(Markdown('### Radial Tilt Differences with Field On/Off'))
plt.hist(d2_tilt_rad - d1_tilt_rad, bins=20, color=colors[0])
plt.show()

Measured Radial Tilts with Field On/Off

Radial Tilt Differences with Field On/Off

Pole Adjustments

We can use the steps from tilt sensor measurements, the curvature from most of the polynomial fits, and the radial tilts from measurements field on/off. With all of this info together, we can create a pole movement plan which might still need some spot checking.

In [8]:
# Set target height based on Yoke C
z0 = 55.0
drad = 45.0 - d2_tilt_rad

display(Markdown('### Pole Adjustment Height Goal'))
plt.scatter(phi_laser, z_laser_corr, color=colors[2], alpha=0.75)
for i in xrange(-4, 10):
    plt.axhline(z0 + i * 25, color='gray', linestyle='--', alpha=0.25)

plt.axhline(z0 + 0.0, color='gray', alpha=0.5)
finish_plot()

display(Markdown('### Pole Adjustment Radial Tilt Goal'))
plt.plot(np.linspace(0, 350, 36), 45.0 - d2_tilt_rad + d1_tilt_rad, color='gray', alpha=0.8)
plt.plot(np.linspace(0, 350, 36), d1_tilt_rad, color=colors[0])
finish_plot('radial tilt [$\mu rad$]')

# Calculate pole foot adjustments

# Convenience variables
moves = np.zeros([36, 10])
mean_pole_z = np.zeros(36)

output = ['| Radius | A | B | C | D | E |']
output.append('|-------|------|------|------|------|------|')
output.append('| Inner | %.2f | %.2f | %.2f | %.2f | %.2f |')
output.append('| Outer | %.2f | %.2f | %.2f | %.2f | %.2f |')

for i in xrange(36):

    # Calculate the height displacement
    idx = np.where((phi_laser - (10.0 * i - 5.0)) % 360 < 10.0)
    t_z = z_laser_corr[idx]
    t_phi = phi_laser[idx]

    t_dz = z0 - t_z.mean()
    moves[i, :] = t_dz
    
    if i not in [19, 20]:
        par = fit_params[i, :]
        for j in xrange(5):
            a = -4.788 + 2.394 * j
            moves[i, j] -= pole5(a, par[0], par[1], 0.0, par[3], par[4], par[5], par[6], par[7])
            moves[i, j + 5] -= pole5(a, par[0], par[1], 0.0, par[3], par[4], par[5], par[6], par[7])
            
    else:
        for j in xrange(5):
            f = interp1d(phi, z)
            t_dz0 = (f(t_phi) - t_z).mean()
            a = 10.0 * i - 4.788 + 2.394 * j
            moves[i, j] -= f(a) - t_dz0
            moves[i, j + 5] -= f(a) - t_dz0
        
    
    # Take care of the radial tilt as an average
    for j in xrange(5):
        moves[i, j + 5] += (d2_tilt_rad[i] - 45.0) * 0.51

# Now take care bad pole steps

t_moves = np.array(moves)
for i in xrange(36):
    
    t_dz_inner = -t_moves[i, 0] + t_moves[i - 1, 4]
    t_dz_outer = -t_moves[i, 5] + t_moves[i - 1, 9]

    a3_inner = 0.5 * (t_dz_inner - dz[i-1]) / 4.878**3
    a3_outer = 0.5 * (t_dz_outer - dz_outer[i-1]) / 4.878**3
    
    for j in xrange(0, 2):
        a = -4.788 + 2.394 * j
        moves[i, j] += a3_inner * np.abs(a**3)
        moves[i, j + 5] += a3_outer * np.abs(a**3)
        
    t_dz_inner = -t_moves[(i + 1) % 36, 0] + t_moves[i, 4]
    t_dz_outer = -t_moves[(i + 1) % 36, 5] + t_moves[i, 9]
    
    a3_inner = 0.5 * (t_dz_inner - dz[i]) / 4.878**3
    a3_outer = 0.5 * (t_dz_outer - dz_outer[i]) / 4.878**3
    
    for j in xrange(3, 5):
        a = -4.788 + 2.394 * j
        moves[i, j] -= a3_inner * np.abs(a**3)
        moves[i, j + 5] -= a3_outer * np.abs(a**3)
        
#     print "% .2f % .2f % .2f % .2f % .2f" % tuple(moves[i, :5] - t_moves[i, :5])
#     print "% .2f % .2f % .2f % .2f % .2f" % tuple(moves[i, 5:] - t_moves[i, 5:])
    
display(Markdown('### Pole Adjustment Plan'))
plt.scatter(phi_laser, z_laser_corr, color='#bdbdbd', alpha=1.0)

for i in xrange(36):
    t_phi = np.linspace(10.0 * i - 4.788, 10.0 * i + 4.788, 5)
    plt.scatter(t_phi, z0 - moves[i, :5], alpha=0.9, s=50.0, color=colors[i%10])
    plt.scatter(t_phi, z0 - moves[i, 5:], alpha=0.9, s=50.0, marker='^', color=colors[i%10])

for i in xrange(-4, 10):
    plt.axhline(z0 + i * 25, color='gray', linestyle='--', alpha=0.25)

plt.axhline(z0 + 0.0, color='gray', alpha=0.5)
finish_plot()

display(Markdown('### Perfect Pole Adjustment Results'))

final_z = np.array(z_laser_corr)
for i in xrange(phi_laser.shape[0]):
    n = int(((phi_laser[i] + 5.0) % 360) / 10.0)
    par = fit_params[n, :]
    a = (phi_laser[i] + 5.0) % 10.0 - 5.0
    final_z[i] -= pole5(a, par[0], par[1], par[2], par[3], par[4], par[5], par[6], par[7]) - z0

plt.scatter(phi_laser, final_z, color=colors[2], alpha=0.8)
plt.axhline(z0 + 0.0, color='gray', alpha=0.5)
finish_plot()

display(Markdown('### Pole Steps'))

plt.plot(np.linspace(5, 355, 36), dz, color=colors[0], alpha=0.2)
plt.plot(np.linspace(5, 355, 36), dz_outer, color=colors[2], alpha=0.2)

plan_dz_inner = np.empty(36)
plan_dz_outer = np.empty(36)

plan_dz_inner[:35] = moves[1:, 0] - moves[:-1, 4]
plan_dz_inner[-1] = moves[0, 0] - moves[-1, 4]
plan_dz_outer[:35] = moves[1:, 5] - moves[:-1, 9]
plan_dz_outer[-1] = moves[0, 5] - moves[-1, 9]

plt.plot(np.linspace(5, 355, 36), -plan_dz_inner, color=colors[0], alpha=0.8)
plt.plot(np.linspace(5, 355, 36), -plan_dz_outer, color=colors[2], alpha=0.8)
plt.axhline(50, color='gray', alpha=0.5)
plt.axhline(25, color='gray', alpha=0.5)
plt.axhline(0, color='gray', alpha=0.5)
plt.axhline(-25, color='gray', alpha=0.5)
plt.axhline(-50, color='gray', alpha=0.5)
finish_plot()

display(Markdown('### Inner Feet Shim Changes'))
plt.hist(moves[:, :5].flatten() / 25.4, bins=40, color=colors[0])
plt.show()

display(Markdown('### Outer Feet Shim Changes'))
plt.hist(moves[:, 5:].flatten() / 25.4, bins=40, color=colors[0])
plt.show()

# Print the values.
for i in xrange(36):
    
    display(Markdown('### Pole %i Movements' % (i + 1)))    
    display(Markdown('\n'.join(output) % tuple(moves[i, :] / 25.4)))
    
    
print d2_tilt_rad.mean()
print (moves[:, :5].flatten().mean() - moves[:, 5:].flatten().mean()) / 0.51

Pole Adjustment Height Goal

Pole Adjustment Radial Tilt Goal

Pole Adjustment Plan

Perfect Pole Adjustment Results

Pole Steps

Inner Feet Shim Changes

Outer Feet Shim Changes

Pole 1 Movements

Radius A B C D E
Inner 5.59 4.22 3.72 3.38 2.87
Outer 3.82 2.38 1.87 1.56 1.20

Pole 2 Movements

Radius A B C D E
Inner 2.97 2.87 2.61 2.36 2.30
Outer 0.99 1.05 0.81 0.57 0.56

Pole 3 Movements

Radius A B C D E
Inner 2.84 2.25 1.99 1.99 2.45
Outer 0.42 -0.12 -0.38 -0.30 0.68

Pole 4 Movements

Radius A B C D E
Inner 1.77 1.96 1.96 1.94 1.99
Outer 0.76 1.49 1.56 1.50 1.29

Pole 5 Movements

Radius A B C D E
Inner 2.33 2.61 2.84 3.19 3.72
Outer 1.07 1.08 1.28 1.70 2.78

Pole 6 Movements

Radius A B C D E
Inner 3.16 2.59 2.68 2.81 2.99
Outer 2.91 2.89 3.05 3.21 3.54

Pole 7 Movements

Radius A B C D E
Inner 2.74 2.37 2.66 3.03 3.80
Outer 3.48 3.27 3.58 3.90 4.28

Pole 8 Movements

Radius A B C D E
Inner 4.03 3.15 2.78 2.54 3.99
Outer 4.36 3.09 2.67 2.46 4.19

Pole 9 Movements

Radius A B C D E
Inner -2.20 -1.68 -1.35 -0.96 -0.04
Outer -0.97 -0.18 0.20 0.60 1.58

Pole 10 Movements

Radius A B C D E
Inner -1.21 -0.00 -0.13 -0.28 0.81
Outer 0.88 2.15 2.03 1.90 3.14

Pole 11 Movements

Radius A B C D E
Inner 0.38 0.96 0.80 1.25 3.87
Outer 2.59 3.32 3.18 3.72 7.04

Pole 12 Movements

Radius A B C D E
Inner 2.38 2.61 2.15 1.61 1.41
Outer 5.56 6.49 6.12 5.63 5.66

Pole 13 Movements

Radius A B C D E
Inner 1.36 0.88 0.77 0.76 1.26
Outer 6.16 5.91 5.84 5.84 6.37

Pole 14 Movements

Radius A B C D E
Inner 0.89 1.35 1.69 2.01 2.31
Outer 6.07 6.57 6.91 7.10 6.55

Pole 15 Movements

Radius A B C D E
Inner 3.55 1.85 1.73 1.97 1.52
Outer 6.40 3.83 3.59 3.82 3.28

Pole 16 Movements

Radius A B C D E
Inner 3.46 2.52 2.64 3.20 3.37
Outer 5.29 4.26 4.37 4.91 4.91

Pole 17 Movements

Radius A B C D E
Inner 4.18 3.00 2.69 2.85 3.03
Outer 5.52 4.17 3.85 3.96 3.82

Pole 18 Movements

Radius A B C D E
Inner 1.95 1.00 1.54 2.32 2.51
Outer 2.59 1.32 1.81 2.54 2.34

Pole 19 Movements

Radius A B C D E
Inner 2.59 2.85 3.36 3.95 5.49
Outer 2.48 2.35 2.81 3.38 4.80

Pole 20 Movements

Radius A B C D E
Inner 4.53 4.20 3.85 3.38 2.15
Outer 3.63 3.17 2.81 2.31 0.94

Pole 21 Movements

Radius A B C D E
Inner 1.60 1.28 1.71 2.21 2.39
Outer 0.93 0.46 0.87 1.42 1.96

Pole 22 Movements

Radius A B C D E
Inner 3.82 3.58 3.34 3.17 3.50
Outer 3.45 3.57 3.38 3.16 3.14

Pole 23 Movements

Radius A B C D E
Inner 3.31 2.63 2.67 2.81 3.46
Outer 2.69 1.66 1.65 1.70 1.77

Pole 24 Movements

Radius A B C D E
Inner 0.73 2.10 2.69 3.19 3.91
Outer -0.25 0.54 1.05 1.55 2.25

Pole 25 Movements

Radius A B C D E
Inner 4.74 3.65 3.13 2.77 2.59
Outer 3.45 2.35 1.82 1.51 1.64

Pole 26 Movements

Radius A B C D E
Inner 2.06 1.67 1.58 1.65 1.93
Outer 0.84 0.76 0.72 0.86 1.68

Pole 27 Movements

Radius A B C D E
Inner 1.74 1.92 2.13 2.48 3.12
Outer 2.59 3.31 3.60 4.02 5.20

Pole 28 Movements

Radius A B C D E
Inner 3.16 2.52 2.43 2.43 2.37
Outer 5.80 5.69 5.68 5.69 5.67

Pole 29 Movements

Radius A B C D E
Inner 3.40 2.22 1.64 1.39 1.24
Outer 6.58 5.44 4.87 4.34 2.31

Pole 30 Movements

Radius A B C D E
Inner 1.93 0.44 0.54 1.48 2.18
Outer 2.08 -1.29 -1.46 -0.50 0.36

Pole 31 Movements

Radius A B C D E
Inner 2.70 2.13 2.07 2.47 3.78
Outer 0.98 0.57 0.53 0.99 2.75

Pole 32 Movements

Radius A B C D E
Inner 2.90 2.49 1.58 0.73 1.14
Outer 2.16 2.19 1.34 0.54 1.29

Pole 33 Movements

Radius A B C D E
Inner 0.12 -0.04 0.27 0.52 0.04
Outer 0.89 1.07 1.42 1.72 1.54

Pole 34 Movements

Radius A B C D E
Inner -0.22 0.67 1.04 1.45 2.68
Outer 1.61 2.79 3.20 3.59 4.62

Pole 35 Movements

Radius A B C D E
Inner 2.62 3.59 3.53 3.50 4.68
Outer 4.66 5.42 5.33 5.13 5.10

Pole 36 Movements

Radius A B C D E
Inner 4.33 4.16 3.30 3.25 5.12
Outer 3.83 2.46 1.43 1.37 3.18
70.95
-25.95
In [ ]: