Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
I
IVL-Messplatz
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
CST
IVL-Messplatz
Commits
e02df711
Commit
e02df711
authored
1 month ago
by
Alexandros Asonitis
Browse files
Options
Downloads
Patches
Plain Diff
First photodiode interface to be tested!
parent
b7755632
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
interfaces/photodiode_ivl.py
+406
-0
406 additions, 0 deletions
interfaces/photodiode_ivl.py
with
406 additions
and
0 deletions
interfaces/photodiode_ivl.py
0 → 100644
+
406
−
0
View file @
e02df711
"""
This is the photodiode 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
from
ivl.measurements
import
ivl_scan_photodiode
except
ModuleNotFoundError
:
sys
.
path
.
append
(
"
.
"
)
sys
.
path
.
append
(
"
..
"
)
import
ivl
from
ivl.instruments
import
Agilent66332A
from
ivl.measurements
import
ivl_scan_photodiode
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
):
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
=
"
save results path
"
,
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
=
"
save results path
"
,
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
(
"
Current Density [$mA/cm^2$]
"
)
self
.
axes
[
2
].
set_ylabel
(
"
Radiance [$W/m^2*sr$]
"
)
self
.
axes
[
3
].
set_xlabel
(
"
Radiance [$W/m^2*sr$]
"
)
self
.
axes
[
3
].
set_ylabel
(
"
EQE [%]
"
)
# set the scales
self
.
axes
[
2
].
set_xscale
(
"
log
"
)
self
.
axes
[
3
].
set_xscale
(
"
log
"
)
self
.
axes
[
2
].
set_yscale
(
"
log
"
)
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
):
"""
Here we set the layout of the app
V_start : First voltage point in [V]
V_stop :
"
Last voltage point in [V]
"
,
V_step : Voltage sweep increament in [V]
for the file we will create a Filedialog
the info can be added
info: Information to add to the header of result file.
points: Points to average for a single measurement.
(Reduce to reduce voltage on time. Reducing below
~100 points does not yield increase measurement speed above ~ 50 ms
per data points.)
offset: offset voltage of amplifier in [V]. If not supplied,offset is measured at the start of the script
delay: Time in [s] to wait between measurement points. (Voltage is
set to 0 V during this time, mimicking a simple pulsed measurement)
address: Address of GPIB and serial interfaces
verbose:
"
Write info about current measurement state
"
True/False
RFA: Feedback resistivity * configuration factor * pinhole area
spectrum: path to reference spectrum for calculation of Radio-photometric quantities
substrate:
"
Active area in cm^2
"
We always display plots
"""
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
.
points
=
QSpinBox
()
self
.
points
.
setRange
(
0
,
4096
)
self
.
points
.
setValue
(
4096
)
self
.
offset
=
QDoubleSpinBox
()
self
.
offset
.
setDecimals
(
4
)
self
.
offset
.
setRange
(
5e-3
,
10e-3
)
self
.
offset
.
setValue
(
7.5e-3
)
self
.
measure_offset
=
QCheckBox
(
"
Measure offset voltage instead of using the above value
"
)
self
.
delay
=
QDoubleSpinBox
()
#only softwrare delay leave it like this
# Minimum 0 Maximum 99.99 and 2 decimals places
self
.
address_serial
=
QSpinBox
()
# well this is also ok for the 0 to 99 just set the default value
self
.
address_serial
.
setValue
(
3
)
self
.
address_gpib
=
QSpinBox
()
self
.
address_gpib
.
setValue
(
1
)
self
.
verbose
=
QCheckBox
(
"
Verbose
"
)
self
.
rfa
=
QDoubleSpinBox
()
# here also set the default value
self
.
rfa
.
setDecimals
(
6
)
self
.
rfa
.
setValue
(
0.827575
)
self
.
spectrum
=
QLineEdit
()
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
(
"
Points to average for a single measurement
"
))
self
.
parameters
.
addWidget
(
self
.
points
)
self
.
parameters
.
addWidget
(
QLabel
(
"
Offset voltage of amplifier in [V]
"
))
self
.
parameters
.
addWidget
(
self
.
offset
)
self
.
parameters
.
addWidget
(
self
.
measure_offset
)
self
.
parameters
.
addWidget
(
QLabel
(
"
Time in [s] to wait between measurement points
"
))
self
.
parameters
.
addWidget
(
self
.
delay
)
self
.
parameters
.
addWidget
(
QLabel
(
"
Serial address
"
))
self
.
parameters
.
addWidget
(
self
.
address_serial
)
self
.
parameters
.
addWidget
(
QLabel
(
"
GPIB address
"
))
self
.
parameters
.
addWidget
(
self
.
address_gpib
)
self
.
parameters
.
addWidget
(
self
.
verbose
)
self
.
parameters
.
addWidget
(
QLabel
(
"
RFA: Feedback resistivity * configuration factor * pinhole area
"
))
self
.
parameters
.
addWidget
(
self
.
rfa
)
self
.
parameters
.
addWidget
(
QLabel
(
"
path to reference spectrum for calculation of Radio-photometric quantities
"
))
self
.
parameters
.
addWidget
(
self
.
spectrum
)
self
.
parameters
.
addWidget
(
QLabel
(
"
Active area in cm^2
"
))
self
.
parameters
.
addWidget
(
self
.
substrate
)
self
.
parameters
.
addWidget
(
self
.
clear_plots
)
self
.
parameters
.
addWidget
(
self
.
load_spectrum
)
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
(
"
Photodiode IVL Measurement
"
)
self
.
widget
.
setLayout
(
self
.
app_grid
)
self
.
setCentralWidget
(
self
.
widget
)
self
.
showMaximized
()
self
.
start_meas
.
clicked
.
connect
(
self
.
start_meas_clicked
)
self
.
load_spectrum
.
clicked
.
connect
(
self
.
load_spectrum_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
)
def
load_spectrum_clicked
(
self
):
self
.
widget
.
setEnabled
(
False
)
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
.
askopenfilename
(
title
=
'
Select spectrum reference file
'
)
root
.
destroy
()
self
.
spectrum
.
setText
(
file
)
self
.
widget
.
setEnabled
(
True
)
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
(
address
=
str
(
self
.
window
.
address_gpib
.
value
()),
timeout
=
30
)
as
agi_source
,
Agilent66332A
(
connection
=
"
serial
"
,
address
=
str
(
self
.
window
.
address_serial
.
value
()),
timeout
=
30
)
as
agi_photo
):
# 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
agi_source
.
device
is
None
or
agi_photo
.
device
is
None
:
if
"
IVL_OFFLINE
"
not
in
os
.
environ
.
keys
():
information_box
(
"
Could not open one of the two necessary sourcemeters!
"
)
self
.
window
.
widget
.
setEnabled
(
True
)
return
agi_source
.
set_measurement_param
(
points
=
self
.
window
.
points
.
value
())
agi_photo
.
set_measurement_param
(
points
=
self
.
window
.
points
.
value
())
agi_source
.
low_current_mode
(
True
)
agi_photo
.
low_current_mode
(
True
)
if
self
.
window
.
measure_offset
.
isChecked
():
dark_voltage
=
np
.
array
([
agi_photo
.
get_voltage
()
for
_
in
range
(
100
)])
offset
=
dark_voltage
.
mean
()
rms
=
np
.
std
(
dark_voltage
)
if
self
.
window
.
verbose
.
isChecked
():
information_box
(
f
"
Ampl. Offset:
{
offset
*
1e3
:
.
3
f
}
mV
\n
"
+
f
"
RMS:
{
rms
*
1e3
:
.
3
}
mV
\n
"
)
self
.
window
.
offset
.
setValue
(
offset
)
# change the value on the interface
scan_data
=
ivl_scan_photodiode
(
self
.
window
.
v_start
.
value
(),
self
.
window
.
v_stop
.
value
(),
self
.
window
.
v_step
.
value
(),
agi_source
,
agi_photo
,
delay
=
self
.
window
.
delay
.
value
(),
verbose
=
self
.
window
.
verbose
.
isChecked
(),
offset
=
self
.
window
.
offset
.
value
(),
substrate
=
self
.
window
.
substrate
.
value
(),
ref_spectrum
=
self
.
window
.
spectrum
.
text
(),
RFA
=
self
.
window
.
rfa
.
value
()
)
voltage
=
scan_data
[
"
voltage_source
"
]
current_dens
=
scan_data
[
"
current_density
"
]
radiance
=
scan_data
[
"
radiance
"
]
eqe
=
scan_data
[
"
eqe
"
]
luminance
=
scan_data
[
"
luminance
"
]
# Plot the results
self
.
window
.
sc
.
axes
[
0
].
plot
(
voltage
,
current_dens
,
label
=
f
"
Measurement
{
self
.
window
.
counter
}
"
)
self
.
window
.
sc
.
axes
[
1
].
plot
(
voltage
,
radiance
,
label
=
f
"
Measurement
{
self
.
window
.
counter
}
"
)
self
.
window
.
sc
.
axes
[
2
].
scatter
(
current_dens
,
radiance
,
label
=
f
"
Measurement
{
self
.
window
.
counter
}
"
)
self
.
window
.
sc
.
axes
[
3
].
scatter
(
radiance
,
eqe
,
label
=
f
"
Measurement
{
self
.
window
.
counter
}
"
)
for
i
in
range
(
4
):
self
.
window
.
sc
.
axes
[
i
].
legend
()
self
.
window
.
sc
.
draw_idle
()
filename
=
"
_ivl.txt
"
header
=
"
Voltage Current_Density Radiance Luminance EQE
"
header
+=
"
Raw_Current Raw_Photovoltage
\n
"
header
+=
"
[V] [mA/cm^2] [W/m^2*sr] [cd/m^2] [%] [A] [V]
\n
"
info
=
str
(
datetime
.
datetime
.
now
().
date
())
data
=
(
voltage
,
current_dens
,
radiance
,
luminance
,
eqe
,
scan_data
[
"
current
"
],
scan_data
[
"
photo_voltage
"
]
)
data
=
np
.
array
(
data
).
T
if
self
.
window
.
info
.
toPlainText
()
!=
""
:
info
+=
"
:
"
+
self
.
window
.
info
.
toPlainText
()
header
+=
info
data_path
=
create_file
(
filename
)
np
.
savetxt
(
data_path
,
data
,
header
=
header
,
fmt
=
'
%.3e
'
)
self
.
window
.
widget
.
setEnabled
(
True
)
app
=
QApplication
(
sys
.
argv
)
w
=
MainWindow
()
app
.
exec
()
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment