123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- import time
- from struct import *
- import ctypes
- import array
- import numpy as np
- import matplotlib.pyplot as plt
- import os
- import eel # GUI
- from ADUCv2p1 import *
- ###################################
- ## PYTHON UTILITIES
- ###################################
- last_wf_number = 0
- last_timestamp = 0
- def save_waveform():
- global last_timestamp, last_wf_number
- chip = chips[state["selected_board"]]
- data = chip.read_data()
- gnd = sum(data[state["start_gnd"]:state["stop_gnd"]])/(state["stop_gnd"]-state["start_gnd"])
- signal = sum(data[state["start"]:state["stop"]])/(state["stop"]-state["start"])
- gnd_std = np.std(data[state["start_gnd"]:state["stop_gnd"]])
- signal_std = np.std(data[state["start"]:state["stop"]])
- wf_number = chip.get_wf_cnt()
- timestamp = time.time()
- print(wf_number, timestamp, last_wf_number, last_timestamp)
- if(last_wf_number>0 and wf_number - last_wf_number>0):
- state["board_freq"] = (timestamp - last_timestamp)/(wf_number - last_wf_number)
- else:
- state["board_freq"] = 0
- print(state["board_freq"])
- last_wf_number, last_timestamp = wf_number, timestamp
- tosave = [wf_number, timestamp, state["start"], state["stop"], state["start_gnd"], state["stop_gnd"], state["input_gain"], state["offset"], signal, gnd, signal_std, gnd_std, state["wf_len"]] + list(data)
- np.savetxt("data/waveforms/"+str(int(timestamp*100))+".csv", [tosave], delimiter=",", fmt='%10.5f')
- # Save more data for long term graphs
- tosave = [wf_number, timestamp, signal, gnd, signal-gnd, signal_std, gnd_std, chip.get_mode(), chip.get_out_of_lock(), chip.get_Vout(1), chip.get_Vout(2)]
- line = '\n'+','.join(map(str, tosave))
- with open('data/long_term.csv','a') as fd:
- fd.write(line)
- #update_state()
- import datetime
- @eel.expose
- def clean_old_files(path, max_Files):
- def sorted_ls(path):
- mtime = lambda f: os.stat(os.path.join(path, f)).st_mtime
- return list(sorted(os.listdir(path), key=mtime))
-
- del_list = sorted_ls(path)[0:(len(sorted_ls(path))-max_Files)]
- for dfile in del_list:
- os.remove(path + dfile)
- '''for dirpath, dirnames, filenames in os.walk("data/waveforms/"):
- for file in filenames:
- curpath = os.path.join(dirpath, file)
- file_modified = datetime.datetime.fromtimestamp(os.path.getmtime(curpath))
- if datetime.datetime.now() - file_modified > datetime.timedelta(hours=10):
- os.remove(curpath)'''
- @eel.expose
- def clean_long_term():
- with open('data/long_term.csv','w') as fd:
- fd.write('')
- @eel.expose
- def calibrate_gain():
- if(state["mode"]!=0):
- error("You must be in learn mode to calibrate the loop gain")
- return
- message("Calibrating...")
- chip = chips[state["selected_board"]]
- auto_set_pga = state["auto_set_pga"]
- chip.set_auto_set_pga(0) #Stop it while we scan
- measurements = []
- for Vfine in range(2000, 4000, 100):
- chip.set_Vout(2, Vfine)
- time.sleep(0.1)
- data = chip.read_data()
- gnd = sum(data[state["start_gnd"]:state["stop_gnd"]])/(state["stop_gnd"]-state["start_gnd"])
- signal = sum(data[state["start"]:state["stop"]])/(state["stop"]-state["start"])
- print('Vfine', chip.get_Vout(2), 'signal', signal-gnd)
- measurements.append([chip.get_Vout(2), signal-gnd])
- chip.set_Vout(2, 3000)
-
- measurements = np.array(measurements)
- p = np.polyfit(measurements[:,0], measurements[:,1], deg=1)
- print('signal-gnd vs Vfine slope', p[0], 'intercept', p[1])
- chip.set_Gain(1/p[0])
- print('Gain has been set to 1/slope', 1/p[0])
- plt.scatter(measurements[:,0], measurements[:,1], label='Measurements')
- plt.plot(np.arange(2000, 4000, 100), np.arange(2000, 4000, 100)*p[0] + p[1], label='Linear fit')
- plt.legend()
- plt.xlabel('Fine voltage')
- plt.ylabel('Photodiode signal')
- plt.show()
- chip.set_auto_set_pga(auto_set_pga)
- update_state()
- @eel.expose
- def calibrate_coarse_fine_ratio():
- if(state["mode"]!=0):
- error("You must be in learn mode to calibrate the broad to fine ratio")
- return
- message("Calibrating...")
- chip = chips[state["selected_board"]]
- auto_set_pga = state["auto_set_pga"]
- chip.set_auto_set_pga(0) #Stop it while we scan
- # Scan Vfine
- measurements = []
- for Vfine in range(2500, 3500, 100):
- chip.set_Vout(2, Vfine)
- time.sleep(0.1)
- data = chip.read_data()
- gnd = sum(data[state["start_gnd"]:state["stop_gnd"]])/(state["stop_gnd"]-state["start_gnd"])
- signal = sum(data[state["start"]:state["stop"]])/(state["stop"]-state["start"])
- print('Vfine', chip.get_Vout(2), 'signal', signal-gnd)
- measurements.append([chip.get_Vout(2), signal-gnd])
- chip.set_Vout(2, 3000)
- measurements = np.array(measurements)
- p = np.polyfit(measurements[:,0], measurements[:,1], deg=1)
- # Scan Vcoarse
- measurements = []
- low, high = state["Vlearn"]-100, state["Vlearn"]+100
- if(low<0):
- low=0
- if(high>4000):
- high=4000
- for Vcoarse in range(low, high, 20):
- chip.set_Vlearn(Vcoarse)
- time.sleep(0.1)
- data = chip.read_data()
- gnd = sum(data[state["start_gnd"]:state["stop_gnd"]])/(state["stop_gnd"]-state["start_gnd"])
- signal = sum(data[state["start"]:state["stop"]])/(state["stop"]-state["start"])
- print('Vcoarse', chip.get_Vlearn(), 'signal', signal-gnd)
- measurements.append([chip.get_Vlearn(), signal-gnd])
- chip.set_Vlearn(state["Vlearn"])
- measurements = np.array(measurements)
- q = np.polyfit(measurements[:,0], measurements[:,1], deg=1)
- # Set to ratio
- print('Setting coarse_fine_ratio to', q[0]/p[0])
- chip.set_coarse_fine_ratio(q[0]/p[0])
- chip.set_auto_set_pga(auto_set_pga)
- update_state()
- @eel.expose
- def measure_response_function():
- message("Measuring...")
- if(state["mode"]!=0):
- error("You must be in learn mode to measure the response function.")
- return
- chip = chips[state["selected_board"]]
- auto_set_pga = state["auto_set_pga"]
- chip.set_auto_set_pga(0) #Stop it while we scan
- # Scan Vcoarse
- measurements = []
- for Vcoarse in range(0, 4000, 100):
- chip.set_Vlearn(Vcoarse)
- time.sleep(0.1)
- data = chip.read_data()
- gnd = sum(data[state["start_gnd"]:state["stop_gnd"]])/(state["stop_gnd"]-state["start_gnd"])
- signal = sum(data[state["start"]:state["stop"]])/(state["stop"]-state["start"])
- print('Vcoarse', chip.get_Vlearn(), 'signal', signal-gnd)
- measurements.append([chip.get_Vlearn(), signal-gnd])
- chip.set_Vlearn(state["Vlearn"])
- measurements = np.array(measurements)
-
- plt.plot(measurements[:,0], measurements[:,1])
- plt.xlabel('Output voltage')
- plt.ylabel('Photodiode signal')
- plt.show()
- chip.set_auto_set_pga(auto_set_pga)
- update_state()
- @eel.expose
- def sdev_time():
- pass
- @eel.expose
- def noise_power_spectrum():
- pass
- ###################################
- ## EXPOSED GUI COMMUNICATION
- ###################################
- # Graphs
- from os import listdir
- @eel.expose
- def listFiles(path):
- return listdir(path)
- @eel.expose
- def loadFile(path):
- try:
- return list(np.loadtxt(path, delimiter=","))
- except:
- print('Could not load file', path)
- @eel.expose
- def loadLongTerm():
- try:
- li = list(np.loadtxt('data/long_term.csv', delimiter=","))
- if((li[-1][1]-li[0][1])/60/60 > 24 or len(li)>100000): # Time to clean up, delete until we have less than 90000 points and 20 hours of data
- with open('data/long_term.csv') as f, open("data/long_term_tmp.csv", "w") as out:
- for x in range(len(li)):
- if(len(li)-x>90000 or (li[-1][1]-li[x][1])/60/60 > 20):
- next(f)
- for line in f:
- out.write(line)
- os.remove("data/long_term.csv")
- os.rename("data/long_term_tmp.csv", "data/long_term.csv")
- return [list(l) for l in li]
- except:
- print('Couldnt load this')
- # Expose functions to GUI and do some parameter checking
- def error(txt):
- eel.error(txt)
- eel.renderUI(state)
- def warning(txt):
- eel.warning(txt)
- def message(txt):
- eel.message(txt)
- @eel.expose
- def set_selected_board(n):
- if n>len(chips):
- error("Selected board does not exist.")
- return;
- state["selected_board"] = n
- update_state()
- @eel.expose
- def set_pi_freq(freq):
- if(freq>100):
- error("The communication cannot be this fast. High values are likely to disturb the board.")
- return
- if(freq<0.01):
- error("Frequency must be at least 0.01Hz.")
- return
- if(freq>10):
- warning("High values are likely to disturb the board.")
- state["pi_freq"] = freq
- eel.renderUI(state)
- @eel.expose
- def set_remote_trigg(status):
- status = int(status)
- if status not in [0, 1]:
- error("remote_trigg must be set to either 0 or 1.")
- return
- chips[state["selected_board"]].set_remote_trigg(status)
- update_state()
- @eel.expose
- def set_enab_gnd(status):
- status = int(status)
- if status not in [0, 1]:
- error("enab_gnd must be set to either 0 or 1.")
- return
- chips[state["selected_board"]].set_enab_gnd(status)
- update_state()
- @eel.expose
- def set_Vlearn(Vlearn):
- if Vlearn>4095 or Vlearn<0:
- error("Vlearn must be in the range 0-4095")
- return
- if Vlearn<2000:
- warning("Low values of Vlearn will heavily attenuate the output. See the response curve.")
- if Vlearn>3500:
- warning("High values of Vlearn may not leave enough room for the stabilization process and may result in the board going out of loop. See the response curve.")
- chips[state["selected_board"]].set_Vlearn(Vlearn)
- update_state()
- @eel.expose
- def set_start(start):
- if start>255 or start<0:
- error("start must be in the range 0-256")
- return
- if start>state["stop"]:
- error("start must be lower than stop")
- return
- if start>state["wf_len"]:
- error("start must be lower than the waveform length")
- return
- chips[state["selected_board"]].set_start(start)
- update_state()
- @eel.expose
- def set_stop(stop):
- if stop>255 or stop<0:
- error("stop must be in the range 0-256")
- return
- if stop<state["start"]:
- error("start must be lower than stop")
- return
- if stop>state["wf_len"]:
- error("stop must be lower than the waveform length")
- return
- chips[state["selected_board"]].set_stop(stop)
- update_state()
- @eel.expose
- def set_start_gnd(start_gnd):
- if start_gnd>255 or start_gnd<0:
- error("start_gnd must be in the range 0-256")
- return
- if start_gnd>state["stop_gnd"]:
- error("start_gnd must be lower than stop")
- return
- if start_gnd>state["wf_len"]:
- error("start_gnd must be lower than the waveform length")
- return
- chips[state["selected_board"]].set_start_gnd(start_gnd)
- update_state()
- @eel.expose
- def set_stop_gnd(stop_gnd):
- if stop_gnd>255 or stop_gnd<0:
- error("stop_gnd must be in the range 0-256")
- return
- if stop_gnd<state["start_gnd"]:
- error("start must be lower than stop")
- return
- if stop_gnd>state["wf_len"]:
- error("stop_gnd must be lower than the waveform length")
- return
- chips[state["selected_board"]].set_stop_gnd(stop_gnd)
- update_state()
- @eel.expose
- def set_wf_len(wf_len):
- if wf_len>255 or wf_len<0:
- error("wf_len must be in the range 0-256")
- return
- if wf_len<state["stop"] or wf_len<state["stop_gnd"]:
- error("wf_len must be higher than both stop and stop_gnd")
- return
- chips[state["selected_board"]].set_wf_len(wf_len)
- update_state()
- @eel.expose
- def set_N(N):
- N = int(N)
- if N > 5:
- warning("Note that increasing the Number of waveforms per stabilization loop decreases the speed of the stabilization. We typically just have N=1.")
- chips[state["selected_board"]].set_N(N)
- update_state()
- @eel.expose
- def set_step_max(step):
- if step>4095 or step<1:
- error("step_max must be in the range 0-1")
- return
- if step<50:
- warning("step_max seems low. This may limit the ability to react to fast power fluctuations.")
- chips[state["selected_board"]].set_step_max(step)
- update_state()
- @eel.expose
- def set_Gain(*params):
- chips[state["selected_board"]].set_Gain(*params)
- update_state()
- @eel.expose
- def set_auto_set_pga(status):
- if status not in [0, 1]:
- error("auto_set_pga must be set to either 0 or 1.")
- return
- chips[state["selected_board"]].set_auto_set_pga(status)
- update_state()
- @eel.expose
- def set_input_gain(input_gain):
- if input_gain not in [1, 2, 4, 8, 16, 32, 64, 128]:
- error("input_gain must be one of [1, 2, 4, 8, 16, 32, 64, 128]")
- return
- chips[state["selected_board"]].set_input_gain(input_gain)
- update_state()
- @eel.expose
- def set_offset(offset):
- if offset>4095 or offset<0:
- error("offset must be in the range 0-4095. 2000 corresponds to no offset.")
- return
- chips[state["selected_board"]].set_offset(offset)
- update_state()
- @eel.expose
- def set_coarse_fine_ratio(coarse_fine_ratio):
- if coarse_fine_ratio<10 or coarse_fine_ratio>30:
- error("coarse_fine_ratio should be approximately 20.")
- return
- if coarse_fine_ratio<15 or coarse_fine_ratio>25:
- warning("coarse_fine_ratio should be approximately 20.")
- chips[state["selected_board"]].set_coarse_fine_ratio(coarse_fine_ratio)
- update_state()
- # Program state
- state = {
- "n_boards": 2,
- "selected_board": 0,
- "box_address": 0x50,
- "mode": 0,
- "out_of_lock": 0,
- "pi_freq": 1,
- "board_freq": 0,
- "remote_trigg": 0,
- "enab_gnd": 1,
- "Vlearn": 3200,
- "start": 25,
- "stop": 100,
- "start_gnd": 125,
- "stop_gnd": 200,
- "wf_len": 200,
- "N": 1,
- "step_max": 200,
- "Gain": 1.0,
- "auto_set_pga": 1,
- "input_gain": 1,
- "offset": 2000,
- "coarse_fine_ratio": 20
- }
- def update_state():
- state["n_boards"] = len(chips)
- state["box_address"] = adresses[state["selected_board"]]
- chip = chips[state["selected_board"]]
- state["enab_gnd"] = chip.get_enab_gnd()
- state["mode"] = chip.get_mode()
- state["out_of_lock"] = chip.get_out_of_lock()
- state["remote_trigg"] = chip.get_remote_trigg()
- state["Vlearn"] = chip.get_Vlearn()
- state["start"] = chip.get_start()
- state["stop"] = chip.get_stop()
- state["start_gnd"] = chip.get_start_gnd()
- state["stop_gnd"] = chip.get_stop_gnd()
- state["wf_len"] = chip.get_wf_len()
- state["N"] = chip.get_N()
- state["step_max"] = chip.get_step_max()
- state["Gain"] = chip.get_Gain()
- state["auto_set_pga"] = chip.get_auto_set_pga()
- state["input_gain"] = chip.get_input_gain()
- state["offset"] = chip.get_offset()
- state["coarse_fine_ratio"] = chip.get_coarse_fine_ratio()
- for l in state:
- if isinstance(state[l], np.uint16) or isinstance(state[l], np.int32):
- state[l] = int(state[l])
- if isinstance(state[l], np.float32):
- state[l] = float(state[l])
- eel.renderUI(state)
- ###################################
- ## START THE GUI
- ###################################
- my_options = {
- 'mode': "chrome-app", #chrome-app
- 'host': 'localhost',
- 'port': 8000 + int(np.random.rand()*1000),
- 'size':(660, 605),
- #'chromeFlags': ["--start-fullscreen", "--browser-startup-dialog"]
- }
- eel.init('web')
- eel.start('main.html', options=my_options, block=False)
- # Detect all boards
- import os
- import subprocess
- import re
- chips = []
- adresses = []
- # TO DO
- p = subprocess.Popen(['i2cdetect', '-y','1'],stdout=subprocess.PIPE,)
- p.stdout.readline()
- for i in range(0,8):
- line = str(p.stdout.readline())[4:]
- for match in re.finditer("[0-9a-f]+", line):
- adresses.append(int(match.group(0), 16))
- chips.append(ADUCv2p1(int(match.group(0), 16),True))
- print('Found boards', adresses, chips)
- eel.renderUI(state)
- eel.sleep(5)
- update_state()
- eel.renderUI(state)
-
-
- i = 0
- while(True):
- #eel.renderUI(state) # TO DO
- save_waveform() # TO DO
- eel.sleep(1/state["pi_freq"])
- if(i%100==0):
- clean_old_files("data/waveforms/", 1000)
- i += 1
-
-
- print(state)
|