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