Commit 7d9fd5e7 authored by Peter Jansweijer's avatar Peter Jansweijer

Merge branch 'peter_insitu_alpha' into proposed_master

Conflicts:
	sw/insitu_alpha/analyze_sellmeier.py
parents a6f79c6f 29db66a2
......@@ -46,8 +46,8 @@ lib_path = os.path.join(lib_path,"..")
sys.path.insert(0,lib_path)
# private imports:
import lib.LeCroy8254 as DSO
#import lib.Keysight_DSO_S_254A as DSO
#import lib.LeCroy8254 as DSO
import lib.Keysight_DSO_S_254A as DSO
#import lib.Agilent_DSO6104A as DSO
import lib.pat_gen as pat_gen
import lib.delay_determination as dd
......@@ -195,7 +195,18 @@ if __name__ == "__main__":
# Initialize oscilloscope
# Use Channel 1 pulse input
# use Channel 3-4 Ethernet Frame input
DSO.osc_init(scope, args.timebase)
init = { \
'channel' : [ 1 , 0 , 1 , 1 ], \
'offset' : [ 0.0 , 0.0, 0.0 , 0.0 ], \
'volt_div' : [ 0.1 , 1.0, 0.25, 0.25 ], \
'50ohm' : [ 1 , 0 , 1 , 1 ], \
'trig' : [ 1 ], \
'trig_level' : [ 0.15 ], \
'timebase' : [ float(args.timebase) ], \
'refclk' : [ 'ext' ], \
}
DSO.osc_init(scope, init)
meas, samples, sample_period, first_filename, last_filename = average_edge_to_edge(scope, num_meas=args.m, expect_max=args.peak, estimate=args.delay, tolerance=args.tol)
......
......@@ -80,8 +80,8 @@ lib_path = os.path.join(lib_path,"..")
sys.path.insert(0,lib_path)
# private imports:
import lib.LeCroy8254 as DSO
#import lib.Keysight_DSO_S_254A as DSO
#import lib.LeCroy8254 as DSO
import lib.Keysight_DSO_S_254A as DSO
#import lib.Agilent_DSO6104A as DSO
import lib.pat_gen as pat_gen
import lib.delay_determination as dd
......@@ -313,7 +313,17 @@ if __name__ == "__main__":
# Initialize oscilloscope
# Use Channel 1 pulse input
# use Channel 3-4 Ethernet Frame input
DSO.osc_init(scope, args.timebase)
init = { \
'channel' : [ 1 , 0 , 1 , 1 ], \
'offset' : [ 0.0 , 0.0, 0.0 , 0.0 ], \
'volt_div' : [ 0.25, 1.0, 0.1 , 0.1 ], \
'50ohm' : [ 1 , 0 , 1 , 1 ], \
'trig' : [ 1 ], \
'trig_level' : [ 0.15 ], \
'timebase' : [ float(args.timebase) ], \
'refclk' : [ 'ext' ], \
}
DSO.osc_init(scope, init)
edge_to_sfd, samples, sample_period, first_filename, last_filename = average_edge_to_sfd(scope, num_meas=args.m, bit_width=args.bitwidth, expect_max_edge=args.edge, expect_max_sfd=args.sfd, estimate=args.delay, tolerance=args.tol)
print("Samples:",samples)
......
#!/usr/bin/python
"""
AnalyzeScopeData
-------------------------------------------------------------------------------
Copyright (C) 2017 Peter Jansweijer, Henk Peek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
-------------------------------------------------------------------------------
Usage:
AnalyzeScopeData.py <waveform_file>
AnalyzeScopeData.py -h | --help
<waveform_file> <type 'str'> file name that contains the DSO traces
Options:
-h --help Show this screen.
--version Show version.
"""
action = "standard"
# action = "length scale test" # measurement datafile length scale factor test
# action = "sample period test" # measurement datafile sample period scale factor test
import os
import sys
import vxi11
import scipy
import numpy
import matplotlib.pyplot as plt
import math
import pdb
# Add parent directory (containing 'lib') to the module search path
lib_path = (os.path.dirname(os.path.abspath(__file__)))
lib_path = os.path.join(lib_path,"..")
sys.path.insert(0,lib_path)
# import docopt
#import lib.LeCroy8254 as DSO
import lib.Keysight_DSO_S_254A as DSO
import lib.delay_determination as dd
directories = False
data1 = []
data2 = []
lastdirname = ""
first = True
filecount = 0
wf_file = ""
def selectfile(filelist,dirpath,dofile):
for name in filelist:
# print("selectfile dir name " + dirpath + "file name " + str(name))
wf_file = os.path.join(dirpath,name)
if os.path.isdir(wf_file):
selectfile(os.listdir(wf_file),wf_file,dofile)
else:
fullfilenamepath = os.path.join(dirpath,name)
dirname = os.path.dirname(fullfilenamepath)
filename = os.path.basename(fullfilenamepath)
dofile(filename,dirname)
def docount(name,dirpath):
global directories
# print("dowork dirname " + dirpath + "filename " + name)
# print("dowork dirname " + os.path.dirname(os.path.join(dirpath,name)))
if os.path.dirname(os.path.join(dirpath,name)) != "" : directories = True
def dowork(filename,dirname):
global lastdirname, first, filecount, data1, data2, directories, wf_file, lopt, topt
print("dowork dirname " + dirname + "filename " + str(filename))
if dirname != lastdirname:
if data1 != []:
# wf_file_dir_name = os.path.dirname(wf_file)
result_file_data = lastdirname + " circulair-mean: " + str(numpy.mean(data1)) + \
" se: " + str(numpy.std(data1,ddof=1)) + \
" sem: " + str(numpy.std(data1,ddof=1)/math.sqrt(len(data1))) + \
" lpot: " + str(lopt) + "\n" + \
lastdirname + " lineair-mean: " + str(numpy.mean(data2)) + \
" se: " + str(numpy.std(data2,ddof=1)) + \
" sem: " + str(numpy.std(data2,ddof=1)/math.sqrt(len(data2))) + \
" topt: " + str(topt) + "\n"
print(result_file_data)
print("stat result file: ", os.path.join(lastdirname,"stat_result.txt"))
result_file = open(os.path.join(lastdirname,"stat_result.txt"),"a")
result_file.write(result_file_data)
result_file.close()
#append the results also to the result.txt file in the working directory
# os.system('cat ' + lastdirname + '/stat_result.txt >> result.txt')
data1 = []
data2 = []
filecount = 0
wf_file = os.path.join(dirname, filename)
try:
wf_data = DSO.file_to_waveform(wf_file)
if len(wf_data) <= 1:
print ("No, or only one oscilloscope trace in the data filea",wf_file)
print ("Correlation is not possible!")
return()
else:
print ("Oscilloscope data file contains "+str(len(wf_data))+" traces")
except:
print (wf_file," is no DSO file")
return()
# Take the first two available traces from the data
trace1 = sorted(wf_data.keys())[0]
trace2 = sorted(wf_data.keys())[1]
print ("Correlate channels "+str(trace1)+" and "+str(trace2))
samples = DSO.check_waveforms(wf_data)
sample_period = wf_data[trace1]["preamble"]["x_increment"]
x1 = wf_data[trace1]["waveform"][0][:samples]
y1 = wf_data[trace1]["waveform"][1][:samples]
x2 = wf_data[trace2]["waveform"][0][:samples]
y2 = wf_data[trace2]["waveform"][1][:samples]
# Test datafile length by divide the datafile length by "lopt"
# "lopt" is defoult 1
samples = samples / (lopt * topt)
# Make sure the buffer holds an even number of samples
a , b = divmod(samples,2)
samples = 2 * a
# The correlation reference point is halfway the array of samples
correlation_zero = int(samples/2)
# Test sample periode by multiplying by "topt"
# "topt" is defualt 1
#for i in range(0,samples):
x1 = x1[::topt]
y1 = y1[::topt]
x2 = x2[::topt]
y2 = y2[::topt]
sample_period = sample_period * topt
# doff = 8 # 200ps
# y1d = numpy.empty_like(y1)
# for i, y in enumerate(y1[doff:]):
# y1d[i] = y-y1[i-doff]
# for i in range(doff):
# y1d[i]=y1d[doff]
# y2d = numpy.empty_like(y2)
# for i, y in enumerate(y2[doff:]):
# y2d[i] = y-y2[i-doff]
# for i in range(doff):
# y2d[i]=y2d[doff]
if first:
wf_fig = plt.figure("waveform")
ax = wf_fig.add_subplot(111)
ax.set_xlabel('time')
ax.set_ylabel('volatge ch:'+str(trace1)+" and "+str(trace2))
ax.plot(x1,y1)
ax.plot(x2,y2)
plt.draw()
# wf_fig = plt.figure("waveform-d")
# ax = wf_fig.add_subplot(111)
# ax.set_xlabel('time')
# ax.set_ylabel('volatge ch:'+str(trace1)+" and "+str(trace2))
# ax.plot(x1,y1d)
# ax.plot(x2,y2d)
# ax.plot(x1,y1d**3)
# ax.plot(x2,y2d**3)
# plt.draw()
cx, cy = dd.correlate_circular(y1, y2)
cor_ref = int(samples/2)
estimated_max = numpy.argmax(cy) - correlation_zero
# print ("estimated max raw type: ",type(estimated_max))
# if emstimated_max is more + 3 ns: wrong correlation: add 2**7-1 (=PRBS-7) gigabit periods (= 800 ps)
if estimated_max < -400/topt: # -12E-9 / sample_period:
estimated_max = numpy.int64(estimated_max + ((2**7-1) * 0.8E-9)/(sample_period*topt)) # (2**7-1) * 0.8E-9 / sample_period
# print ("estimated max type: ",type(estimated_max),estimated_max)
delay1 = sample_period * dd.peak_position(cx, cy, x_estimate = estimated_max)
cor=50
cory=numpy.correlate(y1[estimated_max:],y2[cor:-estimated_max-cor],mode="valid")
corx=numpy.arange(estimated_max -cor,estimated_max + cor+1 )
cor_estimated_max=numpy.argmax(cory)+estimated_max-cor
# print("main convole cory: ",type(cory),cory)
print("main convole cor_estimated_max: ",type(cor_estimated_max),cor_estimated_max)
delay2 = sample_period * dd.peak_position(corx, cory, x_estimate = estimated_max)
print ("circulair delay1: ", delay1, "lineair delay2: ", delay2)
# plt.plot(corx,cory)
# plt.plot(corx,y1[:10001])
# plt.plot(corx,y2[:10001])
# plt.draw()
# plt.show()
# pdb.set_trace()
# zx, zy = dd.correlate_linear(y1, y2, center = estimated_max)
# print("main lineair correlate zx: ", type(zx),zx)
# print("main lineair correlate zy: ", type(zy),zy)
# z_estimated_max = numpy.argmax(zy) - correlation_zero
# print("main lineair correlate z_estimated_max: ", type (z_estimated_max),z_estimated_max)
# delay2 = sample_period * dd.peak_position(zx, zy, x_estimate = z_estimated_max)
print(wf_file + " estimated circulair sample max: " + str(estimated_max) + " circulair delay " + str(delay1))
if directories:
# print("result file: ", os.path.join(dirname,"result.txt"))
result_file = open(os.path.join(dirname,"result.txt"),"a")
result_file.write(str(filecount) + " " +wf_file + ": circulair " + str(delay1) + " lineair " + str(delay2) + " " + "\n")
result_file.close()
data1.append(delay1)
data2.append(delay2)
if first:
first = False
cor_fig = plt.figure("correlation")
ax = cor_fig.add_subplot(111)
ax.text(0.01,0.95,'correlation of ch: '+str(trace1)+' and '+str(trace2), transform=ax.transAxes)
ax.text(0.01,0.90,'delay at estimated max {0:f} = {1:.6g}'.format(estimated_max,delay1), transform=ax.transAxes)
ax.set_xlabel('sample')
ax.set_ylabel('correlation')
ax.plot(cx,cy)
plt.draw()
# cor_fig = plt.figure("correlation-d")
# ax = cor_fig.add_subplot(111)
# ax.set_xlabel('sample')
# ax.set_ylabel('correlationi')
# ax.plot(cdx,cdy)
# plt.draw()
lastdirname = dirname
filecount += 1
############################################################################
##
## If run from commandline, we can test the library
##
if __name__ == "__main__":
selectfile(sys.argv[1:],"",docount)
# print("directories " + str(directories))
lopt = 1 # measurement datafile length scale factor
topt = 1 # measurement datafile sample period scale factor
if action == "standard":
selectfile(sys.argv[1:],"",dowork)
dowork("","") #dummy call to generate last result stat file
if action == "length scale test":
for lopt in [1,2,4,8,16,32,64]:
selectfile(sys.argv[1:],"",dowork)
dowork("","") #dummy call to generate last result stat file
if action == "sample period test":
for topt in [1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40]:
selectfile(sys.argv[1:],"",dowork)
dowork("","") #dummy call to generate last result stat file
plt.show()
# working_directory_result_file=open("result.tst","a")
# working_directory_result_file.write(result_file_data)
# os.system('cat ' + dir_name_0 + '/data*/stat_result.txt >> ' + dir_name_0 + '/result.txt')
# working_directory_result_file.close()
#!/usr/bin/python
"""
calc.py: Analyses the stat_result files that were output by AnalyzeScopeData.py
and takes the linear correlation results to calculate the final optical to
electrical delay of the photo detector.
-------------------------------------------------------------------------------
Copyright (C) 2017 Peter Jansweijer, Henk Peek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
-------------------------------------------------------------------------------
Usage:
calc.py <root-name> (for example "180928_12_09_18_3_lambda_insitu_alpha_scan")
calc.py -h | --help
<root-name> identifies the files to analyse. Four files have the root-name plus:
<root-name>_l1_a lambda 1 (-> lambda 2)
<root-name>_l2_a lambda 2
<root-name>_l2_b lambda 2 (-> lambda 1)
<root-name>_l1_b lambda 1
so two sets of files are recorded: 'a' setting first lambda 1 then lambda 2
and 'b' setting first lambda 2 then lambda 1. This is to evaluate whether
tuning in one or the other direction is of influence on the CRTT measurements.
So far this has not been an issue.
Options:
-h --help Show this screen.
-t tolerance [ps], skip points outside fitted line, default: "200"
-i use ITU channels instead of wavelength
"""
import os
import sys
import scipy
import numpy
import matplotlib.pyplot as plt
import pdb
# Add parent directory (containing 'lib') to the module search path
lib_path = (os.path.dirname(os.path.abspath(__file__)))
lib_path = os.path.join(lib_path,"..")
sys.path.insert(0,lib_path)
############################################################################
def read_stat_result(dirname,sign="neg"):
"""
read_stat_result
dirname -- pointer to the directory that contains the stat_result.txt file
sign -- default "neg" i.e. stat_result lineair-mean values are negative due
-- to the fact that channel 1 and 3 of the oscilloscope are swapped.
returns:
fail, lin_meas
-- <Bool> fail = True when an error occurred while reading the file
-- <Tuple> lin_meas [0] = lineair-mean,
-- [1] = se,
-- [2] = sem,
"""
if not(os.path.isdir(dirname)):
print(dirname+": is not a directory.")
return (True,nan)
stat_result_filename = os.path.join(dirname,"stat_result.txt")
if not(os.path.isfile(stat_result_filename)):
print(stat_result_filename + ": No stat_result.txt file found.")
return (True,nan)
stat_result_file = open(stat_result_filename,"r")
while 1:
# Lines look like this:
# data/data_181106_1/181106_2 lineair-mean: -6.79100959999e-10 se: 2.16707944778e-14 sem: 4.33415889555e-15 topt: 1 if line == "":
line = stat_result_file.readline()
if line == "":
break #end of file
line_lst = line.strip().split(" ")
if "lineair" in line_lst[1]:
if sign == "neg":
lin_meas = -float(line_lst[2]), float(line_lst[4]), float(line_lst[6])
else:
lin_meas = +float(line_lst[2]), float(line_lst[4]), float(line_lst[6])
return (False,lin_meas)
return (True,nan)
###########################################################################
def write_meas(file_ptr,meas_txt,meas):
"""
Test whether a measurement is present or not
If not then exit with a failure message
file_ptr -- <file> Pointer to output file
meas_txt -- <Str> preceding string
meas -- <Tuple> lin_meas [0] = lineair-mean,
-- [1] = se,
-- [2] = sem,
returns:
"""
file_ptr.write(meas_txt + str(meas[0]) + ", " + str(meas[1]) + ", " + str(meas[2]) + "\n")
return
###########################################################################
#
# If run from commandline, we can test the library
#a_meas[
"""
Usage:
calc.py <root-name> (for example "180928_12_09_18_3_lambda_insitu_alpha_scan")
calc.py -h | --help
<root-name> identifies the files to analyse. Four files have the root-name plus:
<root-name>_l1_a lambda 1 (-> lambda 2)
<root-name>_l2_a lambda 2
<root-name>_l2_b lambda 2 (-> lambda 1)
<root-name>_l1_b lambda 1
so two sets of files are recorded: 'a' setting first lambda 1 then lambda 2
and 'b' setting first lambda 2 then lambda 1. This is to evaluate whether
tuning in one or the other direction is of influence on the CRTT measurements.
So far this has not been an issue.
Options:
-h --help Show this screen.
-t tolerance [ps], skip points outside fitted line, default: "200"
-i use ITU channels instead of wavelength
"""
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name", help="directory that contains the measurement files _a, _b1, _b2, _c, _d1, _d2, _e, _f")
args = parser.parse_args()
name = args.name
files = []
# Figure out if the input files exist. Extensions should be:
files_exist = True
if not(os.path.isdir(name)):
print(name+": is not a directory.")
print("Provide the root that contains measurement subdirectories _a, _b1, _b2, _c, _d1, _d2, _e, _f")
sys.exit()
meas_dirs = os.listdir(name)
fail = True
for meas_dir in meas_dirs:
#print(os.path.join(name,meas_dir))
if meas_dir[-2:] == "_aux":
fail,aux_meas = read_stat_result(os.path.join(name,meas_dir))
elif meas_dir[-2:] == "_a":
fail,a_meas = read_stat_result(os.path.join(name,meas_dir))
elif meas_dir[-2:] == "b1":
fail,b1_meas = read_stat_result(os.path.join(name,meas_dir))
elif meas_dir[-2:] == "b2":
fail,b2_meas = read_stat_result(os.path.join(name,meas_dir))
elif meas_dir[-2:] == "_c":
fail,c_meas = read_stat_result(os.path.join(name,meas_dir))
elif meas_dir[-2:] == "d1":
fail,d1_meas = read_stat_result(os.path.join(name,meas_dir))
elif meas_dir[-2:] == "d2":
fail,d2_meas = read_stat_result(os.path.join(name,meas_dir))
elif meas_dir[-2:] == "_e":
fail,e_meas = read_stat_result(os.path.join(name,meas_dir))
elif meas_dir[-2:] == "_f":
fail,f_meas = read_stat_result(os.path.join(name,meas_dir))
if fail:
print(" failed at file: " + os.path.join(name,meas_dir))
sys.exit()
# Check if all mandatory measurements are present:
try:
a_meas[0]
except:
print("FAIL: no file found for measurements _a")
sys.exit()
try:
b1_meas[0]
except:
print("FAIL: no file found for measurements _b1")
sys.exit()
try:
b2_meas[0]
except:
print("FAIL: no file found for measurements _b2")
sys.exit()
try:
c_meas[0]
except:
print("FAIL: no file found for measurements _c")
sys.exit()
try:
d1_meas[0]
except:
print("FAIL: no file found for measurements _d1")
sys.exit()
try:
d2_meas[0]
except:
print("FAIL: no file found for measurements _d2")
sys.exit()
try:
e_meas[0]
except:
print("FAIL: no file found for measurements _e")
sys.exit()
try:
f_meas[0]
except:
print("FAIL: no file found for measurements _f")
sys.exit()
# Now do the calculations:
# lineair-mean values are tuple [0] items
# lineair-se are tuple [1] items, lineair-sem are tuple[2] items
D_f = (85.36e-12,1.1e-13,1.1e-14)
Type_B_err = (1.1e-12,0,1.67929e-12)
# note that b and d are two measurements; take the mean value and
# calculate their standard deviation and standard error.
b_meas = ((b1_meas[0] + b2_meas[0])/2, numpy.sqrt(b1_meas[1]**2 + b2_meas[1]**2)/2, numpy.sqrt(b1_meas[2]**2 + b2_meas[2]**2)/2)
d_meas = ((d1_meas[0] + d2_meas[0])/2, numpy.sqrt(d1_meas[1]**2 + d2_meas[1]**2)/2, numpy.sqrt(d1_meas[2]**2 + d2_meas[2]**2)/2)
# https://doi.org/10.1364/OE.26.014650
# fill in Eq. (10)
D_OE = ((-a_meas[0] - b_meas[0] + c_meas[0] - d_meas[0] + e_meas[0] + f_meas[0] + D_f[0]) / 2) - Type_B_err[0]
# Eq. (10) fraction errors:
frac_se = numpy.sqrt(a_meas[1]**2 + b_meas[1]**2 + c_meas[1]**2 + d_meas[1]**2 + e_meas[1]**2 + f_meas[1]**2 + D_f[1]**2) / 2
frac_sem = numpy.sqrt(a_meas[2]**2 + b_meas[2]**2 + c_meas[2]**2 + d_meas[2]**2 + e_meas[2]**2 + f_meas[2]**2 + D_f[2]**2) / 2
# Eq. (10) total errors:
D_OE_se = numpy.sqrt(frac_se**2 + Type_B_err[1]**2)
D_OE_sem = numpy.sqrt(frac_sem**2 + Type_B_err[2]**2)
result_file = open(os.path.join(name,"calc_result.txt"),"w")
result_file.write("# Calculated result for eooe measurement\n")
result_file.write("# file: " + os.path.join(name,"calc_result.txt") + "\n")
write_meas(result_file, "a, ", a_meas)
write_meas(result_file, "b, ", b_meas)
write_meas(result_file, "c, ", c_meas)
write_meas(result_file, "d, ", d_meas)
write_meas(result_file, "e, ", e_meas)
write_meas(result_file, "f, ", f_meas)
result_file.write("\n")
result_file.write("D_OE, " + str(D_OE) + "\n")
result_file.write("D_OE_se, " + str(D_OE_se) + "\n")
result_file.write("D_OE_sem, " + str(D_OE_sem) + "\n")
result_file.close()
print("a: ", a_meas)
print("b: ", b_meas)
#print("b1: ", b1_meas)
#print("b2: ",b2_meas)
print("c: ",c_meas)
print("d: ",d_meas)
#print("d1: ",d1_meas)
#print("d2: ",d2_meas)
print("e: ",e_meas)
print("f: ",f_meas)
print("D_OE", D_OE)
#print("frac_se", frac_se)
#print("frac_sem", frac_sem)
print("D_OE_se", D_OE_se)
print("D_OE_sem", D_OE_sem)
sys.exit()
electrical to optical and vice versa scripts
\ No newline at end of file
#!/usr/bin/python
"""
analyze.py: Analyzes itu_channel/wavelength/crtt that was stored in a file
-------------------------------------------------------------------------------
Copyright (C) 2017 Peter Jansweijer, Henk Peek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
-------------------------------------------------------------------------------
Usage:
analyze.py <name>
analyze.py -h | --help
<name> if name is a filename and the file contains the crtt
measurements then this file is analyzed and plotted
if the name is a directory then the files in this
directory are analyzed and the result is output in a
file "result.txt"
Options:
-h --help Show this screen.
-t tolerance [ps], skip points outside fitted line, default: "200"
-i use ITU channels instead of wavelength
"""
import os
import sys
import scipy
from scipy.optimize import curve_fit
import numpy
import matplotlib.pyplot as plt
import pdb
# Add parent directory (containing 'lib') to the module search path
lib_path = (os.path.dirname(os.path.abspath(__file__)))
lib_path = os.path.join(lib_path,"..")
sys.path.insert(0,lib_path)
# private imports:
import lib.itu_conversions as itu_conv
import lib.wrt_sfppt015sc as tunable
############################################################################
def file_to_dict(filename):
"""
Retrieve the measurement file
filename -- source file from which to retrieve data.
returns: True, <type 'dict'>
key : value
itu_channel: [wavelength, crtt, temperature, SFP ch_numb]
False
"Not an In Situ Alpha measurements file"
"""
# create an empty dictionairy
crtt_data = {}
data_file = open(filename, "r")
line = data_file.readline()
if line.strip() != "#In Situ Alpha measurements":
Exception("file_to_dict: Not an In Situ Alpha measurements file.")
data_file.close()
return (False, crtt_data)
line = data_file.readline() # Read date
line = data_file.readline() # Read time
line = data_file.readline() # Read comment
# create an empty lists for fields:
# sfp module channel, ITU channel, ITU wavelength [nm], crtt
while 1:
line = data_file.readline()
if line[:len("#")] != "#": # Skip lines that are commented out
line_lst = line.split(",")
if len(line_lst) < 4:
break
# Values of interest on one line are:
# channel, ITU channel, ITU wavelength [nm], crtt [ps], drxm, drxs
# note that there may be multiple measurment lines (link restarts) for a give set
# of {channel, ITU channel, ITU wavelength}
lst_meas = []
lst_meas.append(float(line_lst[2])) # Wavelength
# try if there is already an entry for the ITU channel on this line
# if so then read the already existing list of crtt measurements
try:
existing_crtt_list = crtt_data[float(line_lst[1])][1]
except:
existing_crtt_list = []
try:
existing_temp_list = crtt_data[float(line_lst[1])][1]
except:
existing_temp_list = []
existing_crtt_list.append(float(line_lst[3])) # append the crtt measurement of the current line
existing_temp_list.append(float(line_lst[6])) # append the temperature measurement of the current line
lst_meas.append(existing_crtt_list) # append the list of all crtt measurments
lst_meas.append(existing_temp_list) # append the list of all temperature measurments
lst_meas.append(int(line_lst[0])) # append sfp module channel number
crtt_data.update({float(line_lst[1]): lst_meas}) # itu_channel: [wavelength, [list_of_crtt], SFP ch_numb]
data_file.close()
return (True, crtt_data)
############################################################################
def dict_to_narray(crtt_data):
"""
converts the data that is stored in crtt_data <type 'dict'> into
<type 'numpy.ndarray'>
returns: <type 'numpy.ndarray'>
"""
crtt_array = {}
lst_channel = []
lst_itu_channel = []
lst_itu_wavelength = []
lst_crtt = []
lst_temp = []
for key_itu_ch, value_itu_ch in sorted(crtt_data.items()):
lst_itu_channel.append(key_itu_ch)
lst_itu_wavelength.append(value_itu_ch[0])
#lst_crtt.append(value_itu_ch[1])
# crtt measurements is a list of one (or more for multiple link
# restarts) crtt measurments.
# calculate the mean value of the all crtt measurements and
# temperature measurements
crtt_meas = numpy.array(value_itu_ch[1])
crtt_mean = numpy.mean(crtt_meas)
lst_crtt.append(crtt_mean)
temp_meas = numpy.array(value_itu_ch[2])
temp_mean = numpy.mean(temp_meas)
lst_temp.append(temp_mean)
lst_channel.append(value_itu_ch[2])
crtt_array["itu_channel"]=scipy.array(lst_itu_channel)
crtt_array["itu_wavelength"]=scipy.array(lst_itu_wavelength)
crtt_array["crtt"]=scipy.array(lst_crtt)
crtt_array["temp"]=scipy.array(lst_temp)
crtt_array["channel"]=scipy.array(lst_channel)
return (crtt_array)
############################################################################
def spec_alpha(alpha):
"""
returns the value of alpha as it is used by the SPEC
(see also White Rabbit Calibration procudeure:
http://www.ohwr.org/attachments/4092/WR_Calibration-v1.1-20151109.pdf
equation 11.
alpha -- <float> alpha value
returns:
alpha -- <float> alpha according to SPEC
"""
return(2**40 * (((alpha+1)/(alpha+2))-0.5))
############################################################################
def calc_alpha_l1(lambda_1, lambda_2, crtt_lambda_1, crtt_lambda_2, fixed_lambda):
"""
calc_alpha_l1 calculates the alpha factor for wavelength lambda l1.
For this caluculation we need two cable round trip times that were measured
using lamdba l1 and lambda l2 while both used a common fixed_lambda for the
return channel.
lambda_1, lambda_2, fixed_lambda -- <float> lambda's in [m]
crtt_l1, crtt_l2 -- <float> cable round trip times measured
at lambda_1 and lambda_2
returns:
alpha_lambda_1 -- <float>
"""
delta_lambda_1 = lambda_1 - fixed_lambda
delta_lambda_2 = lambda_2 - fixed_lambda
crtt_diff = crtt_lambda_1 - crtt_lambda_2
lambda_diff = lambda_1 - lambda_2
alpha_lambda_1 = (2 * delta_lambda_1 * crtt_diff)/((crtt_lambda_1 * lambda_diff) - (crtt_diff * delta_lambda_1))
return (alpha_lambda_1)
############################################################################
def calc_alpha(l, crtt_l, tangent, fixed_lambda):
"""
calc_alpha calculates the alpha factor for the wavelength lambda l.
It takes the cable rount trip time that was measured at this lambda
(crtt_l) while using fixed_lambda for the return path.
The tangent is the slope of variation in time over wavelength.
l -- <float> lambda [m]
crtt_l -- <int> cable round trip time measured at lambda l
using fixed_lambda on the return channel [ps]
tangent -- <float> [ps/nm]
fixed_lambda -- <float> fixed return channel lambda [m]
returns:
alpha -- <float> alpha value for lambda l when using fixed_lambda
as return channel
"""
delta_l = (l - fixed_lambda)
alpha = (2* tangent * delta_l )/(crtt_l - tangent * delta_l )
return(alpha)
############################################################################
def line(x, a, b):
return a * x + b
############################################################################
#
# If run from commandline, we can test the library
#
"""
Usage:
analyze.py <name>
analyze.py -h | --help
<name> if name is a filename and the file contains the crtt
measurements then this file is analyzed and plotted
if the name is a directory then the files in this
directory are analyzed and the result is output in a
file "result.txt"
Options:
-h --help Show this screen.
-t tolerance [ps], skip points outside fitted line, default: "200"
-i use ITU channels instead of wavelength
"""
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name", help="file or directory name containing crtt measurements")
parser.add_argument("-tolerance", default=200)
parser.add_argument("-i", action='store_true')
args = parser.parse_args()
name = args.name
tolerance = int(args.tolerance)
use_itu_channels = args.i
fixed_itu_channel = 20
isfile = False
files = []
# Keep tangent and temperature values in an array in case multiple
# files are processed.
tangent_array = numpy.array([])
temperature_array = numpy.array([])
if os.path.exists(name) == True:
if os.path.isdir(name) == True:
print(name+": is a directory")
# Any result files already there will be removed
if os.path.isfile(os.path.join(name,"result.txt")) == True:
os.remove(os.path.join(name, "result.txt"))
# Get a file list (exclude files with extentions!)
for file_name in os.listdir(name):
if len(file_name.split('.')) <= 1:
files.append(os.path.join(name, file_name))
# (re) open result.txt file
result_file = open(os.path.join(name, "result.txt"),"w")
result_file.write("file: outlier-count, tangent, mean-temperature\n")
elif os.path.isfile(name) == True:
isfile = True
print(name+": is a file")
files.append(name)
else:
print("unexpected error")
sys.exit()
else:
print(name+": does not exist")
sys.exit()
#print(files)
for insitu_file in sorted(files):
try:
measurementfile, crtt_data = file_to_dict(insitu_file)
except:
print (insitu_file + ": wrong file type")
continue
if measurementfile == True:
print(insitu_file)
crtt_array = dict_to_narray(crtt_data)
#pdb.set_trace()
if use_itu_channels:
x = crtt_array["itu_channel"]
else:
# Note that values are converted to [nm] instead of [m]
# the curve fit function seems not to be able to handle otherwise
x = 1e9*crtt_array["itu_wavelength"]
y = crtt_array["crtt"]
t = crtt_array["temp"]
# create an array of length (x) elements with a tolerance value
tol = numpy.zeros(len(x))
tol.fill(tolerance)
try:
popt, pcov = curve_fit(line, x, y)
# define the best fit line based on array (still with outliers):
ly=[]
for i in x:
ly.append(line(i,popt[0],popt[1]))
# loop over all array elements and list the indexes of the
# outliers based on best fit line + tolerance
outlier_idx = []
outlier_cnt = 0
for i in range(len(x)):
if abs(ly[i] - y[i]) >= tolerance:
outlier_idx.append(i)
outlier_cnt = outlier_cnt + 1
#print(x[i],"is an outlier")
# create "clean" arrays where the outliers are removed based on the indexes found above
x_clean = x # in [nm]!
y_clean = y
t_clean = t
for i in sorted(outlier_idx, reverse=True):
x_clean = numpy.delete(x_clean, i)
y_clean = numpy.delete(y_clean, i)
t_clean = numpy.delete(t_clean, i)
# Tackle the case when all datapoints are regarded as outlier due to narrow tolerance
if len(x_clean) == 0:
print("Scattered datapoints => all outliers!")
print("Try to loosen the tolerance (for example -t 1000)")
sys.exit()
popt_clean, pcov_clean = curve_fit(line, x_clean, y_clean)
tangent = popt_clean[0] # in [ps]/[nm]
tangent_array = numpy.append(tangent_array,tangent)
# for this particular tangent measurement, take the mean value of the
# temperatures during the measurement.
temperature = t_clean.mean()
temperature_array = numpy.append(temperature_array,temperature)
# again define the best fit line, now based on clean arrays:
ly_clean=[]
alpha_clean=[]
fixed_lambda = itu_conv.itu_2_wavelength(fixed_itu_channel)
### Test. Take ITU channel 11 as a refernce and calculate alpha for this
# wavelength using a scan over all other lambda's and crtt measurments
alpha_tst=[]
tst_lambda_1 = crtt_array["itu_wavelength"][0] # ITU channel 11 is refernce
tst_crtt_1 = crtt_array["crtt"][0]
for i in range(1,len(x_clean)):
l2 = x_clean[i]/1e9 # convert back to [m]
crtt_l2 = y_clean[i]
alpha_tst.append(calc_alpha_l1(tst_lambda_1, l2, tst_crtt_1, crtt_l2, fixed_lambda))
# scan through all wavelengths and calculate the individual alpha's
# using the tangent that was found from the fitted line through the
# clean datapoints.
# Note: that the tangent is in [ps]/[nm] for proper alpha calculation
# we need [ps]/[m]
for i in x_clean: # scan through all wavelengths in [nm]!
clean_y = line(i,popt_clean[0],popt_clean[1])
ly_clean.append(clean_y)
alpha_clean.append(calc_alpha(i/1e9, clean_y, tangent*1e9, fixed_lambda))
fig = plt.figure("CRTT versus ITU Channel number")
ax = fig.add_subplot(111)
ax.set_ylabel('CRTT [ps]')
ax.text(0.01, 0.95, str(insitu_file), transform=ax.transAxes)
ax.text(0.01, 0.90, "tolerance: " + str(tolerance) + "; outliers: " + str(outlier_cnt), transform=ax.transAxes)
ax.text(0.01, 0.85, "fit y = a * x + b", transform=ax.transAxes)
ax.text(0.01, 0.80, "a:" + str(popt_clean[0]), transform=ax.transAxes)
ax.text(0.01, 0.75, "b:" + str(popt_clean[1]), transform=ax.transAxes)
if use_itu_channels:
ax.set_xlabel('ITU Channel number')
ax.text(0.01, 0.70, "tangent:" + str(tangent) + " [ps/ITU channel]", transform=ax.transAxes)
else:
ax.set_xlabel('Wavelenth [nm]')
ax.text(0.01, 0.70, "tangent:" + str(tangent) + " [ps/nm]", transform=ax.transAxes)
ax.plot(x, y) # Original datapoints
ax.plot(x, ly, ".") # best fit line
ax.plot(x, ly + tol, ".") # best fit line with + tolerances
ax.plot(x, ly - tol, ".") # best fit line with - tolerances
ax.plot(x_clean, y_clean) # cleaned array in [nm]
ax.plot(x_clean, ly_clean) # final clean fit line in [nm]
fig.savefig(insitu_file+".png")
if isfile: # Analyze single file => plot
fig_alpha = plt.figure("alpha as a function of wavelength")
ax = fig_alpha.add_subplot(111)
if use_itu_channels:
ax.set_xlabel('ITU Channel number')
else:
ax.set_xlabel('Wavelenth [nm]')
ax.set_ylabel('Alpha')
ax.axhline(0, color='gray')
ax.axvline(fixed_lambda*1e9, color='red')
ax.plot(x_clean, alpha_clean)
alpha_file = open(name+".out","w")
alpha_file.write("file: " + insitu_file + "\n")
alpha_file.write("outlier-count: " + str(outlier_cnt) + "\n")
alpha_file.write("tangent: " + str(tangent)+ " [ps]/[nm]\n")
alpha_file.write("============================\n")
alpha_file.write("ITU_Channel, Lambda, alpha, aplha(SPEC format)\n")
for i in range(len(x_clean)):
wavelength = x_clean[i]
itu_ch = itu_conv.wavelength_2_itu(wavelength/1e9)
alpha_file.write(str(itu_ch) + ", " + str(wavelength) + ", " + str(alpha_clean[i]) + ", " + str (spec_alpha(alpha_clean[i])) + "\n")
alpha_file.close()
#pdb.set_trace()
plt.draw()
plt.show()
else: # Analyze multiple files => output result file
fig.clf() # clear figure (it was stored in a png file)
result_file.write(insitu_file + ": " + str(outlier_cnt) + ", " + str(tangent) + ", " + str(temperature) + "\n")
except:
print("file probably only contians measurements for a single wavelength")
continue
#else: measurementfile == False => wrong file type
# Finally, after scanning all files in a directory (i.e. not a single file)
# => add statistics:
if not(isfile):
result_file.write("\n")
result_file.write("tolerance applied: " + str(tolerance) + "\n")
result_file.write("tangent:\n")
result_file.write("Mean: " + str(tangent_array.mean()) +"\n")
result_file.write("StDev: " + str(tangent_array.std(ddof=1)) +"\n")
sys.exit()
#!/usr/bin/python
"""
analyze_3lambda.py: Analyzes itu_channel/wavelength/crtt that was recorded and
stored in a file using wr_serial_3lamda.py
-------------------------------------------------------------------------------
Copyright (C) 2017 Peter Jansweijer, Henk Peek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
-------------------------------------------------------------------------------
Usage:
analyze_3lambda.py <root-name> (for example "180928_12_09_18_3_lambda_insitu_alpha_scan")
analyze_3lambda.py -h | --help
<root-name> identifies the files to analyse. Four files have the root-name plus:
<root-name>_l1_a lambda 1 (-> lambda 2)
<root-name>_l2_a lambda 2
<root-name>_l2_b lambda 2 (-> lambda 1)
<root-name>_l1_b lambda 1
so two sets of files are recorded: 'a' setting first lambda 1 then lambda 2
and 'b' setting first lambda 2 then lambda 1. This is to evaluate whether
tuning in one or the other direction is of influence on the CRTT measurements.
So far this has not been an issue.
Options:
-h --help Show this screen.
-t tolerance [ps], skip points outside fitted line, default: "200"
-i use ITU channels instead of wavelength
"""
import os
import sys
import scipy
from scipy.optimize import curve_fit
import numpy
import matplotlib.pyplot as plt
import pdb
# Add parent directory (containing 'lib') to the module search path
lib_path = (os.path.dirname(os.path.abspath(__file__)))
lib_path = os.path.join(lib_path,"..")
sys.path.insert(0,lib_path)
# private imports:
import lib.itu_conversions as itu_conv
import lib.wrt_sfppt015sc as tunable
############################################################################
def spec_alpha(alpha):
"""
returns the value of alpha as it is used by the SPEC
(see also White Rabbit Calibration procudeure:
http://www.ohwr.org/attachments/4092/WR_Calibration-v1.1-20151109.pdf
equation 11.
alpha -- <float> alpha value
returns:
alpha -- <float> alpha according to SPEC
"""
return(2**40 * (((alpha+1)/(alpha+2))-0.5))
############################################################################
def calc_alpha_l1(lambda_1, lambda_2, crtt_lambda_1, crtt_lambda_2, fixed_lambda):
"""
calc_alpha_l1 calculates the alpha factor for wavelength lambda l1.
For this calculation we need two cable round trip times that were measured
using lamdba l1 and lambda l2 while both used a common fixed_lambda for the
return channel.
lambda_1, lambda_2, fixed_lambda -- <float> lambda's in [m]
crtt_l1, crtt_l2 -- <float> cable round trip times [ps] measured
at lambda_1 and lambda_2
returns:
alpha_lambda_1 -- <float>
"""
delta_lambda_1 = lambda_1 - fixed_lambda
delta_lambda_2 = lambda_2 - fixed_lambda
crtt_diff = crtt_lambda_1 - crtt_lambda_2
lambda_diff = lambda_1 - lambda_2
alpha_lambda_1 = (2 * delta_lambda_1 * crtt_diff)/((crtt_lambda_1 * lambda_diff) - (crtt_diff * delta_lambda_1))
return (alpha_lambda_1)
############################################################################
def calc_alpha_tangent(l, crtt_l, tangent, fixed_lambda):
"""
calc_alpha_tangent calculates the alpha factor for the wavelength lambda l.
It takes the cable rount trip time that was measured at this lambda
(crtt_l) while using fixed_lambda for the return path.
The tangent is the slope of variation in time over wavelength.
l -- <float> lambda [m]
crtt_l -- <int> cable round trip time measured at lambda l
using fixed_lambda on the return channel [ps]
tangent -- <float> [ps/nm]
fixed_lambda -- <float> fixed return channel lambda [m]
returns:
alpha -- <float> alpha value for lambda l when using fixed_lambda
as return channel
"""
delta_l = (l - fixed_lambda)
alpha = (2* tangent * delta_l )/(crtt_l - tangent * delta_l )
return(alpha)
############################################################################
def calc_alpha_sellmeier(l, fixed_lambda, A, B, C, D, E):
"""
calc_alpha_sellmeier calculates the alpha factor for the wavelength lambda l
while using fixed_lambda for the return path.
It takes the Sellmeier cooefcients that came out of a cable rount trip time
wavelength scan.
l -- <float> lambda [m]
fixed_lambda -- <float> fixed return channel lambda [m]
a..e -- <float> Sellmeier terms
returns:
alpha -- <float> alpha value for lambda l when using fixed_lambda
as return channel
"""
bb = l**2 - fixed_lambda**2
cc = l**-2 - fixed_lambda**-2
dd = l**4 - fixed_lambda**4
ee = l**-4 - fixed_lambda**-4
alpha = 2* (B*bb + C*cc + D*dd + E*ee)/(A + B*fixed_lambda**2 + C*fixed_lambda**-2 + D*fixed_lambda**4 + E*fixed_lambda**-4)
return(alpha)
############################################################################
def calc_alpha_error(alpha1, alpha2, crtt_fixed_lambda):
"""
calc_alpha_error calculates the timing error between the PPS-ses of Master
and Slave that will be the result of an "imperfect" alpha2 with respect to a
"perfect" alpha1.
The timing error scales linear with the round trip time (i.e. the length of
your fiber)
alpha1 -- <float> alpha to be considered the correct value
alpha2 -- <float> alpha for which timing error needs to be calculated
crtt_fixed_lambda -- <float> crtt value at the fixed wavelenght.
note that this is the virtual crtt for which
master2slave and slave2master wavelengths would be
equal. It can be estimated by extrapolating the crtt
array.
returns:
t_err -- <float> PPS time error
"""
t_err = ((alpha1-alpha2)*crtt_fixed_lambda)/4
return(t_err)
############################################################################
def line(x, a, b):
return a * x + b
############################################################################
def group_delay(l, A, B, C, D, E):
"""
group_delay calculates the group delay for the wavelength lambda l based on
the 5-term Sellmeier equation with coefficients A..E.
5-term sellmeier group delay:
tau(lambda) = A + B * lambda^2 + C * lambda^-2 + D * lambda^4 + E * lambda^-4
A..E -- <numpy.float64> Sellmeier coefficients
l -- <float> lambda is in [nm].
-- Note! Convert to [m] before executing sellmeier fit
returns:
delay -- <float> group delay value based on selm5 and l
"""
# l = lambda is in [nm]. convert to [m] before executing sellmeier fit
l = l/1e9
sellmeier_5 = A + B * l**2 + C * l**-2 + D * l**4 + E * l**-4
# and convert fitted value back to [nm]
return sellmeier_5 * 1e9
############################################################################
def read_file(filename):
"""
read_file
filename -- pointer to an open datafile
returns:
data_dict -- <dict> with key "ITU-Lambda1 = ##.#, ITU-Lambda2 = ##.#"
and values:
number of measurements
mean crtt value
stddev of crtt values
"""
data_file = open(os.path.join(filename),"r")
line = data_file.readline()
if line[:len("#3-lambda measurement for")] != "#3-lambda measurement for":
print(filename + " is not a 3-lambda measurement file.")
data_file.close()
sys.exit()
line = data_file.readline() # Read date
line = data_file.readline() # Read time
line = data_file.readline() # Read comment
crtt = []
ITU_l1 = ""
ITU_l2 = ""
key = ""
# create an empty dictionary for storing mean and stddev crtt's
data_dict = {}
while 1:
line = data_file.readline()
if line == "":
break #end of file
# files look like this:
#sfp_channel, ITU channel, ITU wavelength, crtt [ps], drxm, drxs, fiber-spool-temp, wr-slave-temp, meas-time
#ITU-Lambda1 = 18.0, ITU-Lambda2 = 19.0
#15, 18.0, 1.5630472262773723e-06, 492049342.6666667, 4000, 800, 24.499611, 47.4375, 15:49:26
if line[:len("ITU-Lambda1")] == "ITU-Lambda1": # Get Lambda 1 and 2 ITU channel numbers
line_lst = line.strip().split(",")
if len(crtt) != 0:
crtt_arr=numpy.array(crtt)
crtt_mean = crtt_arr.mean(axis=0)
crtt_std = crtt_arr.std(axis=0,ddof=1)
#print ("ITU: ", ITU_l1, ITU_l2)
#print("crtt:", len(crtt), crtt_mean, crtt_std)
data_dict[key]= len(crtt), crtt_mean, crtt_std
crtt = [] # clean and ready for the next set
key = line.strip()
ITU_l1 = float(line_lst[0][len("ITU Lambda1 = "):])
ITU_l2 = float(line_lst[1][len("ITU Lambda2 = "):])
else:
line_lst = line.strip().split(",")
crtt.append(float(line_lst[3])) # 3-rd item is CRTT
# catch the last accumulated crtt's
if len(crtt) != 0:
crtt_arr=numpy.array(crtt)
crtt_mean = crtt_arr.mean(axis=0)
crtt_std = crtt_arr.std(axis=0,ddof=1)
#print ("ITU: ", ITU_l1, ITU_l2)
#print("crtt:", len(crtt), crtt_mean, crtt_std)
data_dict[key]= len(crtt), crtt_mean, crtt_std
return (data_dict)
###########################################################################
#
# If run from commandline, we can test the library
#
"""
Usage:
analyze_3lambda.py <root-name> (for example "180928_12_09_18_3_lambda_insitu_alpha_scan")
analyze_3lambda.py -h | --help
<root-name> identifies the files to analyse. Four files have the root-name plus:
<root-name>_l1_a lambda 1 (-> lambda 2)
<root-name>_l2_a lambda 2
<root-name>_l2_b lambda 2 (-> lambda 1)
<root-name>_l1_b lambda 1
so two sets of files are recorded: 'a' setting first lambda 1 then lambda 2
and 'b' setting first lambda 2 then lambda 1. This is to evaluate whether
tuning in one or the other direction is of influence on the CRTT measurements.
So far this has not been an issue.
Options:
-h --help Show this screen.
-t tolerance [ps], skip points outside fitted line, default: "200"
-i use ITU channels instead of wavelength
"""
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name", help="root-name for _l1_a, _l2_a, _l1_b, _l2_b files")
args = parser.parse_args()
name = args.name
fixed_itu_channel = 20
fixed_lambda = itu_conv.itu_2_wavelength(fixed_itu_channel)
files = []
# Keep tangent and temperature values in an array in case multiple
# files are processed.
tangent_array = numpy.array([])
temperature_array = numpy.array([])
# Figure out if the input files exist. Extensions should be:
files_exist = True
ext = ["_l1_a", "_l2_a", "_l1_b", "_l2_b"]
for extension in ext:
if os.path.isfile(name + extension) == False:
files_exist = False
if files_exist:
print("files found:")
else:
print(name+": does not exist")
sys.exit()
# analyse the set of four files files
# create an empty dictionary for storing mean and stddev crtt's for each of the four files
data_set={}
for extension in sorted(ext):
try:
print (name + extension)
data_set[extension]=read_file(name + extension)
except:
print (name + extension + ": wrong file type")
continue
"""
for data_set_key,data_set_value in data_set.items():
print("===============")
print(data_set_key) # Is one of "_l1_a", "_l2_a", "_l1_b", "_l2_b"
#print(data_set_value)
print("===============")
# For each "_l1_a", "_l2_a", "_l1_b", "_l2_b"
# get keys (for example: "ITU-Lambda1 = 18.0, ITU-Lambda2 = 21.0")
# get values (number of measurements, mean crtt value, stddev of crtt values)
for key,value in data_set_value.items():
print(key)
print(value)
"""
l1_stddev = 3e-12 # 3 [pm]
l2_stddev = 3e-12 # 3 [pm]
fixed_lambda_stddev = 3e-12 # 3 [pm]
# name is the root file name. Get the directory where this file exists and
# open a "result.txt" file in this directory
result_file = open((name + "_result.txt"),"w")
result_file.write("# Proposed 3-Lambda Delta Delay measurements\n")
result_file.write("# file: " + name + "\n")
result_file.write("# fixed_lambda: " + str(fixed_lambda) + " = ITU-ch: "+str(fixed_itu_channel)+"\n")
result_file.write("# Lambda 1, Lambda 2, CRTT(Lambda_1), CRTT(Lambda_2), Fixed Lambda, Alpha, Alpha SPEC format, Alpha StdDev, Alpha/Alpha_StdDev\n")
for key,value in data_set["_l1_a"].items():
# Get the ITU channel numbers used for lambda 1 and 2 and
# convert them to wavelength in [m]
key_lst=key.split(",")
ITU_l1 = float(key_lst[0][len("ITU Lambda1 = "):])
ITU_l2 = float(key_lst[1][len("ITU Lambda2 = "):])
l1 = itu_conv.itu_2_wavelength(ITU_l1)
l2 = itu_conv.itu_2_wavelength(ITU_l2)
# It can be seen (print statements below) that the difference in measured CRTT for
# ("_l1_a" - "_l1_b") and ("_l2_a" - "_l2_b") is within the stddev of the measured
# crtt values. This proves that the direction from which the tunable laser is set
# doesn't contribute to a systematic error.
# Therefore the average over all measurements ("_l1_a" + "_l1_b")/2 is taken to be the
# value for lambda 1 (and the same for lambda 2) as well as the RMS value of the stddev.
crtt_1_meas = data_set["_l1_a"][key][0] + data_set["_l1_b"][key][0]
crtt_2_meas = data_set["_l2_a"][key][0] + data_set["_l2_b"][key][0]
crtt_1a_1b_diff = (data_set["_l1_a"][key][1] - data_set["_l1_b"][key][1])
crtt_2a_2b_diff = (data_set["_l2_a"][key][1] - data_set["_l2_b"][key][1])
crtt_1 = (data_set["_l1_a"][key][1] + data_set["_l1_b"][key][1])/2
crtt_2 = (data_set["_l2_a"][key][1] + data_set["_l2_b"][key][1])/2
crtt_1_stddev = numpy.sqrt(data_set["_l1_a"][key][2]**2 + data_set["_l1_b"][key][2]**2)
crtt_2_stddev = numpy.sqrt(data_set["_l2_a"][key][2]**2 + data_set["_l2_b"][key][2]**2)
print("===============")
print(key)
print("===============")
print("Lambda 1: ", l1)
print("===============")
print("Number of measurements: ", crtt_1_meas)
print("CRTT a-b diff: ", crtt_1a_1b_diff)
print("CRTT average: ", round(crtt_1))
print("CRTT stddev: ", crtt_1_stddev)
print("===============")
print("Lambda 2: ", l2)
print("===============")
print("Number of measurements: ", crtt_2_meas)
print("CRTT a-b diff: ", crtt_2a_2b_diff)
print("CRTT average: ", round(crtt_2))
print("CRTT stddev: ", crtt_2_stddev)
# Calculate the (mean) value of alpha
alpha = calc_alpha_l1(l1, l2, crtt_1, crtt_2, fixed_lambda)
alphaspec = spec_alpha(alpha)
# Calculate the stddev contribution to alpha of each of the parameters l1, l2, crtt_l1, crtt_l2 and fixed_lambda
alpha_stddev_l1 = calc_alpha_l1(l1 + l1_stddev, l2, crtt_1, crtt_2, fixed_lambda) - alpha
alpha_stddev_l2 = calc_alpha_l1(l1, l2 + l2_stddev, crtt_1, crtt_2, fixed_lambda) - alpha
alpha_stddev_crtt_1 = calc_alpha_l1(l1, l2, crtt_1 + crtt_1_stddev, crtt_2, fixed_lambda) - alpha
alpha_stddev_crtt_2 = calc_alpha_l1(l1, l2, crtt_1, crtt_2 + crtt_2_stddev, fixed_lambda) - alpha
alpha_stddev_fixed_lambda = calc_alpha_l1(l1, l2, crtt_1, crtt_2, fixed_lambda + fixed_lambda_stddev) - alpha
# Calculate the RMS stddev of alpha
alpha_stddev = numpy.sqrt(alpha_stddev_l1**2 + alpha_stddev_l2**2 + alpha_stddev_crtt_1**2 + alpha_stddev_crtt_2**2 + alpha_stddev_fixed_lambda **2)
print("===============")
print("fixed_lambda: ", fixed_lambda)
print("delta_l1: ", l1-fixed_lambda)
print("delta_l2: ", l2-fixed_lambda)
print("l1-l2: ", l1-l2)
print("alpha ", alpha )
print("alpha_stddev_l1 ", alpha_stddev_l1 )
print("alpha_stddev_l2 ", alpha_stddev_l2 )
print("alpha_stddev_crtt_1 ", alpha_stddev_crtt_1 )
print("alpha_stddev_crtt_2 ", alpha_stddev_crtt_2 )
print("alpha_stddev_fixed_lambda ", alpha_stddev_fixed_lambda)
print("alpha_stddev ", alpha_stddev )
print("===============")
result_file.write(str(l1) + ", " + str(l2) + ", " + str(crtt_1) + ", " + str(crtt_2) + ", " + str(fixed_lambda) + ", " + str(alpha) + ", " + str(alphaspec) + ", " + str(alpha_stddev) + ", " + str(alpha/alpha_stddev) + "\n")
sys.exit()
......@@ -21,8 +21,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
-------------------------------------------------------------------------------
Usage:
calc_difff.py -name DeltaDelay_meas -nameref DeltaDelay_meas_ref [-o <dir>]
calc_difff.py -h | --help
calc_diff.py -name DeltaDelay_meas -nameref DeltaDelay_meas_ref [-o <dir>]
calc_diff.py -h | --help
Options:
-h --help Show this screen.
......@@ -48,7 +48,7 @@ import pdb
def save_plot(out_file, name, nameref, measurement_str, measurement_lst, outliers):
"""
outfile <file> handle to outfput file
outfile <file> handle to output file
name <str> name of the input file (with fiber spool PPS skew measurements)
nameref <str> name of the input file (with reference setup PPS skew measurements)
measurement_str <str> processed measurement
......@@ -112,7 +112,7 @@ Options:
"""
if __name__ == "__main__":
#arguments = docopt(__doc__,version='White Rabbit controled via serial port')
#arguments = docopt(__doc__,version='White Rabbit controlled via serial port')
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name", help="file containing DeltaDelay_measurement results")
......
#!/usr/bin/python
"""
fiber_crtt_vs_temperature.py: Measure cable round trip time (crtt) for one wavelength that
is set for an SFP with a tunable laser using a serial interface
connection to the WR console.
-------------------------------------------------------------------------------
Copyright (C) 2016 Peter Jansweijer, Henk Peek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
-------------------------------------------------------------------------------
Usage:
fiber_crtt_vs_temperature.py [-o <dir>] [-m <number>]
fiber_crtt_vs_temperature.py -h | --help
Options:
-h --help Show this screen.
-sm master serial port, default: "/dev/ttyUSB2"
-ss slave serial port, default: "/dev/ttyUSB1"
-t track fiber spool temperature (using Digital Multimeter and PT100), default: False
-o <dir> optional directory for output file storage, default: "data/"
"""
import os
import sys
import numpy
import serial
import time
from multiprocessing import Process
import pdb
# Add parent directory (containing 'lib') to the module search path
lib_path = (os.path.dirname(os.path.abspath(__file__)))
lib_path = os.path.join(lib_path,"..")
sys.path.insert(0,lib_path)
#from lib.docopt import docopt
import lib.itu_conversions as itu_conv
import lib.wrt_sfppt015sc as tunable
###############################################
# Found a neat python timout function on:
# https://stackoverflow.com/questions/366682/how-to-limit-execution-time-of-a-function-call-in-python
# drawback: function cannot return a value
def run_with_limited_time(func, args, kwargs, time):
"""Runs a function with time limit
:param func: The function to run
:param args: The functions args, given as tuple
:param kwargs: The functions keywords, given as dict
:param time: The time limit in seconds
:return: True if the function ended successfully. False if it was terminated.
"""
p = Process(target=func, args=args, kwargs=kwargs)
p.start()
p.join(time)
if p.is_alive():
p.terminate()
return False
return True
###############################################
# Found a neat python timout function on:
# https://stackoverflow.com/questions/492519/timeout-on-a-function-call
# default returns None when timeout occurs
def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
import signal
class TimeoutError(Exception):
pass
def handler(signum, frame):
raise TimeoutError()
# set the timeout handler
signal.signal(signal.SIGALRM, handler)
signal.alarm(timeout_duration)
try:
result = func(*args, **kwargs)
except TimeoutError as exc:
result = default
finally:
signal.alarm(0)
return result
###############################################
def wr2wrpc(ser, cmd, prompt="slv=>"):
ser.write(bytes("\r", 'utf-8'))
time.sleep (0.1)
ser.flushInput()
for i in range(len(cmd)):
ser.write(bytes(cmd[i], 'utf-8'))
time.sleep (0.1)
time.sleep (0.5)
ser.readline().decode('utf-8') # Readback command
print(prompt + cmd)
return
###############################################
def sfp_ena(ser_slave):
# bring the link down and up again by dis-/en-abeling the TX laser
# Note that this forces the wr switch to re-sybc and bitslide but
# not the wr device (SPEC or CLB) connected to it; Their wr links
# is kept up
wr2wrpc(ser_slave,"sfp ena 0\r","slv=>")
time.sleep (1)
wr2wrpc(ser_slave,"sfp ena 1\r","slv=>")
time.sleep (1)
return()
###############################################
def link_restart(ser_master,ser_slave, master_is_switch = True):
wr2wrpc(ser_slave,"ptp stop\r","slv=>")
time.sleep (1)
wr2wrpc(ser_slave,"ptp start\r","slv=>")
time.sleep (1)
if master_is_switch:
# A switch hald.sh restart causes all links to be restarted.
# Note that this forces the wr switch as well as the devices connected
# (SPEC or CLB) to re-sync and bitslide.
wr2wrpc(ser_master,"/etc/init.d/hald.sh restart\r","mst=>")
time.sleep (5)
else:
wr2wrpc(ser_master,"ptp stop\r","mst=>")
time.sleep (1)
#wr2wrpc(ser_master,"mode gm\r","mst=>")
#time.sleep (20)
wr2wrpc(ser_master,"ptp start\r","mst=>")
time.sleep (1)
sfp_ena(ser_slave)
return()
###############################################
def wait_for_track_phase(ser_slave):
sync_phase = False
track_phase = False
crtt = 0
while not sync_phase: # First wait for "SYNC_PHASE" state
stat = ser_slave.readline().decode('utf-8') # Readback status line
stat_lst = stat.split(' ') # split on spaces
#print("Waiting for SYNC_PHASE:")
#print(stat_lst)
if len(stat_lst) >= 27:
print(stat_lst[6])
if "SYNC_PHASE" in stat_lst[6]:
sync_phase = True
err_cnt = 0
while not track_phase: # then wait for "SYNC_PHASE" state
stat = ser_slave.readline().decode('utf-8') # Readback status line
stat_lst = stat.split(' ') # split on spaces
#print("Waiting for TRACK_PHASE:")
#print(stat_lst)
if len(stat_lst) < 27:
err_cnt = err_cnt + 1
print("### No track_phase: attempt: " + str(err_cnt) + "\n")
#print("### No track_phase, retry ptp stop, start...\n")
# bring the link down and up again by dis-/en-abeling the TX laser
# Note that this forces the wr switch to re-sybc and bitslide but
# not the wr device (SPEC or CLB) connected to it; Their wr links
# is kept up
sfp_ena(ser_slave)
if err_cnt == 3:
print("### retry ptp stop, start...")
# stop any pending ptp and restart
wr2wrpc(ser_slave,"ptp stop\r","slv=>")
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"ptp start\r","slv=>")
print(ser_slave.readline().decode('utf-8'))
print(ser_slave.readline().decode('utf-8'))
err_cnt = 0 # new attempt re-start counting errors
#break # break if not in "stat" output modus
else:
err_cnt = 0
print(stat_lst[6])
#try:
# crtt_lst = stat_lst[crtt_lst_idx].split(":")
if "TRACK_PHASE" in stat_lst[6]:
track_phase = True
#except:
# print ("### error occurred while reading wr status.")
# continue
return(track_phase)
#return()
###############################################
def get_statusline(ser_slave):
stat_lst = []
while len(stat_lst) < 27: # Keep reading until
stat = ser_slave.readline().decode('utf-8') # Readback valid status line
stat_lst = stat.split(' ') # split on spaces
return(stat_lst)
###############################################
# Main
###############################################
"""
Usage:
wr_serial.py [-o <dir>] [-m <number>]
wr_serial.py -h | --help
Options:
-h --help Show this screen.
-sm master serial port, default: "/dev/ttyUSB2"
-ss slave serial port, default: "/dev/ttyUSB1"
-t <IP> track fiber spool temperature (using PT100 and Digital Multimeter at IP address)
-o <dir> optional directory for output file storage, default: "data/"
"""
if __name__ == "__main__":
#arguments = docopt(__doc__,version='White Rabbit controlled via serial port')
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-mserial", default="/dev/ttyUSB2")
parser.add_argument("-sserial", default="/dev/ttyUSB1")
parser.add_argument("-t", help="track fiber spool temperature (using PT100 and Digital Multimeter at IP address)", default=None)
parser.add_argument("-output_dir", default="data")
args = parser.parse_args()
print("Use Master Serial port: ",args.mserial)
print("Use Slave Serial port: ",args.sserial)
print("Fiber spool temperature track: ",args.t)
print("Output directory: ",args.output_dir)
# add trailing slash if not present
output_dir = os.path.join(args.output_dir,'')
if os.path.exists(output_dir) != True:
os.mkdir(output_dir)
print("Output directory does not exist => created: "+output_dir)
# Some constants (for now)
# Continue CRTT measurements on ITU channel 36 (middle of the C-Band)
ch = 36
#fixed_delay_mst=int(328182) # Master (dTx + dRx) [ps]
#fixed_delay_slv=int(327963) # Slave (dTx + dRx) [ps]
# A reference measurement will be give the CRTT's for a system without a long fiber.
# This reference measurement will be subtracted from the CRTT measurements for a long fiber.
# In this way, any system typical hardware delays are cancelled.
# Initialize all hardware delays to 0.
fixed_delay_mst=int(0) # Master (dTx + dRx) [ps]
fixed_delay_slv=int(0) # Slave (dTx + dRx) [ps]
master_is_switch = False # If the master is a WR switch then the restart sequence is different from CLB or SPEC
master_has_tunable = True # determines whether the master or the slave has the tunable SFP (due to sfp functions needed
# this only works when master is a CLB or SPEC)
# Master SFP (tunable)
params = tunable.get_parameters()
sfp_module_vendor_id = params["vendor_id"]
# Slave SFP (fixed)
vendor_id_slv = "EOLS-1612-24205D"
crtt_measurement = 10 # number of crtt measurements over which the crtt is averaged
crtt_skip = 5 # skip first 5 crtt measurements
restarts = 1 # number of link restarts over which the crtt is averaged
spool_temp = None # if not used then default None
if args.t != None: # open and configure Digital Multimeter with attached PT100
import vxi11
dmm = vxi11.Instrument(args.t)
print(dmm.ask("*IDN?"))
# Returns 'Keysight Technologies,34465A,MY57501367,A.02.14-02.40-02.14-00.49-03-01'
# Configure for 4 wire temperature measurement
dmm.write("SAMPle:COUNt 1")
dmm.write("UNIT:TEMPerature C")
print("Fiber Spool temperature", float(dmm.ask("MEAS:TEMP? FRTD")))
ser_slave = serial.Serial()
ser_slave.port = args.sserial
ser_slave.baudrate = 115200
ser_slave.parity = serial.PARITY_NONE
ser_slave.bytesize = serial.EIGHTBITS
ser_slave.stopbits = serial.STOPBITS_ONE
ser_slave.timeout = None
#ser_slave.timeout = 600 # timeout 10 minutes
ser_slave.open()
ser_master = serial.Serial()
ser_master.port = args.mserial
ser_master.baudrate = 115200
ser_master.parity = serial.PARITY_NONE
ser_master.bytesize = serial.EIGHTBITS
ser_master.stopbits = serial.STOPBITS_ONE
ser_master.timeout = None
#ser_master.timeout = 600 # timeout 10 minutes
ser_master.open()
if (master_has_tunable):
ser_tunable = ser_master
ser_tunable_str = "mst=>"
else:
ser_tunable = ser_slave
ser_tunable_str = "slv=>"
wr2wrpc(ser_master,"mode gm\r","mst=>")
wr2wrpc(ser_slave,"mode slave\r","slv=>")
time.sleep (20)
# stop any pending ptp and or statistics output
wr2wrpc(ser_master,"stat off\r","mst=>")
print(ser_master.readline().decode('utf-8'))
wr2wrpc(ser_slave,"stat off\r","slv=>")
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"ptp stop\r","slv=>")
# Set Master dTx = fixed delay (dTx+dRx), dRx = 0, alpha = 0
wr2wrpc(ser_tunable,"sfp erase\r",ser_tunable_str)
wr2wrpc(ser_tunable,"sfp add "+sfp_module_vendor_id+" "+str(fixed_delay_mst)+" 0 0\r",ser_tunable_str)
print(ser_tunable.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp match\r",ser_tunable_str)
print(ser_tunable.readline().decode('utf-8'))
# Set Slave dTx = fixed delay (dTx+dRx), dRx = 0, alpha = 0
wr2wrpc(ser_slave,"sfp erase\r","slv=>")
wr2wrpc(ser_slave,"sfp add "+vendor_id_slv+" "+str(fixed_delay_slv)+" 0 0\r","slv=>")
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"sfp match\r","slv=>")
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp sel_page2\r",ser_tunable_str)
wr2wrpc(ser_slave,"stat on\r","slv=>")
timestamp = time.localtime()
filename=output_dir+time.strftime(format("%y%m%d_%H_%M_%S"),timestamp)+"_crtt_vs_temp"
print("save insitu_alpha_scan into file:",filename)
data_file = open(filename,"wb")
data_file.write(("#CRTT measurement for ITU Channel " + str(ch) + "\n").encode())
data_file.write(("#date:"+time.strftime(format("%d %b %Y"),timestamp)+"\n").encode())
data_file.write(("#time:"+time.strftime(format("%H:%M:%S"),timestamp)+"\n").encode())
data_file.write(("#sfp_channel, ITU channel, ITU wavelength, crtt [ps], drxm, drxs, fiber-spool-temp, wr-slave-temp, meas-time\n").encode())
sfp_ch = tunable.sfp_channel(ch)
frequency = itu_conv.itu_2_frequency(ch)
wavelength = itu_conv.itu_2_wavelength(ch)
print("select ITU channel",ch, "which is sfp channel number",sfp_ch)
# select a wavelength
wr2wrpc(ser_tunable,"sfp wr_ch " + str(sfp_ch) + "\r",ser_tunable_str)
print(ser_tunable.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp rd_ch\r",ser_tunable_str)
print(ser_tunable.readline().decode('utf-8'))
print("Link restart")
link_restart(ser_master,ser_slave, master_is_switch)
track_phase = False
while not track_phase:
# Call "wait_for_track_phase(ser_slave)" with a timeout of 60 seconds
# If no TRACK_PHASE within 60 seconds then try restart link!
#track_phase = run_with_limited_time(wait_for_track_phase, (ser_slave, ), {}, 60.0)
#if not track_phase:
track_phase = timeout(wait_for_track_phase, (ser_slave, ), {}, 60)
if track_phase == None:
print ("### Timeout waiting for TRACK_PHASE, try link restart...")
link_restart(ser_master,ser_slave, master_is_switch)
try:
# continue CRTT measurements for fixed wavelength "ch" without restarting the link.
# until the program is <Crtl-C>-ed.
while True:
fail = 0
meas_number = 0
crtt = []
while meas_number < (crtt_skip + crtt_measurement): # take mean value over cttt_measurement
stat_lst = timeout(get_statusline, (ser_slave, ), {}, 60)
if stat_lst == None:
print ("### Timeout waiting status line...")
link_restart(ser_master,ser_slave, master_is_switch)
else:
#stat_lst = []
#while len(stat_lst) < 27: # Keep reading until
# stat = ser_slave.readline().decode('utf-8') # Readback valid status line
# stat_lst = stat.split(' ') # split on spaces
#pdb.set_trace()
#if len(stat_lst) >= 27:
# note:
# [s for s in stat_lst if "crtt" in s]
# returns a list with one item, for example ['crtt:82466168']
# take item [0] from this list, split it over ":" and take
# item [1] from the resulting list
# format for 'temp:' is different. it has an extra space so
# the temp value is the next item op the stat_lst
curr_crtt = int([s for s in stat_lst if "crtt" in s][0].split(":")[1])
curr_drxm = int([s for s in stat_lst if "drxm" in s][0].split(":")[1])
curr_drxs = int([s for s in stat_lst if "drxs" in s][0].split(":")[1])
curr_temp = float(stat_lst[stat_lst.index('temp:')+1])
crtt.append(curr_crtt)
if meas_number == 0: # first measurement loads bitslide check valiables
check_drxm = curr_drxm
check_drxs = curr_drxs
meas_number = meas_number + 1
print(curr_crtt, curr_drxm, curr_drxs)
else: # next measurements compare bitslide check variables
# check for good measurement; criteria:
# 1) bitslides should all be equal (no hidden link resynchronizations)
# 2) crtt outliers bigger than 200 ps are not excepted (no hidden finetime jumps;
# a worry since wrpc-v4.1 and PPSi huge PPS offset repair)
if check_drxm == curr_drxm and check_drxs == curr_drxs and max(crtt) - min(crtt) < 200 :
meas_number = meas_number + 1
print(curr_crtt, curr_drxm, curr_drxs)
# print(".",end='') # <= python 3
else:
print ("### bitslide changed or crtt(max-min) > 200 ps. Take next couple of measurements...")
meas_number = 0 # wrong measurement (link resync?) start all over.
crtt = []
fail = fail + 1 # count the number of times this failed
if fail > 3: # restart link when this passes a certain threshold
print ("### failed too many times => restart link")
link_restart(ser_master,ser_slave, master_is_switch)
fail = 0
crtt_mean = numpy.mean(crtt[(crtt_skip + 1):]) # skip first measurements
if args.t != None: # open and configure Digital Multimeter with attached PT100
spool_temp =float(dmm.ask("MEAS:TEMP? FRTD"))
meas_time = time.strftime(format("%H:%M:%S"),time.localtime())
print("sfp_channel: ", sfp_ch ,"itu_channel: ", ch ,"crtt average over "+str(crtt_measurement)+" measurements: "+str(crtt_mean)+" fiber-spool temp: "+str(spool_temp))
data_file.write((str(sfp_ch)+", "+str(ch)+", "+str(wavelength)+", "+str(crtt_mean)+", "+str(curr_drxm)+", "+str(curr_drxs)+", "+str(spool_temp)+", "+str(curr_temp)+", "+str(meas_time)+"\n").encode())
except:
print ("### exception during crtt_measurements.")
#continue
data_file.close()
ser_slave.close()
......@@ -21,12 +21,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
-------------------------------------------------------------------------------
Usage:
pps_diff.py -name ddelay.out [-ms /dev/ttyUSB2] [-ss /dev/ttyUSB1] [-t <IP>] -tic <IP> [-o <dir>] [-a <number>] [-r <number>]
pps_diff.py -name ddelay.out [-f "ddelay"] [-ms /dev/ttyUSB2] [-ss /dev/ttyUSB1] [-t <IP>] -tic <IP> [-o <dir>] [-a <number>] [-r <number>]
pps_diff.py -h | --help
Options:
-h --help Show this screen.
-name pointer to a "ddelay.out" file to be taken as input for measurements
-format file format "3-lambda" or "ddelay", default "ddelay"
-ms master serial port, default: "/dev/ttyUSB2"
-ss slave serial port, default: "/dev/ttyUSB1"
-t <IP> track fiber spool temperature (using PT100 and Digital Multimeter at IP address)
......@@ -112,15 +113,15 @@ def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
###############################################
def wr2wrpc(ser, cmd, prompt="slv=>"):
ser.write("\r")
ser.write(bytes("\r", 'utf-8'))
time.sleep (0.1)
ser.flushInput()
for i in range(len(cmd)):
ser.write(cmd[i])
ser.write(bytes(cmd[i], 'utf-8'))
time.sleep (0.1)
time.sleep (0.5)
ser.readline() # Readback command
ser.readline().decode('utf-8') # Readback command
print(prompt + cmd)
......@@ -177,7 +178,7 @@ def wait_for_track_phase(ser_slave):
track_phase = False
while not sync_phase: # First wait for "SYNC_PHASE" state
stat = ser_slave.readline() # Readback status line
stat = ser_slave.readline().decode('utf-8') # Readback status line
stat_lst = stat.split(' ') # split on spaces
#print("Waiting for SYNC_PHASE:")
......@@ -191,7 +192,7 @@ def wait_for_track_phase(ser_slave):
err_cnt = 0
while not track_phase: # then wait for "SYNC_PHASE" state
stat = ser_slave.readline() # Readback status line
stat = ser_slave.readline().decode('utf-8') # Readback status line
stat_lst = stat.split(' ') # split on spaces
#print("Waiting for TRACK_PHASE:")
......@@ -213,10 +214,10 @@ def wait_for_track_phase(ser_slave):
print("### retry ptp stop, start...")
# stop any pending ptp and restart
wr2wrpc(ser_slave,"ptp stop\r","slv=>")
print(ser_slave.readline())
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"ptp start\r","slv=>")
print(ser_slave.readline())
print(ser_slave.readline())
print(ser_slave.readline().decode('utf-8'))
print(ser_slave.readline().decode('utf-8'))
err_cnt = 0 # new attempt re-start counting errors
#break # break if not in "stat" output modus
else:
......@@ -234,7 +235,7 @@ def get_statusline(ser_slave):
stat_lst = []
while len(stat_lst) < 27: # Keep reading until
stat = ser_slave.readline() # Readback valid status line
stat = ser_slave.readline().decode('utf-8') # Readback valid status line
stat_lst = stat.split(' ') # split on spaces
return(stat_lst)
......@@ -311,9 +312,9 @@ def tic_init(counter):
counter.write("SENSE:TINTerval:GATE:POLarity POSitive")
# Use external 10MHz reference
counter.write("ROSCillator:SOURce EXTernal")
#counter.write("ROSCillator:SOURce EXTernal")
# Use internal 10MHz reference
#counter.write("ROSCillator:SOURce INTernal")
counter.write("ROSCillator:SOURce INTernal")
# Disable timeout (otherwise we might loose measurements)
counter.write("SYSTem:TIMeout INFinity")
......@@ -377,10 +378,20 @@ def spec_alpha(alpha):
############################################################################
def file_to_array(filename):
def delta_delay_file_to_array(filename):
"""
Retrieve the delat delay file
Retrieve the delta delay file
Format example:
# Proposed Delta Delay measurements
# file: data_180621_snd/averaged
# reference file/directory: data_180625
# fixed_lambda: 1.5614190520833333e-06 = ITU-ch: 20.0
# ============================
# time_err within range: 1 [ps]
# lambda-1[nm] ITU-ch SPEC_alpha_3wl(l1) lambda-2[nm] time_err[ps]
1563.04722628, 18.0, 1767934.12769, 1562.23271496, -8.221e-13
filename -- source file from which to retrieve data.
returns: True, <type 'numpy.array'>
......@@ -409,6 +420,7 @@ def file_to_array(filename):
if len(line_lst) < 3:
break
# We need to catch lambda_1 in ITU channel format and Alpha in SPEC format
# Values of interest on one line are:
# # lambda-1[nm], ITU-ch, SPEC_alpha_3wl(lambda-1)
pair = float(line_lst[1]),float(line_lst[2])
......@@ -422,6 +434,58 @@ def file_to_array(filename):
return (True, arr_pair)
############################################################################
def three_lambda_delta_delay_file_to_array(filename):
"""
Retrieve the 3-lambda delta delay file
Format example:
# Proposed 3-Lambda Delta Delay measurements
# file: data_180926/180926_15_47_01_3_lambda_insitu_alpha_scan
# fixed_lambda: 1.5614190520833333e-06 = ITU-ch: 20
# Lambda 1, Lambda 2, CRTT(Lambda_1), CRTT(Lambda_2), Fixed Lambda, Alpha, Alpha SPEC format, Alpha StdDev, Alpha/Alpha_StdDev
1.5630472262773723e-06, 1.5622327149557061e-06, 492049213.722, 492048426.883, 1.5614190520833333e-06, 6.39311328132e-06, 1757319.9801, 1.18601544313e-06, 5.39041318421
filename -- source file from which to retrieve data.
returns: True, <type 'numpy.array'>
[itu-ch, SPEC_alpha_3wl],
[itu-ch, SPEC_alpha_3wl],
:
False
"Not a Delta Delay file"
"""
# create empty list
pairs=[]
data_file = open(filename, "r")
line = data_file.readline()
if line.strip() != "# Proposed 3-Lambda Delta Delay measurements":
Exception("file_to_arrays: Not a 3-Lambda Delta Delay measurements file.")
data_file.close()
return (False, alpha_spec_data)
while 1:
line = data_file.readline()
if line[:len("#")] != "#": # Skip lines that are commented out
line_lst = line.split(",")
if len(line_lst) < 3:
break
# We need to catch lambda_1 in ITU channel format and Alpha in SPEC format
# Values of interest on one line are:
# # Lambda 1 [m], Lambda 2 [m], CRTT(Lambda_1) [ps], CRTT(Lambda_2) [ps], Fixed Lambda [m], Alpha, Alpha SPEC format, Alpha StdDev, Alpha/Alpha_StdDev
pair = float(itu_conv.wavelength_2_itu(float(line_lst[0]))),float(line_lst[6])
pairs.append(pair)
arr_pair=numpy.array(pairs)
data_file.close()
return (True, arr_pair)
###############################################
# Main
###############################################
......@@ -434,6 +498,7 @@ Usage:
Options:
-h --help Show this screen.
-name pointer to a "ddelay.out" file to be taken as input for measurements
-format file format "3-lambda" or "ddelay", default "ddelay"
-ms master serial port, default: "/dev/ttyUSB2"
-ss slave serial port, default: "/dev/ttyUSB1"
-t <IP> track fiber spool temperature (using PT100 and Digital Multimeter at IP address)
......@@ -450,6 +515,7 @@ if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name", help="file containing ddelay measurements to perform")
parser.add_argument("-format", help="file format 3-lambda or ddelay", default="ddelay")
parser.add_argument("-mserial", default="/dev/ttyUSB2")
parser.add_argument("-sserial", default="/dev/ttyUSB1")
parser.add_argument("-t", help="track fiber spool temperature (using PT100 and Digital Multimeter at IP address)", default=None)
......@@ -471,7 +537,10 @@ if __name__ == "__main__":
print("link restarts: ",args.r)
if os.path.exists(name) == True and os.path.isfile(name) == True:
measure, pairs = file_to_array(name)
if args.format == "ddelay":
measure, pairs = delta_delay_file_to_array(name)
else:
measure, pairs = three_lambda_delta_delay_file_to_array(name)
else:
print("Delat Delay input file not found")
sys.exit()
......@@ -515,7 +584,17 @@ if __name__ == "__main__":
restarts = int(args.r) # number of link restarts over which the delta_delay is averaged
#scope = vxi11.Instrument(args.dso)
#osc_init(scope, time_base = 1.0e-9)
#init = { \
# 'channel' : [ 0 , 0 , 1 , 1 ], \
# 'offset' : [ 0.0 , 0.0, -1.5 , -1.5 ], \
# 'volt_div' : [ 0.25, 1.0, 0.5 , 0.5 ], \
# '50ohm' : [ 0 , 0 , 1 , 1 ], \
# 'trig' : [ 3 ], \
# 'trig_level' : [ 0.14 ], \
# 'timebase' : [ 1.0e-9 ], \
# 'refclk' : [ 'ext' ], \
#}
#DSO.osc_init(scope, init)
# Initialize Time Interval Counter (1-2)
# Use Channel 1 PPS SPEC-1 (50 Ohm, Level 1.4)
......@@ -600,24 +679,24 @@ if __name__ == "__main__":
# stop any pending ptp and or statistics output
wr2wrpc(ser_master,"stat off\r","mst=>")
print(ser_master.readline())
print(ser_master.readline().decode('utf-8'))
wr2wrpc(ser_slave,"stat off\r","slv=>")
print(ser_slave.readline())
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"ptp stop\r","slv=>")
# Set Master dTx = fixed delay (dTx+dRx), dRx = 0, alpha = 0
wr2wrpc(ser_tunable,"sfp erase\r",ser_tunable_str)
wr2wrpc(ser_tunable,"sfp add "+sfp_module_vendor_id+" "+str(fixed_delay_mst)+" 0 0\r",ser_tunable_str)
print(ser_tunable.readline())
print(ser_tunable.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp match\r",ser_tunable_str)
print(ser_tunable.readline())
print(ser_tunable.readline().decode('utf-8'))
# Set Slave dTx = fixed delay (dTx+dRx), dRx = 0, alpha
wr2wrpc(ser_slave,"sfp erase\r","slv=>")
wr2wrpc(ser_slave,"sfp add "+vendor_id_slv+" "+str(fixed_delay_slv)+" 0 "+str(alpha)+"\r","slv=>")
print(ser_slave.readline())
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"sfp match\r","slv=>")
print(ser_slave.readline())
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp sel_page2\r",ser_tunable_str)
......@@ -625,9 +704,9 @@ if __name__ == "__main__":
# select wavelength
wr2wrpc(ser_tunable,"sfp wr_ch " + str(sfp_ch) + "\r",ser_tunable_str)
print(ser_tunable.readline())
print(ser_tunable.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp rd_ch\r",ser_tunable_str)
print(ser_tunable.readline())
print(ser_tunable.readline().decode('utf-8'))
restart = 0
while restart < restarts:
......
......@@ -108,15 +108,15 @@ def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
###############################################
def wr2wrpc(ser, cmd, prompt="slv=>"):
ser.write("\r")
ser.write(bytes("\r", 'utf-8'))
time.sleep (0.1)
ser.flushInput()
for i in range(len(cmd)):
ser.write(cmd[i])
ser.write(bytes(cmd[i], 'utf-8'))
time.sleep (0.1)
time.sleep (0.5)
ser.readline() # Readback command
ser.readline().decode('utf-8') # Readback command
print(prompt + cmd)
......@@ -172,7 +172,7 @@ def wait_for_track_phase(ser_slave):
crtt = 0
while not sync_phase: # First wait for "SYNC_PHASE" state
stat = ser_slave.readline() # Readback status line
stat = ser_slave.readline().decode('utf-8') # Readback status line
stat_lst = stat.split(' ') # split on spaces
#print("Waiting for SYNC_PHASE:")
......@@ -186,7 +186,7 @@ def wait_for_track_phase(ser_slave):
err_cnt = 0
while not track_phase: # then wait for "SYNC_PHASE" state
stat = ser_slave.readline() # Readback status line
stat = ser_slave.readline().decode('utf-8') # Readback status line
stat_lst = stat.split(' ') # split on spaces
#print("Waiting for TRACK_PHASE:")
......@@ -208,10 +208,10 @@ def wait_for_track_phase(ser_slave):
print("### retry ptp stop, start...")
# stop any pending ptp and restart
wr2wrpc(ser_slave,"ptp stop\r","slv=>")
print(ser_slave.readline())
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"ptp start\r","slv=>")
print(ser_slave.readline())
print(ser_slave.readline())
print(ser_slave.readline().decode('utf-8'))
print(ser_slave.readline().decode('utf-8'))
err_cnt = 0 # new attempt re-start counting errors
#break # break if not in "stat" output modus
else:
......@@ -234,7 +234,7 @@ def get_statusline(ser_slave):
stat_lst = []
while len(stat_lst) < 27: # Keep reading until
stat = ser_slave.readline() # Readback valid status line
stat = ser_slave.readline().decode('utf-8') # Readback valid status line
stat_lst = stat.split(' ') # split on spaces
return(stat_lst)
......@@ -369,24 +369,24 @@ if __name__ == "__main__":
# stop any pending ptp and or statistics output
wr2wrpc(ser_master,"stat off\r","mst=>")
print(ser_master.readline())
print(ser_master.readline().decode('utf-8'))
wr2wrpc(ser_slave,"stat off\r","slv=>")
print(ser_slave.readline())
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"ptp stop\r","slv=>")
# Set Master dTx = fixed delay (dTx+dRx), dRx = 0, alpha = 0
wr2wrpc(ser_tunable,"sfp erase\r",ser_tunable_str)
wr2wrpc(ser_tunable,"sfp add "+sfp_module_vendor_id+" "+str(fixed_delay_mst)+" 0 0\r",ser_tunable_str)
print(ser_tunable.readline())
print(ser_tunable.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp match\r",ser_tunable_str)
print(ser_tunable.readline())
print(ser_tunable.readline().decode('utf-8'))
# Set Slave dTx = fixed delay (dTx+dRx), dRx = 0, alpha = 0
wr2wrpc(ser_slave,"sfp erase\r","slv=>")
wr2wrpc(ser_slave,"sfp add "+vendor_id_slv+" "+str(fixed_delay_slv)+" 0 0\r","slv=>")
print(ser_slave.readline())
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"sfp match\r","slv=>")
print(ser_slave.readline())
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp sel_page2\r",ser_tunable_str)
......@@ -399,12 +399,12 @@ if __name__ == "__main__":
filename=output_dir+time.strftime(format("%y%m%d_%H_%M_%S"),timestamp)+"_insitu_alpha_scan"
print("save insitu_alpha_scan into file:",filename)
data_file = open(filename,"w")
data_file = open(filename,"wb")
data_file.write("#In Situ Alpha measurements\n")
data_file.write("#date:"+time.strftime(format("%d %b %Y"),timestamp)+"\n")
data_file.write("#time:"+time.strftime(format("%H:%M:%S"),timestamp)+"\n")
data_file.write("#sfp_channel, ITU channel, ITU wavelength, crtt [ps], drxm, drxs, fiber-spool-temp, wr-slave-temp\n")
data_file.write(("#In Situ Alpha measurements\n").encode())
data_file.write(("#date:"+time.strftime(format("%d %b %Y"),timestamp)+"\n").encode())
data_file.write(("#time:"+time.strftime(format("%H:%M:%S"),timestamp)+"\n").encode())
data_file.write(("#sfp_channel, ITU channel, ITU wavelength, crtt [ps], drxm, drxs, fiber-spool-temp, wr-slave-temp\n").encode())
# scan through selected wavelengths
for ch in numpy.arange(itu_channel_start,itu_channel_stop+0.5, itu_channel_increment):
......@@ -419,9 +419,10 @@ if __name__ == "__main__":
# select a wavelength
wr2wrpc(ser_tunable,"sfp wr_ch " + str(sfp_ch) + "\r",ser_tunable_str)
print(ser_tunable.readline())
print(ser_tunable.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp rd_ch\r",ser_tunable_str)
print(ser_tunable.readline())
print(ser_tunable.readline().decode('utf-8'))
restart = 0
while restart < restarts:
......@@ -454,7 +455,7 @@ if __name__ == "__main__":
else:
#stat_lst = []
#while len(stat_lst) < 27: # Keep reading until
# stat = ser_slave.readline() # Readback valid status line
# stat = ser_slave.readline().decode('utf-8') # Readback valid status line
# stat_lst = stat.split(' ') # split on spaces
#pdb.set_trace()
......@@ -472,7 +473,7 @@ if __name__ == "__main__":
curr_temp = float(stat_lst[stat_lst.index('temp:')+1])
crtt.append(curr_crtt)
if meas_number == 0: # first measurment loads bitslide check valiables
if meas_number == 0: # first measurement loads bitslide check valiables
check_drxm = curr_drxm
check_drxs = curr_drxs
meas_number = meas_number + 1
......@@ -501,8 +502,8 @@ if __name__ == "__main__":
if args.t != None: # open and configure Digital Multimeter with attached PT100
spool_temp =float(dmm.ask("MEAS:TEMP? FRTD"))
print("sfp_channel: ", sfp_ch ,"itu_channel: ", ch ,"crtt avarage over "+str(crtt_measurement)+" measurments: "+str(crtt_mean)+" fiber-spool temp: "+str(spool_temp))
data_file.write(str(sfp_ch)+", "+str(ch)+", "+str(wavelength)+", "+str(crtt_mean)+", "+str(curr_drxm)+", "+str(curr_drxs)+", "+str(spool_temp)+", "+str(curr_temp)+"\n")
print("sfp_channel: ", sfp_ch ,"itu_channel: ", ch ,"crtt average over "+str(crtt_measurement)+" measurements: "+str(crtt_mean)+" fiber-spool temp: "+str(spool_temp))
data_file.write((str(sfp_ch)+", "+str(ch)+", "+str(wavelength)+", "+str(crtt_mean)+", "+str(curr_drxm)+", "+str(curr_drxs)+", "+str(spool_temp)+", "+str(curr_temp)+"\n").encode())
except:
print ("### exception during crtt_measurements.")
......
#!/usr/bin/python
"""
wr_serial_3lambda.py:
Repeatedly measures the cable round trip time (crtt) for lambda 1 and lambda 2.
a link restart includes a Grand master- and a Slave- lock
Procedure:
repeat for as many measurements as given
measure in direction A (l1 -> l2)
set lambda 1
restart link
measure crtt
set lambda 2
restart link
measure crtt
measure in direction B (l2 -> l1)
set lambda 1
restart link
measure crtt
set lambda 2
restart link
measure crtt
-------------------------------------------------------------------------------
Copyright (C) 2016 Peter Jansweijer, Henk Peek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
-------------------------------------------------------------------------------
Usage:
wr_serial_3lambda.py -name ddelay.out [-o <dir>] [-m <number>]
wr_serial_3lambda.py -h | --help
Options:
-h --help Show this screen.
-name pointer to a "ddelay.out" file to be taken as input for measurements
-sm master serial port, default: "/dev/ttyUSB2"
-ss slave serial port, default: "/dev/ttyUSB1"
-t track fiber spool temperature (using Digital Multimeter and PT100), default: False
-o <dir> optional directory for output file storage, default: "data/"
-m <number> number of measurement cycles (default = 1 cycle is a sweep from
start to stop lambda)
"""
import os
import sys
import numpy
import serial
import time
from multiprocessing import Process
import pdb
# Add parent directory (containing 'lib') to the module search path
lib_path = (os.path.dirname(os.path.abspath(__file__)))
lib_path = os.path.join(lib_path,"..")
sys.path.insert(0,lib_path)
#from lib.docopt import docopt
import lib.itu_conversions as itu_conv
import lib.wrt_sfppt015sc as tunable
###############################################
# Found a neat python timout function on:
# https://stackoverflow.com/questions/366682/how-to-limit-execution-time-of-a-function-call-in-python
# drawback: function cannot return a value
def run_with_limited_time(func, args, kwargs, time):
"""Runs a function with time limit
:param func: The function to run
:param args: The functions args, given as tuple
:param kwargs: The functions keywords, given as dict
:param time: The time limit in seconds
:return: True if the function ended successfully. False if it was terminated.
"""
p = Process(target=func, args=args, kwargs=kwargs)
p.start()
p.join(time)
if p.is_alive():
p.terminate()
return False
return True
###############################################
# Found a neat python timout function on:
# https://stackoverflow.com/questions/492519/timeout-on-a-function-call
# default returns None when timeout occurs
def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
import signal
class TimeoutError(Exception):
pass
def handler(signum, frame):
raise TimeoutError()
# set the timeout handler
signal.signal(signal.SIGALRM, handler)
signal.alarm(timeout_duration)
try:
result = func(*args, **kwargs)
except TimeoutError as exc:
result = default
finally:
signal.alarm(0)
return result
###############################################
def wr2wrpc(ser, cmd, prompt="slv=>"):
ser.write(bytes("\r", 'utf-8'))
time.sleep (0.1)
ser.flushInput()
for i in range(len(cmd)):
ser.write(bytes(cmd[i], 'utf-8'))
time.sleep (0.1)
time.sleep (0.5)
ser.readline().decode('utf-8') # Readback command
print(prompt + cmd)
return
###############################################
def sfp_ena(ser_slave):
# bring the link down and up again by dis-/en-abeling the TX laser
# Note that this forces the wr switch to re-sybc and bitslide but
# not the wr device (SPEC or CLB) connected to it; Their wr links
# is kept up
wr2wrpc(ser_slave,"sfp ena 0\r","slv=>")
time.sleep (1)
wr2wrpc(ser_slave,"sfp ena 1\r","slv=>")
time.sleep (1)
return()
###############################################
def link_restart(ser_master,ser_slave, master_is_switch = True):
wr2wrpc(ser_slave,"ptp stop\r","slv=>")
time.sleep (1)
wr2wrpc(ser_slave,"mode slave\r","slv=>")
time.sleep (1)
wr2wrpc(ser_slave,"ptp start\r","slv=>")
time.sleep (1)
if master_is_switch:
# A switch hald.sh restart causes all links to be restarted.
# Note that this forces the wr switch as well as the devices connected
# (SPEC or CLB) to re-sync and bitslide.
wr2wrpc(ser_master,"/etc/init.d/hald.sh restart\r","mst=>")
time.sleep (5)
else:
wr2wrpc(ser_master,"ptp stop\r","mst=>")
time.sleep (1)
wr2wrpc(ser_master,"mode gm\r","mst=>")
time.sleep (20)
wr2wrpc(ser_master,"ptp start\r","mst=>")
time.sleep (1)
sfp_ena(ser_slave)
return()
###############################################
def wait_for_track_phase(ser_slave):
sync_phase = False
track_phase = False
crtt = 0
while not sync_phase: # First wait for "SYNC_PHASE" state
stat = ser_slave.readline().decode('utf-8') # Readback status line
stat_lst = stat.split(' ') # split on spaces
#print("Waiting for SYNC_PHASE:")
#print(stat_lst)
if len(stat_lst) >= 27:
print(stat_lst[6])
if "SYNC_PHASE" in stat_lst[6]:
sync_phase = True
err_cnt = 0
while not track_phase: # then wait for "SYNC_PHASE" state
stat = ser_slave.readline().decode('utf-8') # Readback status line
stat_lst = stat.split(' ') # split on spaces
#print("Waiting for TRACK_PHASE:")
#print(stat_lst)
if len(stat_lst) < 27:
err_cnt = err_cnt + 1
print("### No track_phase: attempt: " + str(err_cnt) + "\n")
#print("### No track_phase, retry ptp stop, start...\n")
# bring the link down and up again by dis-/en-abeling the TX laser
# Note that this forces the wr switch to re-sybc and bitslide but
# not the wr device (SPEC or CLB) connected to it; Their wr links
# is kept up
sfp_ena(ser_slave)
if err_cnt == 3:
print("### retry ptp stop, start...")
# stop any pending ptp and restart
wr2wrpc(ser_slave,"ptp stop\r","slv=>")
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"ptp start\r","slv=>")
print(ser_slave.readline().decode('utf-8'))
print(ser_slave.readline().decode('utf-8'))
err_cnt = 0 # new attempt re-start counting errors
#break # break if not in "stat" output modus
else:
err_cnt = 0
print(stat_lst[6])
#try:
# crtt_lst = stat_lst[crtt_lst_idx].split(":")
if "TRACK_PHASE" in stat_lst[6]:
track_phase = True
#except:
# print ("### error occurred while reading wr status.")
# continue
return(track_phase)
#return()
###############################################
def get_statusline(ser_slave):
stat_lst = []
while len(stat_lst) < 27: # Keep reading until
stat = ser_slave.readline().decode('utf-8') # Readback valid status line
stat_lst = stat.split(' ') # split on spaces
return(stat_lst)
###############################################
def meas_crtt(ser_tunable, ser_master, ser_slave, master_is_switch, crtt_skip, crtt_measurement, ch):
"""
Performs a Delta Delay Measurement.
ser_tunable -- instance of pyserial connected to the WR GUI of the SPEC with the tunable
ser_master -- instance of pyserial connected to the WR GUI of the SPEC master
ser_slave -- instance of pyserial connected to the WR GUI of the SPEC slave
master_is_switch -- <boolean> if master is WR switch then the restart sequence differs from CLB or SPEC
crtt_measurement -- <int> number of crtt measurements over which the crtt is averaged
crtt_skip -- <int> skip first crtt measurements
ch -- <int> ITU channel number for which CRTT will be measured
returns:
result_line -- <str> line with measurement results
"""
sfp_ch = tunable.sfp_channel(ch)
frequency = itu_conv.itu_2_frequency(ch)
wavelength = itu_conv.itu_2_wavelength(ch)
print("select ITU channel",ch, "which is sfp channel number",sfp_ch)
# select a wavelength
wr2wrpc(ser_tunable,"sfp wr_ch " + str(sfp_ch) + "\r",ser_tunable_str)
print(ser_tunable.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp rd_ch\r",ser_tunable_str)
print(ser_tunable.readline().decode('utf-8'))
print("Link restart")
link_restart(ser_master,ser_slave, master_is_switch)
track_phase = False
while not track_phase:
# Call "wait_for_track_phase(ser_slave)" with a timeout of 60 seconds
# If no TRACK_PHASE within 60 seconds then try restart link!
#track_phase = run_with_limited_time(wait_for_track_phase, (ser_slave, ), {}, 60.0)
#if not track_phase:
track_phase = timeout(wait_for_track_phase, (ser_slave, ), {}, 60)
if track_phase == None:
print ("### Timeout waiting for TRACK_PHASE, try link restart...")
link_restart(ser_master,ser_slave, master_is_switch)
try:
fail = 0
meas_number = 0
crtt = []
while meas_number < (crtt_skip + crtt_measurement): # take mean value over cttt_measurement
stat_lst = timeout(get_statusline, (ser_slave, ), {}, 60)
if stat_lst == None:
print ("### Timeout waiting status line...")
link_restart(ser_master,ser_slave, master_is_switch)
else:
#stat_lst = []
#while len(stat_lst) < 27: # Keep reading until
# stat = ser_slave.readline().decode('utf-8') # Readback valid status line
# stat_lst = stat.split(' ') # split on spaces
#pdb.set_trace()
#if len(stat_lst) >= 27:
# note:
# [s for s in stat_lst if "crtt" in s]
# returns a list with one item, for example ['crtt:82466168']
# take item [0] from this list, split it over ":" and take
# item [1] from the resulting list
# format for 'temp:' is different. it has an extra space so
# the temp value is the next item op the stat_lst
curr_crtt = int([s for s in stat_lst if "crtt" in s][0].split(":")[1])
curr_drxm = int([s for s in stat_lst if "drxm" in s][0].split(":")[1])
curr_drxs = int([s for s in stat_lst if "drxs" in s][0].split(":")[1])
curr_temp = float(stat_lst[stat_lst.index('temp:')+1])
crtt.append(curr_crtt)
if meas_number == 0: # first measurement loads bitslide check valiables
check_drxm = curr_drxm
check_drxs = curr_drxs
meas_number = meas_number + 1
print(curr_crtt, curr_drxm, curr_drxs)
else: # next measurements compare bitslide check variables
# check for good measurement; criteria:
# 1) bitslides should all be equal (no hidden link resynchronizations)
# 2) crtt outliers bigger than 200 ps are not excepted (no hidden finetime jumps;
# a worry since wrpc-v4.1 and PPSi huge PPS offset repair)
if check_drxm == curr_drxm and check_drxs == curr_drxs and max(crtt) - min(crtt) < 200 :
meas_number = meas_number + 1
print(curr_crtt, curr_drxm, curr_drxs)
# print(".",end='') # <= python 3
else:
print ("### bitslide changed or crtt(max-min) > 200 ps. Take next couple of measurements...")
meas_number = 0 # wrong measurement (link resync?) start all over.
crtt = []
fail = fail + 1 # count the number of times this failed
if fail > 3: # restart link when this passes a certain threshold
print ("### failed too many times => restart link")
link_restart(ser_master,ser_slave, master_is_switch)
fail = 0
crtt_mean = numpy.mean(crtt[(crtt_skip + 1):]) # skip first measurements
if args.t != None: # open and configure Digital Multimeter with attached PT100
spool_temp =float(dmm.ask("MEAS:TEMP? FRTD"))
meas_time = time.strftime(format("%H:%M:%S"),time.localtime())
print("sfp_channel: ", sfp_ch ,"itu_channel: ", ch ,"crtt average over "+str(crtt_measurement)+" measurements: "+str(crtt_mean)+" fiber-spool temp: "+str(spool_temp))
#data_file.write((str(sfp_ch)+", "+str(ch)+", "+str(wavelength)+", "+str(crtt_mean)+", "+str(curr_drxm)+", "+str(curr_drxs)+", "+str(spool_temp)+", "+str(curr_temp)+"\n").encode())
result_line= (str(sfp_ch)+", "+str(ch)+", "+str(wavelength)+", "+str(crtt_mean)+", "+str(curr_drxm)+", "+str(curr_drxs)+", "+str(spool_temp)+", "+str(curr_temp)+", "+str(meas_time)+"\n")
except:
print ("### exception during crtt_measurements.")
#continue
return (result_line)
############################################################################
def file_to_array(filename):
"""
Retrieve the delat delay file
filename -- source file from which to retrieve data.
returns: True, <type 'numpy.array'>
[lambda 1 itu-ch, lambda 2 itu-ch],
[lambda 1 itu-ch, lambda 2 itu-ch],
:
False
"Not a Delta Delay file"
"""
# create empty list
pairs=[]
data_file = open(filename, "r")
line = data_file.readline()
if line.strip() != "# Proposed Delta Delay measurements":
Exception("file_to_arrays: Not a Delta Delay measurements file.")
data_file.close()
return (False, alpha_spec_data)
while 1:
line = data_file.readline()
if line[:len("#")] != "#": # Skip lines that are commented out
line_lst = line.split(",")
if len(line_lst) < 3:
break
# Values of interest on one line are lambda-1[nm] and lambda-2[nm]:
# # lambda-1[nm], ITU-ch, SPEC_alpha_3wl(lambda-1), lambda-2[nm], time_err[ps]
l1_wavelength = float(line_lst[0])*1e-9
l2_wavelength = float(line_lst[3])*1e-9
l1 = itu_conv.wavelength_2_itu(l1_wavelength)
l2 = itu_conv.wavelength_2_itu(l2_wavelength)
pair = l1, l2
pairs.append(pair)
arr_pair=numpy.array(pairs)
data_file.close()
return (True, arr_pair)
###############################################
# Main
###############################################
"""
Usage:
wr_serial_3lambda.py -name ddelay.out [-o <dir>] [-m <number>]
wr_serial_3lambda.py -h | --help
Options:
-h --help Show this screen.
-name pointer to a "ddelay.out" file to be taken as input for measurements
-sm master serial port, default: "/dev/ttyUSB2"
-ss slave serial port, default: "/dev/ttyUSB1"
-t <IP> track fiber spool temperature (using PT100 and Digital Multimeter at IP address)
-o <dir> optional directory for output file storage, default: "data/"
-m <number> number of measurement cycles (default = 1 cycle is a sweep from
start to stop lambda)
"""
if __name__ == "__main__":
#arguments = docopt(__doc__,version='White Rabbit controlled via serial port')
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name", help="file containing ddelay measurements to perform")
parser.add_argument("-mserial", default="/dev/ttyUSB2")
parser.add_argument("-sserial", default="/dev/ttyUSB1")
parser.add_argument("-t", help="track fiber spool temperature (using PT100 and Digital Multimeter at IP address)", default=None)
parser.add_argument("-output_dir", default="data")
parser.add_argument("-measurements", default=1, type=int)
args = parser.parse_args()
name = args.name
print("Used Delta Delay input file: ",name)
print("Use Master Serial port: ",args.mserial)
print("Use Slave Serial port: ",args.sserial)
print("Fiber spool temperature track: ",args.t)
print("Output directory: ",args.output_dir)
print("Number of measurement cycles: ", args.measurements)
if os.path.exists(name) == True and os.path.isfile(name) == True:
measure, pairs = file_to_array(name)
else:
print("Delat Delay input file not found")
sys.exit()
# add trailing slash if not present
output_dir = os.path.join(args.output_dir,'')
if os.path.exists(output_dir) != True:
os.mkdir(output_dir)
print("Output directory does not exist => created: "+output_dir)
measurements = args.measurements
# Some constants (for now)
# scan from itu channel start to stop and skip the channel that is used
# for the return channel. "itu_skip_width" can be made larger than 1
# in case the dwdm filters are wider than just the return channel
# Step size of the scan is defined by "itu_channel_increment"
#fixed_delay_mst=int(328182) # Master (dTx + dRx) [ps]
#fixed_delay_slv=int(327963) # Slave (dTx + dRx) [ps]
# A reference measurement will be give the CRTT's for a system without a long fiber.
# This reference measurement will be subtracted from the CRTT measurements for a long fiber.
# In this way, any system typical hardware delays are cancelled.
# Initialize all hardware delays to 0.
fixed_delay_mst=int(0) # Master (dTx + dRx) [ps]
fixed_delay_slv=int(0) # Slave (dTx + dRx) [ps]
master_is_switch = False # If the master is a WR switch then the restart sequence is different from CLB or SPEC
master_has_tunable = True # determines whether the master or the slave has the tunable SFP (due to sfp functions needed
# this only works when master is a CLB or SPEC)
# Master SFP (tunable)
params = tunable.get_parameters()
sfp_module_vendor_id = params["vendor_id"]
itu_channel_start = params["itu_channel_start"]
itu_channel_stop = params["itu_channel_stop"]
#itu_channel_stop = 11.5 ## use this one for testing (it only tunes itu-11 and itu-11.5)
# Slave SFP (fixed)
vendor_id_slv = "EOLS-1612-24205D"
itu_channel_skip = 20
itu_skip_width = 0.5
#itu_channel_increment = params["itu_channel_spacing"]
itu_channel_increment = 1
crtt_measurement = 10 # number of crtt measurements over which the crtt is averaged
crtt_skip = 5 # skip first 5 crtt measurements
restarts = 1 # number of link restarts over which the crtt is averaged
spool_temp = None # if not used then default None
if args.t != None: # open and configure Digital Multimeter with attached PT100
import vxi11
dmm = vxi11.Instrument(args.t)
print(dmm.ask("*IDN?"))
# Returns 'Keysight Technologies,34465A,MY57501367,A.02.14-02.40-02.14-00.49-03-01'
# Configure for 4 wire temperature measurement
dmm.write("SAMPle:COUNt 1")
dmm.write("UNIT:TEMPerature C")
print("Fiber Spool temperature", float(dmm.ask("MEAS:TEMP? FRTD")))
ser_slave = serial.Serial()
ser_slave.port = args.sserial
ser_slave.baudrate = 115200
ser_slave.parity = serial.PARITY_NONE
ser_slave.bytesize = serial.EIGHTBITS
ser_slave.stopbits = serial.STOPBITS_ONE
ser_slave.timeout = None
#ser_slave.timeout = 600 # timeout 10 minutes
ser_slave.open()
ser_master = serial.Serial()
ser_master.port = args.mserial
ser_master.baudrate = 115200
ser_master.parity = serial.PARITY_NONE
ser_master.bytesize = serial.EIGHTBITS
ser_master.stopbits = serial.STOPBITS_ONE
ser_master.timeout = None
#ser_master.timeout = 600 # timeout 10 minutes
ser_master.open()
if (master_has_tunable):
ser_tunable = ser_master
ser_tunable_str = "mst=>"
else:
ser_tunable = ser_slave
ser_tunable_str = "slv=>"
timestamp = time.localtime()
filename_l1_a =output_dir+time.strftime(format("%y%m%d_%H_%M_%S"),timestamp)+"_3_lambda_insitu_alpha_scan_l1_a"
filename_l2_a =output_dir+time.strftime(format("%y%m%d_%H_%M_%S"),timestamp)+"_3_lambda_insitu_alpha_scan_l2_a"
filename_l2_b =output_dir+time.strftime(format("%y%m%d_%H_%M_%S"),timestamp)+"_3_lambda_insitu_alpha_scan_l2_b"
filename_l1_b =output_dir+time.strftime(format("%y%m%d_%H_%M_%S"),timestamp)+"_3_lambda_insitu_alpha_scan_l1_b"
print("save 3-lambda measurement for lambda 1 (-> lambda 2) into file:",filename_l1_a)
print("save 3-lambda measurement for lambda 2 into file:",filename_l2_a)
print("save 3-lambda measurement for lambda 2 (-> lambda 1) into file:",filename_l2_b)
print("save 3-lambda measurement for lambda 1 into file:",filename_l1_b)
data_file_l1_a = open(filename_l1_a,"wb")
data_file_l2_a = open(filename_l2_a,"wb")
data_file_l2_b = open(filename_l2_b,"wb")
data_file_l1_b = open(filename_l1_b,"wb")
file_header = "#date:"+time.strftime(format("%d %b %Y"),timestamp)+"\n"
file_header += "#time:"+time.strftime(format("%H:%M:%S"),timestamp)+"\n"
file_header += "#sfp_channel, ITU channel, ITU wavelength, crtt [ps], drxm, drxs, fiber-spool-temp, wr-slave-temp, meas-time\n"
data_file_l1_a.write(("#3-lambda measurement for lambda 1 (-> lambda 2)\n").encode())
data_file_l1_a.write(file_header.encode())
data_file_l2_a.write(("#3-lambda measurement for lambda 2\n").encode())
data_file_l2_a.write(file_header.encode())
data_file_l2_b.write(("#3-lambda measurement for lambda 2 (-> lambda 1)\n").encode())
data_file_l2_b.write(file_header.encode())
data_file_l1_b.write(("#3-lambda measurement for lambda 1\n").encode())
data_file_l1_b.write(file_header.encode())
# first time link restart to set all in a proper state.
link_restart(ser_master,ser_slave, master_is_switch)
# stop any pending ptp and or statistics output
wr2wrpc(ser_master,"stat off\r","mst=>")
print(ser_master.readline().decode('utf-8'))
wr2wrpc(ser_slave,"stat off\r","slv=>")
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"ptp stop\r","slv=>")
# Set Master dTx = fixed delay (dTx+dRx), dRx = 0, alpha = 0
wr2wrpc(ser_tunable,"sfp erase\r",ser_tunable_str)
wr2wrpc(ser_tunable,"sfp add "+sfp_module_vendor_id+" "+str(fixed_delay_mst)+" 0 0\r",ser_tunable_str)
print(ser_tunable.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp match\r",ser_tunable_str)
print(ser_tunable.readline().decode('utf-8'))
# Set Slave dTx = fixed delay (dTx+dRx), dRx = 0, alpha = 0
wr2wrpc(ser_slave,"sfp erase\r","slv=>")
wr2wrpc(ser_slave,"sfp add "+vendor_id_slv+" "+str(fixed_delay_slv)+" 0 0\r","slv=>")
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_slave,"sfp match\r","slv=>")
print(ser_slave.readline().decode('utf-8'))
wr2wrpc(ser_tunable,"sfp sel_page2\r",ser_tunable_str)
wr2wrpc(ser_slave,"stat on\r","slv=>")
for pair in pairs:
# pair[0] = ITU channel for lambda 1
# pair[1] = ITU channel for lambda 2
# write file delimieter to separate the measurements in the output file
print("ITU-Lambda1 = " + str(pair[0]) + ", ITU-Lambda2 = " + str(pair[1]) + "\r")
data_file_l1_a.write(("ITU-Lambda1 = " + str(pair[0]) + ", ITU-Lambda2 = " + str(pair[1]) + "\r").encode())
data_file_l2_a.write(("ITU-Lambda1 = " + str(pair[0]) + ", ITU-Lambda2 = " + str(pair[1]) + "\r").encode())
data_file_l2_b.write(("ITU-Lambda1 = " + str(pair[0]) + ", ITU-Lambda2 = " + str(pair[1]) + "\r").encode())
data_file_l1_b.write(("ITU-Lambda1 = " + str(pair[0]) + ", ITU-Lambda2 = " + str(pair[1]) + "\r").encode())
# for each pair, repeat 3-lamda wavelength measuremens with link restart "measurement" times
meas = measurements
while meas > 0:
meas = meas - 1
result_line = meas_crtt(ser_tunable, ser_master, ser_slave, master_is_switch, crtt_skip, crtt_measurement, pair[0])
data_file_l1_a.write(result_line.encode())
result_line = meas_crtt(ser_tunable, ser_master, ser_slave, master_is_switch, crtt_skip, crtt_measurement, pair[1])
data_file_l2_a.write(result_line.encode())
result_line = meas_crtt(ser_tunable, ser_master, ser_slave, master_is_switch, crtt_skip, crtt_measurement, pair[1])
data_file_l2_b.write(result_line.encode())
result_line = meas_crtt(ser_tunable, ser_master, ser_slave, master_is_switch, crtt_skip, crtt_measurement, pair[0])
data_file_l1_b.write(result_line.encode())
data_file_l1_a.close()
data_file_l2_a.close()
data_file_l2_b.close()
data_file_l1_b.close()
ser_slave.close()
ser_master.close()
......@@ -136,19 +136,10 @@ def get_waveforms(scope, channels=[1,2,3,4], num_avg=1, output_dir="data"):
file_header += str(chan)+","
file_header += "\n"
# Windows filenames cannot handle the datetime "micro second timing" format.
micro_second_timing = False
if micro_second_timing:
timestamp = datetime.datetime.now() #micro seconds timing
filename = output_dir+timestamp.strftime("%y%m%dT%H:%M:%S.%f")+"_scope_keysight_dso_s_254A_bin"
file_header += "#date:"+timestamp.strftime("%d %b %Y")+"\n"
file_header += "#time:"+timestamp.strftime("%H:%M:%S")+"\n"
else:
timestamp = time.localtime()
filename=output_dir+time.strftime(format("%y%m%d_%H_%M_%S"),timestamp)+"_scope_keysight_dso_s_254A_bin"
file_header += "#date:"+time.strftime(format("%d %b %Y"),timestamp)+"\n"
file_header += "#time:"+time.strftime(format("%H:%M:%S"),timestamp)+"\n"
timestamp = datetime.datetime.now() #micro seconds timing
filename = output_dir+timestamp.strftime("%y%m%dT%H%M%S_%f")+"_scope_keysight_dso_s_254A_bin"
file_header += "#date:"+timestamp.strftime("%d %b %Y")+"\n"
file_header += "#time:"+timestamp.strftime("%H:%M:%S")+"\n"
print("save waveform into file:",filename)
......@@ -526,56 +517,87 @@ def file_to_waveform(filename):
return waveform_data
############################################################################
def osc_init(scope, time_base = 50.0e-9):
def osc_init(scope, init):
"""
Initialize the Oscilloscope for the timestamp edge to SFD measurement.
Initialize the KEYSIGHT TECHNOLOGIES,DSO
scope -- instance of python-vxi connected to the oscilloscope
time_base -- <float> time base, default 50 ns/div
init -- <dict> for example:
init = { \
'channel' : [ 1 , 0 , 1 , 0 ], \
'offset' : [ 0.0, 0.0, 0.0 , 0.0 ], \
'volt_div' : [ 0.5, 1.0, 0.125, 1.0 ], \
'50ohm' : [ 1 , 0 , 1 , 0 ], \
#'sinxx' : [ 0 , 0 , 0 , 0 ], \
'trig' : [ 1 ], \
'trig_level' : [ 0.14 ], \
'timebase' : [ 50e-9 ], \
'refclk' : [ 'ext' ], \
"""
#scope = vxi11.Instrument("192.168.32.248")
print(scope.ask("*IDN?"))
# Returns 'KEYSIGHT TECHNOLOGIES,DSOS254A,MY55160101,05.50.0004'
# Use Channel 1 pulse input
# use Channel 3 Ethernet Frame input
# A fixed trigger level is important for proper timing measurement
# Choose 1.4 Volt for a direct signal but 0.8 Volt when the signal
# is split by a power splitter
scope.write(":TRIGger:EDGE:SOURce CHANnel1")
# Initialize the oscilloscope trigger
scope.write(":TRIGger:SWEep TRIGgered")
trig = str(init['trig'][0])
triglevel = str(float(init['trig_level'][0]))
scope.write(":TRIGger:EDGE:SOURce CHANnel"+ trig)
scope.write(":TRIGger:LEVel CHANnel"+ trig + ", " + triglevel)
use_power_splitter = True
if use_power_splitter:
scope.write(":TRIGger:LEVel CHANnel1, 0.4")
scope.write(":CHANnel1:RANGe 4.0") # 500 mV/div
else:
scope.write(":TRIGger:LEVel CHANnel1, 0.7")
scope.write(":CHANnel1:RANGe 6.0") # 750 mV/div
scope.write(":CHANnel1:INPut DCFifty")
scope.write(":CHANnel1:OFFSet 0.0")
"""
# For Keysight sinxx interpolation is a "Horizontal" setting that
# applies to all enabled channels! Default = False
sinxx = False
"""
scope.write(":CHANnel3:INPut DCFifty")
scope.write(":CHANnel3:OFFSet 0.0")
scope.write(":CHANnel3:RANGe 1.0") # 125 mV/div
scope.write(":CHANnel4:INPut DCFifty")
scope.write(":CHANnel4:OFFSet 0.0")
scope.write(":CHANnel4:RANGe 1.0") # 125 mV/div
for ch in range(4):
# Set channel ON/OFF
if init['channel'][ch] == 1:
scope.write(":CHANnel" + str(ch+1) + ":DISPlay ON")
else:
scope.write(":CHANnel" + str(ch+1) + ":DISPlay OFF")
# Set channel Offset
scope.write(":CHANnel" + str(ch+1) + ":OFFSet " + str(float(init['offset'][ch])))
# Set channel Volt/Div
volt_div = float(init['volt_div'][ch]/0.125) # Volt/Div is per 125 mV
scope.write(":CHANnel" + str(ch+1) + ":RANGe " + str(volt_div))
# Set channel Coupling
#'50ohm' : [ 1 , 0 , 1 , 0 ], \
if init['50ohm'][ch] == 1:
scope.write(":CHANnel" + str(ch+1) + ":INPut DCFifty")
else:
scope.write(":CHANnel" + str(ch+1) + ":INPut DC")
"""
# Set Interpolation for all used channels to "16 point Sin(x)/x"
#'sinxx' : [ 1 , 0 , 1 , 0 ], \
# Check if one of the channels is set to sinxx then enable sinxx for all
if init['sinxx'][ch] == 1:
sinxx = True
if sinxx:
scope.write(":ACQuire:INTerpolate INT16")
else:
scope.write(":ACQuire:INTerpolate OFF")
"""
# Trigger in the centre of the screen; important for maximum estimations
# forwarded to function average_edge_to_sfd
# Trigger in the centre of the screen and set timebase
scope.write(":TIMebase:DELay 0")
scope.write(":TIMebase:RANGe "+str(10*time_base)) # set 50 ns/div
scope.write(":TIMebase:REFClock ON") # set external refrence clock
scope.write(":TIMebase:RANGe "+str(10*float(init['timebase'][0]))) # set 50 ns/div
return
# Set internal/external 10 MHz timebase
if init['refclk'][0] == 'ext':
scope.write(":TIMebase:REFClock ON")
else:
scope.write(":TIMebase:REFClock OFF")
return
############################################################################
##
## If run from commandline, we can test the library
......
......@@ -41,6 +41,7 @@ import sys
import time
import scipy
import struct
import datetime
import pdb
#TJP: installed from web python-vxi Alex
......@@ -135,16 +136,20 @@ def get_waveforms(scope, channels=[1,2,3,4],num_avg=1,output_dir="data"):
os.mkdir(output_dir)
print("Output directory does not exist => created: "+output_dir)
timestamp = time.localtime()
filename = output_dir+time.strftime(format("%y%m%d_%H_%M_%S"),timestamp)+"_LeCroy8254_bin"
print("save LeCroy8254 Waveform into file:",filename)
file_header = "#WaveformData:LeCroy8254\n"
file_header += "#version:0.2\n"
file_header += "#type:RAW\n"
file_header += "#channel:"+str(channels)+"\n"
file_header += "#date:"+time.strftime(format("%d %b %Y"),timestamp)+"\n"
file_header += "#time:"+time.strftime(format("%H:%M:%S"),timestamp)+"\n"
#file_header += "#date:"+time.strftime(format("%d %b %Y"),timestamp)+"\n"
#file_header += "#time:"+time.strftime(format("%H:%M:%S"),timestamp)+"\n"
timestamp = datetime.datetime.now() #micro seconds timing
filename = output_dir+timestamp.strftime("%y%m%dT%H%M%S_%f")+"_LeCroy8254_bin"
file_header += "#date:"+timestamp.strftime("%d %b %Y")+"\n"
file_header += "#time:"+timestamp.strftime("%H:%M:%S")+"\n"
print("save LeCroy8254 Waveform into file:",filename)
file_header += "#byteorder:LSBFIRST\n"
channel_preamble = []
channel_descriptor = []
......@@ -700,55 +705,74 @@ def file_to_waveform(filename):
return waveform_data
############################################################################
def osc_init(scope, time_base = 50.0e-9):
def osc_init(scope, init):
"""
Initialize the Oscilloscope for the timestamp edge to SFD measurement.
Initialize the LeCroy,DSO
scope -- instance of python-vxi connected to the oscilloscope
time_base -- <float> time base, default 50 ns/div
init -- <dict> for example:
init = { \
'channel' : [ 1 , 0 , 1 , 0 ], \
'offset' : [ 0.0, 0.0, 0.0 , 0.0 ], \
'volt_div' : [ 0.5, 1.0, 0.125, 1.0 ], \
'50ohm' : [ 1 , 0 , 1 , 0 ], \
#'sinxx' : [ 0 , 0 , 0 , 0 ], \
'trig' : [ 1 ], \
'trig_level' : [ 0.14 ], \
'timebase' : [ 50e-9 ], \
'refclk' : [ 'ext' ], \
"""
#scope = vxi11.Instrument("192.168.32.243")
#scope = vxi11.Instrument("192.168.32.248")
print(scope.ask("*IDN?"))
# Returns '*IDN LECROY,HDO4034-MS,LCRY-HDO,7.9.0'
# Use Channel 1 pulse input
# use Channel 3 Ethernet Frame input
# A fixed trigger level is important for proper timing measurement
# MiniCircuits Splitters ZFRSC-123+ have ~ 6 + 3,75 dB attenuation (~ factor 3).
# A 2,4 V signal split once results in 0,8 V, slit twice in 260 mV.
scope.write("TRIG_SELECT EDGE,SR,C1")
use_power_splitter = True
if use_power_splitter:
scope.write("C1:TRIG_LEVEL 0.15")
scope.write("C1:Volt_DIV 0.25")
else:
scope.write("C1:TRIG_LEVEL 0.3")
scope.write("C1:Volt_DIV 0.5")
scope.write("C1:COUPLING D50")
scope.write("C1:OFFSET 0.0")
scope.write("VBS 'app.Acquisition.C1.InterpolateType = \"sinxx\"'")
scope.write("C3:COUPLING D50")
scope.write("C3:OFFSET 0.0")
scope.write("C3:Volt_DIV 0.25")
scope.write("VBS 'app.Acquisition.C3.InterpolateType = \"sinxx\"'")
scope.write("C4:COUPLING D50")
scope.write("C4:OFFSET 0.0")
scope.write("C4:Volt_DIV 0.25")
scope.write("VBS 'app.Acquisition.C4.InterpolateType = \"sinxx\"'")
# Returns 'LECROY,WAVERUNNER8254M-MS,LCRY4253N20398,8.4.1'
# Initialize the oscilloscope trigger
trig = str(init['trig'][0])
triglevel = str(float(init['trig_level'][0]))
scope.write("TRIG_SELECT EDGE,SR,C" + trig)
scope.write("C" + trig + ":TRIG_LEVEL " + triglevel)
for ch in range(4):
# Set channel ON/OFF
if init['channel'][ch] == 1:
scope.write("C" + str(ch+1) + ":TRACE ON")
else:
scope.write("C" + str(ch+1) + ":TRACE OFF")
# Set channel Offset
scope.write("C" + str(ch+1) + ":OFFSET " + str(float(init['offset'][ch])))
# Set channel Volt/Div
volt_div = float(init['volt_div'][ch])
scope.write("C" + str(ch+1) + ":Volt_DIV " + str(volt_div))
# Set channel Coupling
#'50ohm' : [ 1 , 0 , 1 , 0 ], \
if init['50ohm'][ch] == 1:
scope.write("C" + str(ch+1) + ":COUPLING D50")
else:
scope.write("C" + str(ch+1) + ":COUPLING D1M")
"""
# Set Interpolation for all used channels to "Compatible Mode 10"
#'sinxx' : [ 1 , 0 , 1 , 0 ], \
if init['sinxx'][ch] == 1:
scope.write("VBS 'app.Acquisition.C" + str(ch+1) + ".InterpolateType = \"sinxx\"'")
else:
scope.write("VBS 'app.Acquisition.C" + str(ch+1) + ".InterpolateType = \"linear\"'")
"""
# Trigger in the centre of the screen; important for maximum estimations
# forwarded to function average_edge_to_sfd
# Trigger in the centre of the screen and set timebase
scope.write("TRIG_DELAY 0 ns")
scope.write("TIME_DIV "+str(time_base)) # set 50 ns/div
scope.write("REFERENCE_CLOCK EXTERNAL") # set external refrence clock
scope.write("TIME_DIV "+str(float(init['timebase'][0])))
# Set internal/external 10 MHz timebase
if init['refclk'][0] == 'ext':
scope.write("REFERENCE_CLOCK EXTERNAL")
else:
scope.write("REFERENCE_CLOCK INTERNAL")
return
......@@ -789,7 +813,8 @@ if __name__ == "__main__":
# Set Interpolation for all used channels to "Compatible Mode 10"
for chan in args.channels:
scope.write("VBS 'app.Acquisition.C" + str(chan) + ".InterpolateType = \"sinxx\"'")
#scope.write("VBS 'app.Acquisition.C" + str(chan) + ".InterpolateType = \"sinxx\"'")
pass
#print("VBS 'app.Acquisition.C" + str(chan) + ".InterpolateType = \"sinxx\"'")
# Use Channel 1 pulse input
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment