471 lines
15 KiB
Python
471 lines
15 KiB
Python
|
|
#!/user/bin/env python3
|
||
|
|
"""
|
||
|
|
SPD3303X-E CONTROL APPLICATION - PSU_CONTROl_TEST_APP.PY
|
||
|
|
- ENTRY POINT OF APPLICATION
|
||
|
|
|
||
|
|
VERSION: 1.0
|
||
|
|
|
||
|
|
AUTHOR: D. RICE 19/11/2025
|
||
|
|
© 2025 ARRIVE
|
||
|
|
"""
|
||
|
|
|
||
|
|
# Imports
|
||
|
|
import numpy as np
|
||
|
|
from PySide6.QtCore import (QTimer)
|
||
|
|
from PySide6.QtWidgets import (QApplication, QMainWindow, QFileDialog)
|
||
|
|
import pyvisa
|
||
|
|
import time
|
||
|
|
import sys
|
||
|
|
import csv
|
||
|
|
|
||
|
|
from ui_mainwindow import Ui_MainWindow
|
||
|
|
|
||
|
|
# Global variables
|
||
|
|
test_state_flag = False
|
||
|
|
chan1_state_flag = False
|
||
|
|
chan2_state_flag = False
|
||
|
|
setup_del = 0.2 # Setup delay in seconds
|
||
|
|
meas_del = 0.05 # Measure delay in seconds
|
||
|
|
file_name = ""
|
||
|
|
test_data = list()
|
||
|
|
test_time_counter = 0
|
||
|
|
test_state = 0
|
||
|
|
test_length = 0
|
||
|
|
test_time_target = 0
|
||
|
|
repeat_state = 0
|
||
|
|
repeat_length = 0
|
||
|
|
|
||
|
|
VISA_ADDRESS = "TCPIP::192.168.45.3::INSTR"
|
||
|
|
|
||
|
|
rm = pyvisa.ResourceManager()
|
||
|
|
devices = rm.list_resources()
|
||
|
|
print (devices)
|
||
|
|
|
||
|
|
SPD = rm.open_resource(
|
||
|
|
VISA_ADDRESS,
|
||
|
|
write_termination='\n',
|
||
|
|
read_termination='\n'
|
||
|
|
)
|
||
|
|
|
||
|
|
# Main window class
|
||
|
|
class MainWindow(QMainWindow):
|
||
|
|
def __init__(self):
|
||
|
|
global SPD
|
||
|
|
global setup_del
|
||
|
|
|
||
|
|
# Initialise main window
|
||
|
|
super(MainWindow, self).__init__()
|
||
|
|
|
||
|
|
# Finish main window initial setup
|
||
|
|
self.ui = Ui_MainWindow()
|
||
|
|
self.ui.setupUi(self)
|
||
|
|
|
||
|
|
# Set up timer prototype
|
||
|
|
self.counter = 0
|
||
|
|
|
||
|
|
# Hold process reference.
|
||
|
|
self.p = None
|
||
|
|
|
||
|
|
# Add file browser button action
|
||
|
|
#self.ui.filebrowseButton.setCheckable(True)
|
||
|
|
#self.ui.filebrowseButton.clicked.connect(self.file_browse_button_press)
|
||
|
|
|
||
|
|
# Add test button action
|
||
|
|
#self.ui.testButton.setCheckable(True)
|
||
|
|
#self.ui.testButton.clicked.connect(self.test_button_press)
|
||
|
|
|
||
|
|
# Add channel button action
|
||
|
|
self.ui.chan1Button.setEnabled(True)
|
||
|
|
self.ui.chan1Button.setCheckable(True)
|
||
|
|
self.ui.chan1Button.clicked.connect(self.chan1_button_press)
|
||
|
|
self.ui.chan2Button.setEnabled(True)
|
||
|
|
self.ui.chan2Button.setCheckable(True)
|
||
|
|
self.ui.chan2Button.clicked.connect(self.chan2_button_press)
|
||
|
|
|
||
|
|
# Enable voltage/current entry
|
||
|
|
self.ui.chan1_v_lab.setEnabled(True)
|
||
|
|
self.ui.chan1_i_lab.setEnabled(True)
|
||
|
|
self.ui.chan2_v_lab.setEnabled(True)
|
||
|
|
self.ui.chan2_i_lab.setEnabled(True)
|
||
|
|
|
||
|
|
# Setup LEDs - show black/gray initially
|
||
|
|
self.ui.chan1_blk.setHidden(False)
|
||
|
|
self.ui.chan1_grn.setHidden(True)
|
||
|
|
self.ui.chan1_red.setHidden(True)
|
||
|
|
self.ui.chan2_blk.setHidden(False)
|
||
|
|
self.ui.chan2_grn.setHidden(True)
|
||
|
|
self.ui.chan2_red.setHidden(True)
|
||
|
|
#self.ui.test_blk.setHidden(False)
|
||
|
|
#self.ui.test_grn.setHidden(True)
|
||
|
|
#self.ui.test_red.setHidden(True)
|
||
|
|
|
||
|
|
# Setup QT timers
|
||
|
|
self.chan1timer = QTimer()
|
||
|
|
self.chan1timer.setInterval(200)
|
||
|
|
self.chan1timer.timeout.connect(self.chan1_timer)
|
||
|
|
self.chan2timer = QTimer()
|
||
|
|
self.chan2timer.setInterval(200)
|
||
|
|
self.chan2timer.timeout.connect(self.chan2_timer)
|
||
|
|
|
||
|
|
#self.testledtimer = QTimer()
|
||
|
|
#self.testledtimer.setInterval(500)
|
||
|
|
#self.testledtimer.timeout.connect(self.test_led_timer)
|
||
|
|
|
||
|
|
#self.testtimer = QTimer()
|
||
|
|
#self.testtimer.setInterval(100)
|
||
|
|
#self.testtimer.timeout.connect(self.test_timer)
|
||
|
|
|
||
|
|
# Configure Power Supplys
|
||
|
|
#SPD.write_termination='\n'
|
||
|
|
#SPD.read_termination='\n'
|
||
|
|
|
||
|
|
SPD.write('CH1:VOLT ' + str(0.0)) # Send power supply source voltage
|
||
|
|
time.sleep(setup_del)
|
||
|
|
SPD.write('CH1:CURR ' + str(1.0)) # Send power supply current limit
|
||
|
|
time.sleep(setup_del)
|
||
|
|
SPD.write('CH2:VOLT ' + str(0.0)) # Send power supply source voltage
|
||
|
|
time.sleep(setup_del)
|
||
|
|
SPD.write('CH2:CURR ' + str(1.0)) # Send power supply current limit
|
||
|
|
time.sleep(setup_del)
|
||
|
|
|
||
|
|
# Disable power supply output source
|
||
|
|
SPD.write('OUTP CH1,OFF') # Enable supply output
|
||
|
|
SPD.write('OUTP CH2,OFF') # Enable supply output
|
||
|
|
|
||
|
|
def file_browse_button_press (self):
|
||
|
|
global file_name
|
||
|
|
|
||
|
|
fname=QFileDialog.getOpenFileName(self, 'Open file', 'C:\\Users\\david.rice\\Documents\\Python\\DRIVER CONSOLE TEST\\TEST FILES', 'CSV UTF-8 (*.csv)')
|
||
|
|
file_name = fname[0]
|
||
|
|
self.ui.tfp_val.setText(fname[0])
|
||
|
|
|
||
|
|
def test_button_press (self):
|
||
|
|
global test_state_flag
|
||
|
|
global SPD
|
||
|
|
global file_name
|
||
|
|
global test_data
|
||
|
|
global test_time_counter
|
||
|
|
global test_state
|
||
|
|
global test_length
|
||
|
|
global test_time_target
|
||
|
|
global repeat_state
|
||
|
|
global repeat_length
|
||
|
|
|
||
|
|
self.ui.testButton.toggle()
|
||
|
|
test_time_target = 0
|
||
|
|
|
||
|
|
if test_state_flag == False:
|
||
|
|
test_state_flag = True
|
||
|
|
|
||
|
|
if file_name != "":
|
||
|
|
self.ui.testButton.setText("STOP TEST")
|
||
|
|
self.testledtimer.start()
|
||
|
|
|
||
|
|
# Enable power supply output source
|
||
|
|
self.ui.chan1Button.setEnabled(False)
|
||
|
|
self.ui.v_lab.setEnabled(False)
|
||
|
|
self.ui.i_lab.setEnabled(False)
|
||
|
|
|
||
|
|
SPD.write('OUTP CH1,ON') # Enable supply output
|
||
|
|
|
||
|
|
# Read test file contents
|
||
|
|
with open(file_name, newline='') as csvfile:
|
||
|
|
test_data_l = list(csv.reader(csvfile))
|
||
|
|
|
||
|
|
test_data = test_data_l[0]
|
||
|
|
|
||
|
|
test_length = len(test_data) - 2
|
||
|
|
|
||
|
|
repeat_state = 0
|
||
|
|
|
||
|
|
repeat_length_str = test_data[1]
|
||
|
|
|
||
|
|
repeat_length = int(repeat_length_str)
|
||
|
|
|
||
|
|
test_time_counter = 0
|
||
|
|
test_state = 1
|
||
|
|
|
||
|
|
self.testtimer.start()
|
||
|
|
|
||
|
|
else:
|
||
|
|
test_state_flag = False
|
||
|
|
self.testtimer.stop()
|
||
|
|
self.ui.testButton.setText("RUN TEST")
|
||
|
|
self.testledtimer.stop()
|
||
|
|
self.ui.test_blk.setHidden(False)
|
||
|
|
self.ui.test_grn.setHidden(True)
|
||
|
|
self.ui.test_red.setHidden(True)
|
||
|
|
self.ui.chan1Button.setEnabled(True)
|
||
|
|
self.ui.v_lab.setEnabled(True)
|
||
|
|
self.ui.i_lab.setEnabled(True)
|
||
|
|
self.ui.it_val.setText("0.00")
|
||
|
|
self.ui.vt_val.setText("0.00")
|
||
|
|
self.ui.vt_val.setText("00.0")
|
||
|
|
|
||
|
|
# Disable power supply output source
|
||
|
|
#SPD.write('OUTP CH1,OFF') # Disable supply output
|
||
|
|
|
||
|
|
def chan1_button_press (self):
|
||
|
|
global chan1_state_flag
|
||
|
|
global setup_del
|
||
|
|
global SPD
|
||
|
|
|
||
|
|
if chan1_state_flag == False:
|
||
|
|
chan1_state_flag = True
|
||
|
|
self.ui.chan1_v_lab.setEnabled(False)
|
||
|
|
self.ui.chan1_i_lab.setEnabled(False)
|
||
|
|
|
||
|
|
voltage = self.ui.chan1_v_val.text()
|
||
|
|
current = self.ui.chan1_i_val.text()
|
||
|
|
|
||
|
|
self.ui.chan1_blk.setHidden(True)
|
||
|
|
self.ui.chan1_grn.setHidden(False)
|
||
|
|
self.ui.chan1_red.setHidden(True)
|
||
|
|
|
||
|
|
SPD.write('CH1:VOLT ' + voltage) #Send power supply source voltage
|
||
|
|
time.sleep(setup_del)
|
||
|
|
SPD.write('CH1:CURR ' + current) #Send power supply current limit
|
||
|
|
time.sleep(setup_del)
|
||
|
|
|
||
|
|
# Enable power supply output source
|
||
|
|
SPD.write('OUTP CH1,ON') # Enable supply output
|
||
|
|
|
||
|
|
# Enable timer to get data
|
||
|
|
self.chan1timer.start()
|
||
|
|
|
||
|
|
else:
|
||
|
|
chan1_state_flag = False
|
||
|
|
self.ui.chan1_v_lab.setEnabled(True)
|
||
|
|
self.ui.chan1_i_lab.setEnabled(True)
|
||
|
|
|
||
|
|
self.ui.chan1_blk.setHidden(False)
|
||
|
|
self.ui.chan1_grn.setHidden(True)
|
||
|
|
self.ui.chan1_red.setHidden(True)
|
||
|
|
|
||
|
|
# Disable power supply output source
|
||
|
|
SPD.write('OUTP CH1,OFF') # Disable supply output
|
||
|
|
|
||
|
|
# Disable timer
|
||
|
|
self.chan1timer.stop()
|
||
|
|
|
||
|
|
self.ui.chan1_mv_val.setText("0.00")
|
||
|
|
self.ui.chan1_mi_val.setText("0.00")
|
||
|
|
self.ui.chan1_mp_val.setText("0.00")
|
||
|
|
|
||
|
|
def chan2_button_press (self):
|
||
|
|
global chan2_state_flag
|
||
|
|
global setup_del
|
||
|
|
global SPD
|
||
|
|
|
||
|
|
if chan2_state_flag == False:
|
||
|
|
chan2_state_flag = True
|
||
|
|
self.ui.chan2_v_lab.setEnabled(False)
|
||
|
|
self.ui.chan2_i_lab.setEnabled(False)
|
||
|
|
|
||
|
|
voltage = self.ui.chan2_v_val.text()
|
||
|
|
current = self.ui.chan2_i_val.text()
|
||
|
|
|
||
|
|
self.ui.chan2_blk.setHidden(True)
|
||
|
|
self.ui.chan2_grn.setHidden(False)
|
||
|
|
self.ui.chan2_red.setHidden(True)
|
||
|
|
|
||
|
|
SPD.write('CH2:VOLT ' + voltage) #Send power supply source voltage
|
||
|
|
time.sleep(setup_del)
|
||
|
|
SPD.write('CH2:CURR ' + current) #Send power supply current limit
|
||
|
|
time.sleep(setup_del)
|
||
|
|
|
||
|
|
# Enable power supply output source
|
||
|
|
SPD.write('OUTP CH2,ON') # Enable supply output
|
||
|
|
|
||
|
|
# Enable timer to get data
|
||
|
|
self.chan2timer.start()
|
||
|
|
|
||
|
|
else:
|
||
|
|
chan2_state_flag = False
|
||
|
|
self.ui.chan2_v_lab.setEnabled(True)
|
||
|
|
self.ui.chan2_i_lab.setEnabled(True)
|
||
|
|
|
||
|
|
self.ui.chan2_blk.setHidden(False)
|
||
|
|
self.ui.chan2_grn.setHidden(True)
|
||
|
|
self.ui.chan2_red.setHidden(True)
|
||
|
|
|
||
|
|
# Disable power supply output source
|
||
|
|
SPD.write('OUTP CH2,OFF') # Disable supply output
|
||
|
|
|
||
|
|
# Disable timer
|
||
|
|
self.chan2timer.stop()
|
||
|
|
|
||
|
|
self.ui.chan2_mv_val.setText("0.00")
|
||
|
|
self.ui.chan2_mi_val.setText("0.00")
|
||
|
|
self.ui.chan2_mp_val.setText("0.00")
|
||
|
|
|
||
|
|
def chan1_timer (self):
|
||
|
|
global SPD
|
||
|
|
global meas_del
|
||
|
|
|
||
|
|
# get voltage/current/power
|
||
|
|
SPD.write("MEAS:VOLT? CH1")
|
||
|
|
time.sleep(meas_del)
|
||
|
|
voltage = SPD.read()
|
||
|
|
SPD.write("MEAS:CURR? CH1")
|
||
|
|
time.sleep(meas_del)
|
||
|
|
current = SPD.read()
|
||
|
|
SPD.write("MEAS:POWE? CH1")
|
||
|
|
time.sleep(meas_del)
|
||
|
|
power = SPD.read()
|
||
|
|
|
||
|
|
self.ui.chan1_mv_val.setText(voltage)
|
||
|
|
self.ui.chan1_mi_val.setText(current)
|
||
|
|
self.ui.chan1_mp_val.setText(power)
|
||
|
|
|
||
|
|
QApplication.processEvents()
|
||
|
|
|
||
|
|
|
||
|
|
def chan2_timer (self):
|
||
|
|
global SPD
|
||
|
|
global meas_del
|
||
|
|
|
||
|
|
# get voltage/current/power
|
||
|
|
SPD.write("MEAS:VOLT? CH2")
|
||
|
|
time.sleep(meas_del)
|
||
|
|
voltage = SPD.read()
|
||
|
|
SPD.write("MEAS:CURR? CH2")
|
||
|
|
time.sleep(meas_del)
|
||
|
|
current = SPD.read()
|
||
|
|
SPD.write("MEAS:POWE? CH2")
|
||
|
|
time.sleep(meas_del)
|
||
|
|
power = SPD.read()
|
||
|
|
|
||
|
|
self.ui.chan2_mv_val.setText(voltage)
|
||
|
|
self.ui.chan2_mi_val.setText(current)
|
||
|
|
self.ui.chan2_mp_val.setText(power)
|
||
|
|
|
||
|
|
QApplication.processEvents()
|
||
|
|
|
||
|
|
def test_led_timer (self):
|
||
|
|
self.counter += 1
|
||
|
|
|
||
|
|
# Toggle light blue/dark blue LED for 'load_cell_zero' test
|
||
|
|
if self.counter == 1:
|
||
|
|
self.ui.test_red.setHidden(False)
|
||
|
|
self.ui.test_blk.setHidden(True)
|
||
|
|
|
||
|
|
else:
|
||
|
|
self.ui.test_blk.setHidden(False)
|
||
|
|
self.ui.test_red.setHidden(True)
|
||
|
|
self.counter = 0
|
||
|
|
|
||
|
|
QApplication.processEvents()
|
||
|
|
|
||
|
|
def test_timer (self):
|
||
|
|
global test_time_counter
|
||
|
|
global test_time_target
|
||
|
|
global test_state
|
||
|
|
global test_data
|
||
|
|
global test_length
|
||
|
|
global test_state_flag
|
||
|
|
global psu_state_flag
|
||
|
|
global repeat_state
|
||
|
|
global repeat_length
|
||
|
|
|
||
|
|
if repeat_state <= repeat_length:
|
||
|
|
if test_state <= test_length:
|
||
|
|
if test_time_counter >= test_time_target:
|
||
|
|
test_state = test_state + 1
|
||
|
|
|
||
|
|
print ("TEST STATE: " + str(test_state) + " | TEST LENGTH:" + str(test_length))
|
||
|
|
print ("REPEAT STATE: " + str(repeat_state) + " | REPEAT LENGTH: " + str(repeat_length))
|
||
|
|
|
||
|
|
if test_state % 2 == 0:
|
||
|
|
if test_state < test_length + 1:
|
||
|
|
voltage_set = test_data[test_state]
|
||
|
|
|
||
|
|
test_time_target = 0
|
||
|
|
|
||
|
|
SPD.write('CH1:VOLT ' + voltage_set) # Send power supply source voltage
|
||
|
|
|
||
|
|
current_t = self.ui.i_val.text()
|
||
|
|
|
||
|
|
self.ui.it_val.setText(current_t)
|
||
|
|
self.ui.vt_val.setText(voltage_set)
|
||
|
|
self.ui.tt_val.setText("00.0")
|
||
|
|
|
||
|
|
print ("VOLTAGE: " + voltage_set + " | CURRENT: " + current_t)
|
||
|
|
|
||
|
|
test_time_counter = 0
|
||
|
|
|
||
|
|
else:
|
||
|
|
time_set = test_data[test_state]
|
||
|
|
ts_f = float(time_set)
|
||
|
|
test_time_target = int(ts_f * 10)
|
||
|
|
|
||
|
|
if ts_f < 10:
|
||
|
|
self.ui.tt_val.setText("0" + time_set + ".0")
|
||
|
|
|
||
|
|
else:
|
||
|
|
self.ui.tt_val.setText(time_set + ".0")
|
||
|
|
|
||
|
|
|
||
|
|
else:
|
||
|
|
test_time_counter = test_time_counter + 1
|
||
|
|
|
||
|
|
time_now = test_time_target - test_time_counter
|
||
|
|
|
||
|
|
t_div = time_now / 10
|
||
|
|
|
||
|
|
t_mod = t_div % 1
|
||
|
|
|
||
|
|
int_t_modmult = int (t_mod * 10)
|
||
|
|
int_t_div = int(t_div)
|
||
|
|
|
||
|
|
if int_t_div < 10:
|
||
|
|
self.ui.tt_val.setText("0" + str(int_t_div) + "." + str(int_t_modmult))
|
||
|
|
|
||
|
|
else:
|
||
|
|
self.ui.tt_val.setText(str(int_t_div) + "." + str(int_t_modmult))
|
||
|
|
|
||
|
|
else:
|
||
|
|
repeat_state = repeat_state + 1
|
||
|
|
test_state = 1
|
||
|
|
test_time_counter = 0
|
||
|
|
|
||
|
|
else:
|
||
|
|
test_state_flag = False
|
||
|
|
self.testtimer.stop()
|
||
|
|
self.ui.testButton.setText("RUN TEST")
|
||
|
|
self.testledtimer.stop()
|
||
|
|
self.ui.test_blk.setHidden(False)
|
||
|
|
self.ui.test_grn.setHidden(True)
|
||
|
|
self.ui.test_red.setHidden(True)
|
||
|
|
self.ui.psuButton.setEnabled(True)
|
||
|
|
psu_state_flag = False
|
||
|
|
self.ui.psuButton.setText("PSU ON")
|
||
|
|
self.ui.v_lab.setEnabled(True)
|
||
|
|
self.ui.i_lab.setEnabled(True)
|
||
|
|
self.ui.it_val.setText("0.00")
|
||
|
|
self.ui.vt_val.setText("0.00")
|
||
|
|
|
||
|
|
# Disable power supply output source
|
||
|
|
#SPD.write('OUTP CH1,OFF') # Disable supply output
|
||
|
|
|
||
|
|
QApplication.processEvents()
|
||
|
|
|
||
|
|
|
||
|
|
# Run main
|
||
|
|
if __name__ == '__main__':
|
||
|
|
# Send debug information
|
||
|
|
print("SPD3303X-E CONTROL/TEST APPLICATION")
|
||
|
|
print("------------------------------------")
|
||
|
|
print("PROGRAM STARTED...")
|
||
|
|
|
||
|
|
# Launch main window
|
||
|
|
app = QApplication(sys.argv)
|
||
|
|
app.setStyle('Fusion')
|
||
|
|
window = MainWindow()
|
||
|
|
window.show()
|
||
|
|
app.exec()
|
||
|
|
|
||
|
|
# Exit app
|
||
|
|
print("EXITING APPLICATION...")
|
||
|
|
|
||
|
|
sys.exit()
|