In [3]:
#Imports
from math import *
import numpy as np
import scipy as sp
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
import sys
import os
#Matplotlib settings
mpl.rcParams['mathtext.fontset'] = 'stix'
mpl.rcParams['font.family'] = 'STIXGeneral'
sns.set(font_scale=2.0)
sns.set_style("darkgrid")
sns.set_palette(palette='deep')
sns.set_color_codes(palette='deep')
#Import custom modules
from physics import *
%matplotlib notebook
In [4]:
def Background(data,interval):
"""Calculates the background of a data set given an interval over which there is no true signal"""
return np.mean(np.mean(data[:,interval[0]:interval[1]],axis=0))
def Signal(data,interval):
"""Calculates the true signal by subtracting the background"""
return data - Background(data,interval)
def AverageSignal(data,interval):
"""Calculates the average signal"""
return np.mean(Signal(data,interval),axis=0)
def Radius(KE):
"""Returns radius of electron orbit in m given KE in keV"""
return me*c/(q*B0)*np.sqrt((KE*1000*q/(me*c**2)+1)**2-1)
def zfcalc(KE,y):
"""Returns the z-position at the screen in inches given the KE in keV and the distance between the
electron injection position and the screen (y) in m"""
R = Radius(KE)
return np.sqrt(R**2 - (y-R)**2)
def zfcalcGeneral(KE,yM,y):
"""Returns the z-position at the screen in inches given the KE in keV, and the distance between the
electron injection position and the screen (y) in m, and the magnet edge y-position yM in m"""
R = Radius(KE)
zM = zfcalc(KE,yM) #Final z-position of the electrons once they reach the magnet edge
return zM + (y - yM)*(R - yM)/zM
def KEcalcGeneral(zf,yM,yf):
"""Returns KE in J given z-position of electrons, y-position of magnet edge, and y-position of screen, all in m"""
a = (yM+yf)**2
b = -2*yM*(yf*(yM+yf)+zf**2)
d = yM**2*(zf**2+yf**2)
f = (me*c)/(q*B0)
g = (-b+np.sqrt(b**2-4*a*d))/(2*a)
return me*c**2*(np.sqrt(g**2+f**2)/f - 1)
In [5]:
filepath1MeV = './ND_Data/Yoke_1MeV_10ms/traces.csv'
data1MeV = np.genfromtxt(filepath1MeV, delimiter=',')
filepath2MeV = './ND_Data/Yoke_2MeV_0.58nA_4ms_003/traces.csv'
data2MeV = np.genfromtxt(filepath2MeV, delimiter=',')
filepath2p5MeV = './ND_Data/Yoke_2.5MeV_2ms/traces.csv'
data2p5MeV = np.genfromtxt(filepath2p5MeV, delimiter=',')
In [6]:
interval = (0,100) #there appears to be no signal over this interval
Signal1MeV = Signal(data1MeV,interval)
AverageSignal1MeV = AverageSignal(data1MeV,interval)
Signal2MeV = Signal(data2MeV,interval)
AverageSignal2MeV = AverageSignal(data2MeV,interval)
Signal2p5MeV = Signal(data2p5MeV,interval)
AverageSignal2p5MeV = AverageSignal(data2p5MeV,interval)
In [7]:
fig1 = plt.figure(figsize=(12,8))
ax1 = fig1.add_subplot(111)
ax1.set_xlim(0,3648)
ax1.set_xlabel('Pixel')
ax1.set_ylabel('Instance')
mesh1 = ax1.pcolormesh(Signal1MeV, cmap='viridis',vmin=0, vmax=np.max(Signal1MeV))
colorbar = fig1.colorbar(mesh1)
colorbar.set_label('Pixel Value')
plt.show()
In [8]:
plt.figure()
plt.plot(AverageSignal1MeV,label='1.0 MeV')
plt.plot(AverageSignal2MeV,label='2.0 MeV')
plt.plot(AverageSignal2p5MeV,label='2.5 MeV')
plt.xlim(0,3648)
plt.ylim(0)
plt.xlabel('Pixel')
plt.ylabel('Pixel Value')
plt.legend()
plt.tight_layout()
plt.show()
In [9]:
Integral1MeV = np.sum(AverageSignal1MeV[1200:2000])
Integral2MeV = np.sum(AverageSignal2MeV[1000:2000])
Integral2p5MeV = np.sum(AverageSignal2p5MeV[1000:2000])
print('1 MeV integral =',Integral1MeV)
print('2 MeV integral =',Integral2MeV)
print('2.5 MeV integral =',Integral2p5MeV)
In [10]:
filepath1MeV = './ND_Data/Yoke_1MeV_10ms/traces.csv'
Data1MeV = np.genfromtxt(filepath1MeV, delimiter=',')
filepath1p8MeV = './ND_Data/Yoke_1.8MeV_10ms/traces.csv'
Data1p8MeV = np.genfromtxt(filepath1p8MeV, delimiter=',')
filepath2MeV = './ND_Data/Yoke_2MeV_0.58nA_4ms_003/traces.csv'
Data2MeV = np.genfromtxt(filepath2MeV, delimiter=',')
filepath2p5MeV = './ND_Data/Yoke_2.5MeV_2ms/traces.csv'
Data2p5MeV = np.genfromtxt(filepath2p5MeV, delimiter=',')
interval1MeV = (3000,3500) #there appears to be no signal over this interval
interval1p8MeV = (0,500)
interval2MeV = (0,500)
interval2p5MeV = (0,500)
Signal1MeV = Signal(Data1MeV,interval)
AverageSignal1MeV = AverageSignal(Data1MeV,interval1MeV)
Signal1p8MeV = Signal(Data1p8MeV,interval)
AverageSignal1p8MeV = AverageSignal(Data1p8MeV,interval1p8MeV)
Signal2MeV = Signal(Data2MeV,interval)
AverageSignal2MeV = AverageSignal(Data2MeV,interval2MeV)
Signal2p5MeV = Signal(Data2p5MeV,interval)
AverageSignal2p5MeV = AverageSignal(Data2p5MeV,interval2p5MeV)
In [11]:
fig2 = plt.figure(figsize=(12,8))
ax1 = fig2.add_subplot(111)
ax1.set_xlim(0,3648)
ax1.set_xlabel('Pixel')
ax1.set_ylabel('Instance')
mesh = ax1.pcolormesh(Signal1MeV, cmap='viridis',vmin=0, vmax=np.max(Signal1MeV))
colorbar = fig2.colorbar(mesh)
colorbar.set_label('Pixel Value')
plt.show()
In [12]:
B0 = 2136.0
yM = 0.5 #magnet edge position in inches
r0 = [0,-12.7,-12.7] #initial position in mm
CCDpos = 3.02 #CCD y-position relative to magnet edge in mm
HoleSep = 0.16 #Separation between holes in inches
#Convert to base units
B0 = B0/10**4
yM = yM*0.0254
r0 = np.multiply(r0,10**-3)
CCDpos = CCDpos*10**-3
HoleSep *= 0.0254
yf = yM + CCDpos
zfinalTheory1MeV = zfcalcGeneral(1000,-r0[1], -r0[1]+CCDpos)*10**3
zfinalTheoryPixels1MeV = (zfinalTheory1MeV - 9.5)*1000/8
zfinalTheory1p8MeV = (zfcalcGeneral(1800,-r0[1], -r0[1]+CCDpos) - 3*HoleSep)*10**3
zfinalTheoryPixels1p8MeV = (zfinalTheory1p8MeV - 9.5)*1000/8
zfinalTheory2MeV = zfcalcGeneral(2000,-r0[1], -r0[1]+CCDpos)*10**3
zfinalTheoryPixels2MeV = (zfinalTheory2MeV - 9.5)*1000/8
zfinalTheory2p5MeV = (zfcalcGeneral(2500,-r0[1], -r0[1]+CCDpos) - 3*HoleSep)*10**3
zfinalTheoryPixels2p5MeV = (zfinalTheory2p5MeV - 9.5)*1000/8
In [13]:
pixels = np.arange(3648)
position = pixels*8/1000 + 9.5
EnergyTheory = KEcalcGeneral(np.multiply(position,10**-3),yM,yf)/(10**6*q)
EnergyCalibration = np.vstack((pixels,EnergyTheory))
np.savetxt('Energy_Calibration_2136Gauss.csv',np.transpose(EnergyCalibration),delimiter=',')
In [14]:
plt.figure()
plt.plot(pixels,EnergyTheory)
Out[14]:
In [15]:
SmoothedSignal1MeV = savitzky_golay(AverageSignal1MeV,window_size=51,order=5)
SmoothedSignal1p8MeV = savitzky_golay(AverageSignal1p8MeV,window_size=51,order=5)
SmoothedSignal2MeV = savitzky_golay(AverageSignal2MeV,window_size=51,order=5)
SmoothedSignal2p5MeV = savitzky_golay(AverageSignal2p5MeV,window_size=51,order=5)
fig3 = plt.figure()
plt.plot(SmoothedSignal1MeV,label='1 MeV',color='b')
plt.plot(AverageSignal1p8MeV,label='1.8 MeV',color='g')
plt.plot(SmoothedSignal2MeV,label='2 MeV',color='r')
plt.plot(SmoothedSignal2p5MeV,label='2.5 MeV',color='k')
plt.axvline(zfinalTheoryPixels1MeV,color='b',linestyle='--')
plt.axvline(zfinalTheoryPixels1p8MeV,color='g',linestyle='--')
plt.axvline(zfinalTheoryPixels2MeV,color='r',linestyle='--')
plt.axvline(zfinalTheoryPixels2p5MeV,color='k',linestyle='--')
plt.ylim(0)
plt.xlabel('Pixel')
plt.ylabel('Pixel Value')
plt.legend(loc=1,fontsize=16)
plt.tight_layout()
zfinalExpPixels1MeV = np.argmax(SmoothedSignal1MeV)
zfinalExpPixels1p8MeV = np.argmax(SmoothedSignal1p8MeV)
zfinalExpPixels2MeV = np.argmax(SmoothedSignal2MeV)
zfinalExpPixels2p5MeV = np.argmax(SmoothedSignal2p5MeV)
print('Predicted 1 MeV location:',round(zfinalTheoryPixels1MeV))
print('Actual 1 MeV location:',zfinalExpPixels1MeV)
print('Error:',abs(round(zfinalTheoryPixels1MeV)-zfinalExpPixels1MeV)/zfinalExpPixels1MeV*100,'%')
print('\n')
print('Predicted 1.8 MeV location:',round(zfinalTheoryPixels1p8MeV))
print('Actual 1.8 MeV location:',zfinalExpPixels1p8MeV)
print('Error:',abs(round(zfinalTheoryPixels1p8MeV)-zfinalExpPixels1p8MeV)/zfinalExpPixels1p8MeV*100,'%')
print('\n')
print('Predicted 2MeV location:',round(zfinalTheoryPixels2MeV))
print('Actual 2MeV location:',zfinalExpPixels2MeV)
print('Error:',abs(round(zfinalTheoryPixels2MeV)-zfinalExpPixels2MeV)/zfinalExpPixels2MeV*100,'%')
print('\n')
print('Predicted 2.5 MeV location:',round(zfinalTheoryPixels2p5MeV))
print('Actual 2.5 MeV location:',zfinalExpPixels2p5MeV)
print('Error:',abs(round(zfinalTheoryPixels2p5MeV)-zfinalExpPixels2p5MeV)/zfinalExpPixels2p5MeV*100,'%')
plt.savefig('Energy calibration comparison with experiment (adjusted for varying CCD position).svg')
In [16]:
# filepath1MeV_560pA = './ND_Data/NoYoke_1MeV_0.58nA_0.5ms/traces.csv'
# Data1MeV_560pA = np.genfromtxt(filepath1MeV_560pA, delimiter=',')
# interval = (0,100) #there appears to be no signal over this interval
# Signal1MeV_560pA = Signal(Data1MeV_560pA,interval)
# AverageSignal1MeV_560pA = AverageSignal(Data1MeV_560pA,interval)
filepath2MeV_390pA = './ND_Data/Yoke_2MeV_0.58nA_10ms/traces.csv'
Data2MeV_390pA = np.genfromtxt(filepath2MeV_390pA, delimiter=',')
interval = (0,100) #there appears to be no signal over this interval
Signal2MeV_390pA = Signal(Data2MeV_390pA,interval)
AverageSignal2MeV_390pA = AverageSignal(Data2MeV_390pA,interval)
filepath2MeV_760pA = './ND_Data/Yoke_2MeV_0.95nA_0.1ms/traces.csv'
Data2MeV_760pA = np.genfromtxt(filepath2MeV_760pA, delimiter=',')
interval = (0,100) #there appears to be no signal over this interval
Signal2MeV_760pA = Signal(Data2MeV_760pA,interval)
AverageSignal2MeV_760pA = AverageSignal(Data2MeV_760pA,interval)
In [17]:
plt.figure()
plt.plot(AverageSignal2MeV_390pA,label='390 pA')
plt.plot(AverageSignal2MeV_760pA,label='760 pA')
plt.axvline(zfinalTheoryPixels2MeV,linestyle='--')
plt.xlim(0,3648)
plt.ylim(0)
plt.xlabel('Pixel')
plt.ylabel('Pixel Value')
plt.legend(loc=2)
plt.tight_layout()