From 1a910ac76d82c82779dc3a10090ccb98b4e5e4d3 Mon Sep 17 00:00:00 2001
From: unknown <asoalexandros@gmail.com>
Date: Wed, 4 Jun 2025 15:22:33 +0200
Subject: [PATCH] Second measurement to be tested!

---
 interfaces/spectrometer_ivl.py | 324 +++++++++++++++++++++++++++++++++
 1 file changed, 324 insertions(+)
 create mode 100644 interfaces/spectrometer_ivl.py

diff --git a/interfaces/spectrometer_ivl.py b/interfaces/spectrometer_ivl.py
new file mode 100644
index 0000000..79de81b
--- /dev/null
+++ b/interfaces/spectrometer_ivl.py
@@ -0,0 +1,324 @@
+""" 
+This is the spectrometer measurement. Now the parser arguments are widgets
+"""
+
+import sys 
+import os
+import time
+import datetime
+import traceback
+
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+try:
+    import ivl
+    from ivl.instruments import Agilent66332A, RedTide650
+    from ivl.measurements import ivl_scan_spectrometer
+except:
+    sys.path.append(".")
+    sys.path.append("..")
+    import ivl
+    from ivl.instruments import Agilent66332A, RedTide650
+    from ivl.measurements import ivl_scan_spectrometer
+
+from PyQt6.QtWidgets import *
+from PyQt6.QtGui import *
+from PyQt6.QtCore import *
+
+from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg,NavigationToolbar2QT as NavigationToolbar
+from matplotlib.figure import Figure
+
+import tkinter as tk
+from tkinter import filedialog
+import tkinter.messagebox
+
+
+def create_file(filename,title):
+    root = tk.Tk()
+    root.withdraw()
+    root.lift() #show window above all other applications
+
+    root.attributes("-topmost", True)#window stays above all other applications
+
+    file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = title,initialfile =filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".txt") == False:
+        #open again filedialog with error message box
+        tk.messagebox.showerror(message='invalid filename!')
+        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = title,initialfile =filename)
+    root.destroy()
+    return file
+
+def information_box(information):
+    #open dialog and hide the main window
+    root = tk.Tk()
+    root.withdraw()
+    root.lift() #show window above all other applications
+
+    root.attributes("-topmost", True)#window stays above all other applications
+
+    #display meaagebox
+    tkinter.messagebox.showinfo(message=information)
+    root.destroy()
+
+
+class MplCanvas(FigureCanvasQTAgg):
+    def __init__(self):
+        fig = Figure(figsize=(15,9),dpi=100)
+        self.axes = fig.subplots(nrows=2,ncols=2)
+        self.axes = self.axes.flatten()
+
+        self.axes[0].set_xlabel("Voltage [$V$]")
+        self.axes[0].set_ylabel("Current Density [$mA/cm^2$]")
+
+        self.axes[1].set_xlabel("Voltage [$V$]")
+        self.axes[1].set_ylabel("Radiance [$W/m^2*sr$]")
+
+        self.axes[2].set_xlabel("Voltage [$V$]")
+        self.axes[2].set_ylabel("EQE [%]")
+
+        self.axes[3].set_xlabel("Wavelength [$nm$]")
+        self.axes[3].set_ylabel("Spectral Radiance [$W/m^2*sr*nm$]")
+
+        # set the scales
+        self.axes[0].set_yscale("log")
+        self.axes[1].set_yscale("log")
+        
+
+        super().__init__(fig)
+    
+    def clear_axes(self):
+        for ax in self.axes:
+            # remove line plots
+            for line in ax.get_lines():
+                line.remove()
+
+            #remove scatter plots
+            for scatter in ax.collections:
+                scatter.remove()
+
+            ax.set_prop_cycle(None) # Reset colors
+
+
+# define the mainwindow
+
+class MainWindow(QMainWindow):
+    def __init__(self):
+        super().__init__()
+        self.setupUI()
+    
+    def setupUI(self):
+
+        self.widget = QWidget() # Abstract main widget
+        self.app_grid = QGridLayout()
+
+        self.parameters = QVBoxLayout()
+        self.start_meas = QPushButton(text="Start Measurement")
+        self.load_spectrum = QPushButton(text = "Load spectrum reference file")
+
+        # I will search for the acceptable range of values later
+        self.v_start = QDoubleSpinBox()
+        self.v_start.setDecimals(3)
+        self.v_start.setRange(-20.475,20.475)
+        self.v_start.setValue(-8)
+        
+        self.v_stop = QDoubleSpinBox()
+        self.v_stop.setDecimals(3)
+        self.v_stop.setRange(-20.475,20.475)
+        self.v_stop.setValue(2)
+
+        self.v_step = QDoubleSpinBox()
+        self.v_step.setDecimals(3)
+        self.v_step.setRange(-2*20.475,2*20.475)
+        self.v_step.setValue(0.5)
+
+        self.info = QPlainTextEdit()
+        self.info.setFixedSize(500,150)
+
+        # integration time instead of points
+        self.int_time = QDoubleSpinBox()
+        self.int_time.setDecimals(6) # microseconds
+        self.int_time.setRange(10e-6,60)
+        self.int_time.setValue(0.5)
+
+
+
+        self.delay = QDoubleSpinBox() #only software delay leave it like this
+        # Minimum 0 Maximum 99.99 and 2 decimals places
+
+    
+        self.verbose = QCheckBox("Verbose")
+        
+        self.spectrum = QComboBox()
+        self.spectrum.addItems(["NONE","ALL","MAX"])
+
+
+        self.substrate = QDoubleSpinBox()
+        self.substrate.setRange(0,1)
+        self.substrate.setValue(0.11)
+        
+        self.clear_plots = QCheckBox("Clear Plots Before Measurement")
+
+
+        self.parameters.addWidget(QLabel("First voltage point in [V]"))
+        self.parameters.addWidget(self.v_start)
+        self.parameters.addWidget(QLabel("Last voltage point in [V]"))
+        self.parameters.addWidget(self.v_stop)
+        self.parameters.addWidget(QLabel("Voltage sweep increament in [V]"))
+        self.parameters.addWidget(self.v_step)
+        
+        self.parameters.addWidget(QLabel("Information to add to the header of result file"))
+        self.parameters.addWidget(self.info)
+        self.parameters.addWidget(QLabel("Initial integration time for spectrometer (automatically increased if saturation is reached"))
+        self.parameters.addWidget(self.int_time)
+        self.parameters.addWidget(QLabel("Time in [s] to wait between measurement points"))
+        self.parameters.addWidget(self.delay)
+        
+        self.parameters.addWidget(QLabel("Active area in cm^2"))
+        self.parameters.addWidget(self.substrate)
+
+        self.parameters.addWidget(QLabel("Save radiance spectrum\nMAX: Save single spectrum at maximum irradiance\nALL: Safe every spectrum\nNONE: Dont save any spectrum."))
+        self.parameters.addWidget(self.spectrum)
+
+        self.parameters.addWidget(self.clear_plots)
+        self.parameters.addWidget(self.start_meas)
+
+
+        self.parameters_widget = QWidget()
+        self.parameters_widget.setLayout(self.parameters) # an abstract widget to hold the QVBoxLayout
+
+        self.app_grid.addWidget(self.parameters_widget,0,0)
+        # add the canvas
+        # abstract widget for figure
+        self.figure_widget = QWidget()
+
+        self.sc = MplCanvas()
+        self.figure_toolbar = NavigationToolbar(self.sc, self)
+        self.figure_widget_layout = QVBoxLayout()
+        self.figure_widget_layout.addWidget(self.figure_toolbar)
+        self.figure_widget_layout.addWidget(self.sc)
+
+        self.figure_widget.setLayout(self.figure_widget_layout)
+        
+        self.app_grid.addWidget(self.figure_widget,0,1)
+
+        self.setWindowTitle("Spectrometer IVL Measurement")
+        self.widget.setLayout(self.app_grid)
+        self.setCentralWidget(self.widget)
+        self.showMaximized()
+
+        self.start_meas.clicked.connect(self.start_meas_clicked)
+
+        #initialize a counter to keep track of how many measurements are done
+        self.counter = 1
+
+        # use of threads
+        self.threadpool = QThreadPool()
+    
+    def start_meas_clicked(self):
+        self.worker = Worker(self)
+        self.threadpool.start(self.worker)
+    
+
+class Worker(QRunnable):
+    def __init__(self,window:MainWindow):
+        self.window = window # Keep a referernce to the main window
+        super().__init__()
+    
+    @pyqtSlot()
+    def run(self):
+        self.window.widget.setEnabled(False)
+        
+        with(
+        Agilent66332A(timeout=30) as sourcemeter, 
+        RedTide650() as spectrometer):
+            
+            # clear the plots
+            if self.window.clear_plots.isChecked():
+                self.window.sc.clear_axes()
+                self.window.counter = 1
+            else:
+                self.window.counter =+ 1 #increase counter
+            
+
+            if sourcemeter.device is None or spectrometer.device is None:
+                information_box("Could not open one of the two necessary sourcemeters!")
+                self.window.widget.setEnabled(True)
+                return
+            
+                
+            data,spectra = ivl_scan_spectrometer(
+                self.window.v_start.value(),self.window.v_stop.value(),self.window.v_step.value(),
+                sourcemeter,spectrometer,
+                int_time=self.window.int_time.value(),
+                delay=self.window.delay.value(), 
+                substrate=self.window.substrate.value(),
+                save_spectrum=self.window.spectrum.currentText(),
+                verbose = self.window.verbose.isChecked(),
+            )
+
+            # Plot the results
+            self.window.sc.axes[0].plot(data["voltage"], data["current_density"],label = f"Measurement {self.window.counter}")
+            self.window.sc.axes[1].plot(data["voltage"], data["radiance"],label = f"Measurement {self.window.counter}")
+            self.window.sc.axes[2].plot(data["voltage"],data["eqe"],label = f"Measurement {self.window.counter}")
+            
+            
+            if self.window.spectrum.currentText() == "MAX":
+                self.window.sc.axes[3].plot(spectra[0],spectra[1],label = f"Measurement {self.window.counter}")
+            
+            elif self.window.spectrum.currentText() == "ALL":
+                for index,s in enumerate(spectra[1:]):
+                    self.window.sc.axes[3].plot(spectra[0],s,label = f"Measurement {self.window.counter}, Spectrum {index}")
+
+            for i in range(4):
+                try:    
+                    self.window.sc.axes[i].legend()
+                except:
+                    pass
+            
+            self.window.sc.draw_idle()
+
+            name = "_ivl.txt"
+            name_spec = "_spec.txt"
+            
+
+            header = "Voltage Current_Density Radiance Luminance EQE \n"
+            header += "[V] [mA/cm^2] [W/m^2*sr] [cd/m^2] [%]\n"
+
+            info = str(datetime.datetime.now().date())
+        
+            data = (data["voltage"], data["current_density"],
+                data["radiance"], data["eqe"], data["luminance"])
+            data = np.array(data).T
+
+
+            if self.window.info.toPlainText() != "":
+                info += ": "+ self.window.info.toPlainText()
+
+            header += info
+
+            data_path = create_file(name,title="Save results file")
+            np.savetxt(data_path, data, header = header, fmt='%.3e')
+
+            if self.window.spectrum.currentText()=="NONE":
+                header = "Wavelengths Spectral_Radiance\n"
+                header +=    "[nm] [W/m^2*sr*nm]\n"
+                header += info
+
+                spectrum_path = create_file(name_spec,"Save spectrum file")
+                np.savetxt(spectrum_path,spectra.T,header=header,fmt='%.3e')
+
+
+
+            self.window.widget.setEnabled(True)
+    
+app= QApplication(sys.argv)
+w= MainWindow()
+app.exec()
+
+
+
+
-- 
GitLab