Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
L
labcode
Manage
Activity
Members
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Model registry
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
CST
labcode
Commits
6550c2a2
Commit
6550c2a2
authored
1 year ago
by
Jan Gruis
Browse files
Options
Downloads
Patches
Plain Diff
added evaluation module which is currently only a copy of tlmlib.py
parent
40afb7c8
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
.gitignore
+2
-0
2 additions, 0 deletions
.gitignore
evaluation.py
+320
-0
320 additions, 0 deletions
evaluation.py
with
322 additions
and
0 deletions
.gitignore
+
2
−
0
View file @
6550c2a2
.idea/
.ipynb_checkpoints/
__pycache__/
jan_tests.ipynb
This diff is collapsed.
Click to expand it.
evaluation.py
0 → 100644
+
320
−
0
View file @
6550c2a2
"""
Contains all evaluation classes and functions.
class LinearRegressionFitting: Represents a Linear Regression Fitting of a 2D x,y plot
"""
import
os
import
pandas
as
pd
import
numpy
as
np
import
altair
as
alt
import
datetime
# Colors
rwthcolors
=
{
'
blau
'
:
'
#00549F
'
,
'
schwarz
'
:
'
#000000
'
,
'
magenta
'
:
'
#E30066
'
,
'
gelb
'
:
'
#FFED00
'
,
'
petrol
'
:
'
#006165
'
,
'
türkis
'
:
'
#0098A1
'
,
'
grün
'
:
'
#57AB27
'
,
'
maigrün
'
:
'
#BDCD00
'
,
'
orange
'
:
'
#F6A800
'
,
'
rot
'
:
'
#CC071E
'
,
'
bordeaux
'
:
'
#A11035
'
,
'
violett
'
:
'
#612158
'
,
'
lila
'
:
'
#7A6FAC
'
,
}
colorlist
=
[
rwthcolors
[
'
blau
'
],
rwthcolors
[
'
türkis
'
],
rwthcolors
[
'
grün
'
],
rwthcolors
[
'
orange
'
],
rwthcolors
[
'
violett
'
],
]
# Class Definitions
class
LinearRegressionFitting
:
"""
Represents a Linear Regression Fitting of a 2D x,y plot
"""
def
__init__
(
self
,
PandaDataFrame
):
"""
Initializes the instance with a PandaDataFrame
Attributes:
x
y
slope
intercept
residuals
diagnostics
model
R2
df
chart
"""
self
.
input
=
PandaDataFrame
self
.
x
=
PandaDataFrame
.
to_numpy
()[:,
0
]
self
.
y
=
PandaDataFrame
.
to_numpy
()[:,
1
]
# https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html
[
self
.
slope
,
self
.
intercept
],
self
.
residuals
,
*
self
.
diagnostics
=
np
.
polyfit
(
self
.
x
,
self
.
y
,
1
,
full
=
True
)
# model = expression of polynom from polyfit, here basicly
# y = model(x) <=> same as writing y = slope * x + intercept
self
.
model
=
np
.
poly1d
([
self
.
slope
,
self
.
intercept
])
# Bestimmtheitsmaß / Coefficient of determination / R²
# 1 - ( residual sum of squares / SUM( (yi - y_mean)² ) )
self
.
R2
=
1
-
(
self
.
residuals
[
0
]
/
np
.
sum
(
pow
(
self
.
y
-
np
.
average
(
self
.
y
),
2
)
)
)
self
.
df
=
pd
.
DataFrame
({
'
x
'
:
self
.
x
,
'
f(x)
'
:
self
.
model
(
self
.
x
)})
self
.
chart
=
alt
.
Chart
(
self
.
df
).
mark_line
().
encode
(
x
=
"
x
"
,
y
=
'
f(x)
'
)
class
RT_Evaluation
(
LinearRegressionFitting
):
def
__init__
(
self
,
PandaDataFrame
,
contactlenght
):
super
().
__init__
(
PandaDataFrame
)
#self.input
#self.x
#self.y
#self.slope
#self.intercept
#self.residuals
#self.diagnostics
#self.model
#self.R2
#self.df
model_df_x
=
np
.
linspace
(
0
,
self
.
x
[
-
1
])
self
.
df
=
pd
.
DataFrame
({
'
x
'
:
model_df_x
,
'
f(x)
'
:
self
.
model
(
model_df_x
)})
#self.chart
self
.
chart
=
alt
.
Chart
(
self
.
df
).
mark_line
().
encode
(
x
=
"
x
"
,
y
=
'
f(x)
'
)
self
.
contactlenght
=
contactlenght
# Kontaktwiderstand Rc [Ohm*mm]
# = RT(d=0)/2 [Ohm] * Contactlenght [µm/1000]
self
.
Rc
=
(
self
.
intercept
/
2
)
*
(
contactlenght
/
1000
)
# Schichtwiderstand [Ohm/sq = Ohm]
# = slope [Ohm/µm] * Contactlenght [µm]
self
.
Rsh
=
self
.
slope
*
contactlenght
# Transferlänge LT [mm] RT(d) = 0
# = slope [Ohm/µm] / RT(d=0) [Ohm] / 1000
#self.LT = self.intercept / self.slope / 1000
# Transferlänge LT [µm] RT(d) = 0
# = slope [Ohm/µm] / RT(d=0) [Ohm]
self
.
LT
=
self
.
intercept
/
self
.
slope
/
2
# LT = sqrt(rhoc/Rsh).
# "Semiconductor Material and Device Characterization Third Edition",
# D. Schroder, p. 140, Eq. 3.21
# Spezifischer Kontaktwiderstand rhoc = LT² * Rsh
# = Ohm cm² | µm²*0.00000001 = cm²
self
.
rhoc
=
self
.
LT
*
self
.
LT
*
self
.
Rsh
*
1E-4
*
1E-4
class
TlmMeasurement
(
object
):
def
__init__
(
self
,
filelist
,
distances
=
(
5
,
10
,
15
,
20
,
50
),
contactlenght
=
50
):
"""
filelist as tuple
distances as tuple ## Abstände der TLM in µm
contactlenght # Kontaktweite der TLM Strukturen in µm
"""
self
.
_creation_date
=
datetime
.
datetime
.
now
()
self
.
filelist
=
filelist
self
.
path
,
self
.
files
=
self
.
importfiles
(
filelist
)
self
.
distances
=
distances
self
.
contactlenght
=
contactlenght
self
.
df
=
self
.
construct_dataframes
(
self
.
filelist
)
#self.df_org = self.df
self
.
R
,
self
.
lin_reg_charts
,
self
.
R_statistics
=
self
.
R_from_lin_reg
()
self
.
RT0
=
pd
.
DataFrame
({
'
d/µm
'
:
self
.
distances
,
'
R_T/Ohm
'
:
self
.
R
})
self
.
eval0
=
RT_Evaluation
(
self
.
RT0
,
self
.
contactlenght
)
self
.
eval1
,
self
.
eval2
=
self
.
find_RT1_RT2
()
self
.
refined
=
False
#self.results = self.results()
def
importfiles
(
self
,
filelist
):
if
not
len
(
filelist
)
==
5
:
raise
Exception
(
"
Files Missing - I need 5 files for TLM or CTLM
"
)
filenames
=
[]
name
=
""
measurement
=
[]
for
i
in
range
(
len
(
filelist
)):
filenames
.
append
(
os
.
path
.
split
(
filelist
[
i
])[
1
])
name
,
end
=
filenames
[
i
].
rsplit
(
sep
=
"
_
"
,
maxsplit
=
1
)
#print(name, "_", end)
if
i
==
0
:
firstname
=
name
elif
not
name
==
firstname
:
print
(
"
Files:
"
,
filenames
)
raise
Exception
(
"
Filenames differ
"
)
measurement
.
append
(
end
.
split
(
sep
=
"
.
"
)[
0
])
#print(measurement)
#print(i, len(files)-1)
if
(
i
==
len
(
filelist
)
-
1
)
and
(
not
measurement
==
[
'
1
'
,
'
2
'
,
'
3
'
,
'
4
'
,
'
5
'
]):
print
(
"
Files:
"
,
filenames
)
raise
Exception
(
"
Not Measurement _1 to _5?
"
)
path
=
os
.
path
.
split
(
filelist
[
0
])[
0
]
return
(
path
,
filenames
)
def
construct_dataframes
(
self
,
filelist
=
None
):
if
filelist
is
None
:
filelist
=
self
.
filelist
df
=
[]
for
i
in
range
(
len
(
filelist
)):
df
.
append
(
pd
.
read_csv
(
filelist
[
i
],
sep
=
"
"
,
skip_blank_lines
=
True
,
header
=
3
,
index_col
=
0
,
usecols
=
[
0
,
1
,
2
,
3
],
names
=
[
"
#
"
,
"
U/V
"
,
"
I/A
"
,
"
R/Ohm
"
]))
return
df
def
construct_ui_charts
(
self
,
PandaDataFrames
=
None
):
if
PandaDataFrames
is
None
:
PandaDataFrames
=
self
.
df
uicharts
=
[]
for
i
in
range
(
len
(
PandaDataFrames
)):
uicharts
.
append
(
alt
.
Chart
(
self
.
df
[
i
]).
mark_point
(
color
=
colorlist
[
i
]).
encode
(
x
=
"
U/V
"
,
y
=
"
I/A
"
).
interactive
()
)
return
uicharts
def
R_from_lin_reg
(
self
,
PandaDataFrames
=
None
):
if
PandaDataFrames
is
None
:
PandaDataFrames
=
self
.
df
lin_reg_results
=
[]
# R
lin_reg_charts
=
[]
statistics_string
=
f
"
Statistics for Fitting of R Values
\n
d / µm | R² | RT / Ohm
"
#print(f"Statistics for Fitting of R Values \n {'d / µm' : >9} | {'R²' : <6} | RT / Ohm ")
for
i
in
range
(
len
(
PandaDataFrames
)):
fit
=
LinearRegressionFitting
(
PandaDataFrames
[
i
])
lin_reg_results
.
append
(
1
/
(
fit
.
slope
)
)
lin_reg_charts
.
append
(
alt
.
Chart
(
fit
.
df
).
mark_line
(
color
=
colorlist
[
i
]).
encode
(
x
=
"
x
"
,
y
=
'
f(x)
'
)
)
#print(f"{self.distances[i] : 10d} | {fit.R2 : >5.4f} | {lin_reg_results[i] : 10.4f}")
statistics_string
+=
"
\n
"
+
f
"
{
self
.
distances
[
i
]
:
10
d
}
|
{
fit
.
R2
:
>
5.4
f
}
|
{
lin_reg_results
[
i
]
:
10.4
f
}
"
#print(statistics_string)
return
lin_reg_results
,
lin_reg_charts
,
statistics_string
def
contruct_lin_reg_fit_charts
(
self
):
return
self
.
lin_reg_charts
def
find_RT1_RT2
(
self
,
R
=
None
):
if
R
is
None
:
R
=
self
.
RT0
# Remove One Measurement
# Find maximal Bestimmtheitsmaß / Coefficient of determination / R²
save_RT1
=
None
max
=
0
for
i
in
range
(
len
(
R
)):
Ri
=
R
.
drop
(
labels
=
i
,
axis
=
0
)
evali
=
RT_Evaluation
(
Ri
,
self
.
contactlenght
)
if
evali
.
R2
>=
max
:
max
=
evali
.
R2
save_RT1
=
evali
# Remove Two Measurements
list_of_rows_to_remove
=
[[
0
,
1
],
[
0
,
2
],
[
0
,
3
],
[
0
,
4
],
[
1
,
2
],
[
1
,
3
],
[
1
,
4
],
[
2
,
3
],
[
2
,
4
],
[
3
,
4
],
]
save_RT2
=
None
max
=
0
for
rows
in
list_of_rows_to_remove
:
Ri
=
R
.
drop
(
labels
=
rows
,
axis
=
0
)
evali
=
RT_Evaluation
(
Ri
,
self
.
contactlenght
)
if
evali
.
R2
>=
max
:
max
=
evali
.
R2
save_RT2
=
evali
return
save_RT1
,
save_RT2
def
refine_evaluated_range
(
self
,
newrange
=
None
):
if
not
type
(
newrange
)
is
tuple
:
raise
Exception
(
"
Wrong format for Newrange! Should be tuple (float, float)
"
)
if
not
len
(
newrange
)
==
2
:
raise
Exception
(
"
Two few or many values in newrange! Should be tuple (float, float)
"
)
minI
,
maxI
=
newrange
refined_df
=
self
.
df
for
i
in
range
(
len
(
refined_df
)):
# First vector where values for I/A are bigger than min and smaller than max = True
# (dataframe.iloc[:,1] > min) & (dataframe.iloc[:,1] < max )
# then this boolean vector is used as indexer for the dame dataframe
# every value with False is sliced
work
=
refined_df
[
i
]
#print(work)
#print((dataframe.iloc[:,1] > minI) & (dataframe.iloc[:,1] < maxI ))
work
=
work
[
(
work
.
iloc
[:,
1
]
>
minI
)
&
(
work
.
iloc
[:,
1
]
<
maxI
)
]
#print(work)
refined_df
[
i
]
=
work
self
.
df
=
refined_df
self
.
R
,
self
.
lin_reg_charts
,
statistics_string
=
self
.
R_from_lin_reg
()
self
.
RT0
=
pd
.
DataFrame
({
'
d/µm
'
:
self
.
distances
,
'
R_T/Ohm
'
:
self
.
R
})
self
.
eval0
=
RT_Evaluation
(
self
.
RT0
,
self
.
contactlenght
)
self
.
eval1
,
self
.
eval2
=
self
.
find_RT1_RT2
()
self
.
refined
=
True
def
results
(
self
,
comment
=
""
):
#print("Path:\n", ctlm.path, "\n", sep = "")
results_string
=
"
Path:
"
+
self
.
path
+
"
\n
"
#print("Files: {}, {}, {}, {}, {} \n".format(*ctlm.files))
results_string
+=
"
Files: {}, {}, {}, {}, {}
\n
"
.
format
(
*
self
.
files
)
#header = "Feld Rsh R² Rc LT rhoc min I max I # removed values"
#header = "Feld Rsh R² Rc LT rhoc # removed values"
results_string
+=
comment
+
"
\n
"
results_string
+=
"
Feld Rsh R² Rc LT rhoc # removed values
\n
"
#units = "- [Ohm/sq] - [Ohm mm] [µm] [Ohm cm²] [A] [A] -"
#units = "- [Ohm/sq] - [Ohm mm] [µm] [Ohm cm²] -"
results_string
+=
"
- [Ohm/sq] - [Ohm mm] [µm] [Ohm cm²] -
\n
"
format_string
=
"
{:<4}{:7.2f} {:8.4f} {:6.2f} {:8.2f} {:8.2e} {}
\n
"
results_string
+=
format_string
.
format
(
self
.
files
[
0
].
rsplit
(
"
_
"
)[
0
],
self
.
eval0
.
Rsh
,
self
.
eval0
.
R2
,
self
.
eval0
.
Rc
,
self
.
eval0
.
LT
,
self
.
eval0
.
rhoc
,
#minI,
#maxI,
None
,
)
results_string
+=
format_string
.
format
(
self
.
files
[
0
].
rsplit
(
"
_
"
)[
0
],
self
.
eval1
.
Rsh
,
self
.
eval1
.
R2
,
self
.
eval1
.
Rc
,
self
.
eval1
.
LT
,
self
.
eval1
.
rhoc
,
#minI,
#maxI,
1
,
)
results_string
+=
format_string
.
format
(
self
.
files
[
0
].
rsplit
(
"
_
"
)[
0
],
self
.
eval2
.
Rsh
,
self
.
eval2
.
R2
,
self
.
eval2
.
Rc
,
self
.
eval2
.
LT
,
self
.
eval2
.
rhoc
,
#minI,
#maxI,
2
,
)
return
results_string
def
construct_rt_charts
(
self
):
rt_charts
=
[]
rt_charts
.
append
(
alt
.
Chart
(
self
.
RT0
).
mark_point
(
color
=
rwthcolors
[
'
blau
'
]).
encode
(
x
=
'
d/µm
'
,
y
=
'
R_T/Ohm
'
).
interactive
()
)
rt_charts
.
append
(
alt
.
Chart
(
self
.
eval0
.
df
).
mark_line
(
color
=
rwthcolors
[
'
bordeaux
'
]).
encode
(
x
=
'
x
'
,
y
=
'
f(x)
'
)
)
rt_charts
.
append
(
alt
.
Chart
(
self
.
eval1
.
df
).
mark_line
(
color
=
rwthcolors
[
'
violett
'
]).
encode
(
x
=
'
x
'
,
y
=
'
f(x)
'
)
)
rt_charts
.
append
(
alt
.
Chart
(
self
.
eval2
.
df
).
mark_line
(
color
=
rwthcolors
[
'
lila
'
]).
encode
(
x
=
'
x
'
,
y
=
'
f(x)
'
)
)
return
rt_charts
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