123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- eel.expose(renderUI);
- eel.expose(error)
- eel.expose(warning)
- eel.expose(message)
- // Helper functions
- function range(n){
- return [...Array(n).keys()];
- }
- function onload(){ //Bind events
- // Changing tabs
- tabs = document.querySelector('#tabs').children
- for (var i = 0; i < tabs.length; i++){
- tabs[i].addEventListener("click", function(event){
- eel.set_selected_board(event.srcElement.getAttribute("i"))
- })
- }
- // Box information
- document.querySelector('#piFreq').addEventListener("focusout", function(event){
- eel.set_pi_freq(parseFloat(event.srcElement.value))
- })
- document.querySelector('#remoteTrigg').addEventListener("click", function(event){
- eel.set_remote_trigg(event.srcElement.checked ? 1 : 0)
- })
- // Learning options
- document.querySelector('#enabGnd').addEventListener("click", function(event){
- eel.set_enab_gnd(event.srcElement.checked ? 1 : 0)
- })
- document.querySelector('#Vlearn').addEventListener("focusout", function(event){
- eel.set_Vlearn(parseInt(event.srcElement.value))
- })
- document.querySelector('#start').addEventListener("focusout", function(event){
- eel.set_start(parseInt(event.srcElement.value))
- })
- document.querySelector('#stop').addEventListener("focusout", function(event){
- eel.set_stop(parseInt(event.srcElement.value))
- })
- document.querySelector('#startGnd').addEventListener("focusout", function(event){
- eel.set_start_gnd(parseInt(event.srcElement.value))
- })
- document.querySelector('#stopGnd').addEventListener("focusout", function(event){
- eel.set_stop_gnd(parseInt(event.srcElement.value))
- })
- document.querySelector('#N').addEventListener("focusout", function(event){
- eel.set_N(parseInt(event.srcElement.value))
- })
- document.querySelector('#wfLen').addEventListener("focusout", function(event){
- eel.set_wf_len(parseInt(event.srcElement.value))
- })
- // Locking options
- document.querySelector('#stepMax').addEventListener("focusout", function(event){
- eel.set_max_step(parseInt(event.srcElement.value))
- })
- document.querySelector('#Gain').addEventListener("focusout", function(event){
- eel.set_Gain(parseFloat(event.srcElement.value))
- })
- document.querySelector('#calibrateGain').addEventListener("click", function(event){
- eel.calibrate_gain()
- })
- // Input options
- document.querySelector('#autoSetPga').addEventListener("click", function(event){
- eel.set_auto_set_pga(event.srcElement.checked ? 1 : 0)
- })
- document.querySelector('#inputGain').addEventListener("focusout", function(event){
- eel.set_input_gain(parseInt(event.srcElement.value))
- })
- document.querySelector('#offset').addEventListener("focusout", function(event){
- eel.set_offset(parseInt(event.srcElement.value))
- })
- // Output options
- document.querySelector('#coarseFineRatio').addEventListener("focusout", function(event){
- eel.set_coarse_fine_ratio(parseFloat(event.srcElement.value))
- })
- document.querySelector('#calibrateCoarseFineRatio').addEventListener("click", function(event){
- eel.calibrate_coarse_fine_ratio()
- })
- // Analysis tools
- document.querySelector('#measureResponseFunction').addEventListener("click", function(event){
- eel.measure_response_function()
- })
- document.querySelector('#sdevTime').addEventListener("click", function(event){
- eel.sdev_time()
- })
- document.querySelector('#noisePowerSpectrum').addEventListener("click", function(event){
- eel.noise_power_spectrum()
- })
- // Graphs
- document.getElementById("waveformGraphSelect").addEventListener("change", function(){
- document.querySelector('#waveformGraphAutoupdate').checked = false
- loadGraph()
- })
- document.getElementById("longGraphX").addEventListener("change", function(){
- loadLongGraph()
- })
- document.getElementById("longGraphY").addEventListener("change", function(){
- loadLongGraph()
- })
- document.querySelector('#waveformGraphClear').addEventListener("click", function(event){
- eel.clean_old_files("data/waveforms/", 0)
- })
- document.querySelector('#longGraphClear').addEventListener("click", function(event){
- eel.clean_long_term()
- })
- // Information for simple usage
- tippy('#boxAdress', {delay: 3000, content: "The i2c adress used for communication with the board. This is automatically obtained.",})
- tippy('#outOfLock', {delay: 3000, content: "The box is out of lock when the output of the board is maximum, and thus fluctuations cannot be stabilized anymore.",})
- tippy('#piFreq', {delay: 3000, content: "Frequency at which the Pi polls the board for new waveforms, typically no more than 10Hz as this can disturb the board.",})
- tippy('#boardFreq', {delay: 3000, content: "Frequency at which the board is currently measuring waveforms (untested).",})
- tippy('#remoteTrigg', {delay: 3000, content: "If true, the board will continously trigger, ignoring the trigger input. For normal operation set to false.",})
- tippy('#enabGnd', {delay: 3000, content: "If true (recommended), the board stabilizes signal-gnd, otherwise it stabilizes signal",})
- tippy('#Vlearn', {delay: 3000, content: "The output voltage (0-4095) when the box is in learn mode. This can be used to select an appropiate input power. Small values will unnecessarily suppress the signal and large values (>3500, see response function) may result in out_of_lock due to the limited range.",})
- tippy('#start', {delay: 3000, content: "Point # where the signal starts being measured. Sampling frequency ~1MHz.",})
- tippy('#stop', {delay: 3000, content: "Point # where the signal stop being measured. Sampling frequency ~1MHz.",})
- tippy('#startGnd', {delay: 3000, content: "Point # where the ground starts being measured. Sampling frequency ~1MHz.",})
- tippy('#stopGnd', {delay: 3000, content: "Point # where the ground stops being measured. Sampling frequency ~1MHz.",})
- tippy('#N', {delay: 3000, content: "Number of waveforms (typ. 1) to sample in each stabilization cycle.",})
- tippy('#wfLen', {delay: 3000, content: "Number of points to sample (1-255)",})
- tippy('#stepMax', {delay: 3000, content: "Maximum step allowed in one stabilization cycle (typ. 200) . Small values may lead to slow response to sharp fluctuations.",})
- tippy('#Gain', {delay: 3000, content: "At every step Vout += (Vmeasured-Vset)*Gain",})
- tippy('#calibrateGain', {delay: 3000, content: "Automatically select a loop gain based on the response function of the system.",})
- tippy('#autoSetPga', {delay: 3000, content: "When True, the board changes the input gain and offset so that the signal is in an appropiate range (not clipped and going >2000). Set to False to select it manually.",})
- tippy('#inputGain', {delay: 3000, content: "Allowed values: [1, 2, 4, 8, 16, 32, 64, 128]",})
- tippy('#offset', {delay: 3000, content: "Input offset (0-4096). 2000 corresponds to no offset.",})
- tippy('#coarseFineRatio', {delay: 3000, content: "Ratio of the precision in the fine and broad outputs. Typ. 20 from circuit design.",})
- tippy('#calibrateCoarseFineRatio', {delay: 3000, content: "Calibrate the ratio by measuring the response functions of the broad and fine outputs.",})
- tippy('#measureResponseFunction', {delay: 3000, content: "Measure the photodiode signal as a funtion of the output voltage.",})
- setTimeout(loop, 100)
- }
- j = 0
- function loop(){
- if(document.getElementById("waveformGraphSelect") != document.activeElement){
- loadGraphList()
- }
- if(document.querySelector('#longGraphAutoupdate').checked){
- // Don't update this too often
- if(j%10==0){loadLongGraph()}
- }
- j++
- setTimeout(loop, 1000)
- }
- function renderUI(state){
- //console.log('Updating UI')
- // BOX INFORMATION
- tabs = document.querySelector('#tabs').children
- for (var i = 0; i < tabs.length; i++){
- tabs[i].classList.remove('active')
- if(i>=state.n_boards){
- tabs[i].style.opacity = 0
- }
- else{
- tabs[i].style.opacity = 1
- }
- }
- tabs[state.selected_board].classList.add('active')
- document.querySelector('#boxAddress').value = "0x"+state.box_address.toString(16)
- document.querySelector('#isLearn').checked = false
- document.querySelector('#isLock').checked = false
- if(state.mode == 0) document.querySelector('#isLearn').checked = true
- if(state.mode == 1) document.querySelector('#isLock').checked = true
- document.querySelector('#outOfLock').checked = false
- if(state.out_of_lock == 1) document.querySelector('#outOfLock').checked = true
- document.querySelector('#piFreq').value = state.pi_freq
- document.querySelector('#boardFreq').value = state.board_freq
- document.querySelector('#remoteTrigg').checked = false
- if(state.remote_trigg == 1) document.querySelector('#remoteTrigg').checked = true
- // LEARNING OPTIONS
- document.querySelector('#enabGnd').checked = state.enab_gnd
- document.querySelector('#Vlearn').value = state.Vlearn
- document.querySelector('#start').value = state.start
- document.querySelector('#stop').value = state.stop
- document.querySelector('#startGnd').value = state.start_gnd
- document.querySelector('#stopGnd').value = state.stop_gnd
- document.querySelector('#N').value = state.N
- document.querySelector('#wfLen').value = state.wf_len
- // LOCKING OPTIONS
- document.querySelector('#stepMax').value = state.step_max
- document.querySelector('#Gain').value = state.Gain
- // INPUT OPTIONS
- document.querySelector('#autoSetPga').checked = state.auto_set_pga
- document.querySelector('#inputGain').disabled = state.auto_set_pga==1
- document.querySelector('#offset').disabled = state.auto_set_pga==1
- document.querySelector('#inputGain').value = state.input_gain
- document.querySelector('#offset').value = state.offset
- // OUTPUT OPTIONS
- document.querySelector('#coarseFineRatio').value = state.coarse_fine_ratio
- }
- async function loadGraphList(){
- files = await eel.listFiles('data/waveforms/')()
- timestamps = files.map(s => parseInt(s.replace('.csv', '')))
- timestamps.sort()
- dates = []
- for(timestamp of timestamps){
- var d = new Date(0);
- d.setUTCMilliseconds(timestamp*10);
- dates.push(d.toLocaleString() + "." + d.getMilliseconds())
- }
- var list = document.getElementById("waveformGraphSelect")
- index = list.selectedIndex
- list.innerHTML = ""
- for (var i = 0; i < dates.length; i++){
- var element = document.createElement("option")
- element.setAttribute('timestamp', timestamps[i])
- element.innerText = dates[i]
- list.append(element);
- }
- list.selectedIndex = index
- if(document.querySelector('#waveformGraphAutoupdate').checked){
- list.selectedIndex = list.children.length-1
- if(list.children.length-1 != index) loadGraph()
- }
- else if(index>-1){
- list.selectedIndex = index
- }
- else{
- loadGraph()
- }
- }
- async function loadGraph(){
- option = document.querySelector('#waveformGraphSelect')[document.querySelector('#waveformGraphSelect').selectedIndex]
- timestamp = option.getAttribute('timestamp')
- csv = await eel.loadFile('data/waveforms/'+timestamp+'.csv')()
- document.querySelector('#waveformGraphText').innerText = "Signal: "+csv[8]+" - Gnd: "+csv[9]+" - Signal_std: "+csv[10].toFixed(2)+" - Gnd_std: "+csv[11].toFixed(2)
- var data = [{
- x: range(csv[12]),
- y: csv.slice(13),
- type: 'scatter'
- },{
- x: [csv[2], csv[2]],
- y: [0, Math.max(...csv.slice(13))],
- line: {
- color: 'red'
- },
- type: 'scatter',
- mode: 'lines'
- },{
- x: [csv[3], csv[3]],
- y: [0, Math.max(...csv.slice(13))],
- line: {
- color: 'red'
- },
- type: 'scatter',
- mode: 'lines'
- },{
- x: [csv[4], csv[4]],
- y: [0, Math.max(...csv.slice(13))],
- line: {
- color: 'green'
- },
- type: 'scatter',
- mode: 'lines'
- },{
- x: [csv[5], csv[5]],
- y: [0, Math.max(...csv.slice(13))],
- line: {
- color: 'green'
- },
- type: 'scatter',
- mode: 'lines'
- }];
- var layout = {
- margin: {
- l: 50,
- r: 10,
- b: 50,
- t: 10,
- pad: 4
- },
- xaxis: {
- title: 'Time',
- showgrid: true,
- },
- yaxis: {
- title: 'Input voltage',
- showgrid: true
- },
- showlegend: false
- };
- Plotly.newPlot('waveformGraph', data, layout);
- }
- async function loadLongGraph(){
- csv = await eel.loadLongTerm()()
- xIndex = parseInt(document.querySelector('#longGraphX').children[document.querySelector('#longGraphX').selectedIndex].value)
- xTitle = document.querySelector('#longGraphX').children[document.querySelector('#longGraphX').selectedIndex].innerText
- yIndex = parseInt(document.querySelector('#longGraphY').children[document.querySelector('#longGraphY').selectedIndex].value)
- yTitle = document.querySelector('#longGraphY').children[document.querySelector('#longGraphY').selectedIndex].innerText
- var data = [{
- x: csv.map(l => l[xIndex]),
- y: csv.map(l => l[yIndex]),
- type: 'scatter'
- }]
- if(xIndex==1){
- max = Math.max(...data[0].x)
- data[0].x = data[0].x.map(v => (v-max)/60)
- }
- var layout = {
- margin: {
- l: 50,
- r: 10,
- b: 50,
- t: 10,
- pad: 4
- },
- xaxis: {
- title: xTitle,
- showgrid: true,
- },
- yaxis: {
- title: yTitle,
- showgrid: true
- },
- showlegend: false
- };
- Plotly.newPlot('longGraph', data, layout);
-
- }
- function error(txt){
- Toastify({
- text: "Error: "+txt,
- gravity: 'bottom',
- position: 'left',
- close: true,
- backgroundColor: "#ef4041",
- duration: 3000,}).showToast()
- }
- function warning(txt){
- Toastify({
- text: "Warning: "+txt,
- gravity: 'bottom',
- position: 'left',
- close: true,
- backgroundColor: "#e36d25",
- duration: 3000,}).showToast()
- }
- function message(txt){
- Toastify({
- text: txt,
- gravity: 'bottom',
- position: 'left',
- close: true,
- backgroundColor: "white",
- duration: 3000,}).showToast()
- }
|