Skip to content

Commit 045b10a

Browse files
authored
Merge pull request #110 from upb-lea/develop
Update switching loss measurements
2 parents 0e8668e + 99b301a commit 045b10a

4 files changed

Lines changed: 166 additions & 6 deletions

File tree

requirements.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ PyQt5
1212
PyQtWebEngine
1313
mongomock
1414
requests
15-
deepdiff
15+
deepdiff
16+
pandas
17+
scikit-learn

transistordatabase/checker_functions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ def csv2array(csv_filename: str, first_xy_to_00: bool = False, second_y_to_0: bo
105105
if ';' in readfile:
106106
# csv-file was generated by a german language system
107107
array = np.genfromtxt(csv_filename, delimiter=";",
108-
converters={0: lambda s: float(s.decode("UTF-8").replace(",", ".")),
109-
1: lambda s: float(s.decode("UTF-8").replace(",", "."))})
108+
converters={0: lambda s: float(s.replace(",", ".")),
109+
1: lambda s: float(s.replace(",", "."))})
110110
else:
111111
# csv-file was generated by a english language system
112112
array = np.genfromtxt(csv_filename, delimiter=",")

transistordatabase/data_classes.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
"""Contains important data classes like SOA, SwitchEnergyData, GateChargeCurve, ..."""
2+
import dataclasses
3+
24
# Python standard libraries
35
from matplotlib import pyplot as plt
46
from datetime import datetime
@@ -1055,3 +1057,23 @@ def dpt_calculate_energies(self, integration_interval: str, dataset_type: str, e
10551057

10561058
dpt_dict = {'e_off_meas': e_off_meas, 'e_on_meas': e_on_meas}
10571059
return dpt_dict
1060+
1061+
@dataclasses.dataclass
1062+
class SwitchingLossFitFactors:
1063+
"""Fit parameters for the switching losses."""
1064+
1065+
a_current: np.float64
1066+
b_current: np.float64
1067+
c_current: np.float64
1068+
voltage_factor: np.float64
1069+
voltage_exponent: np.float64
1070+
ct_0: np.float64
1071+
ct_1: np.float64
1072+
ct_2: np.float64
1073+
# min / max values to avoid extrapolation
1074+
temperature_min: np.float64
1075+
temperature_max: np.float64
1076+
voltage_min: np.float64
1077+
voltage_max: np.float64
1078+
current_min: np.float64
1079+
current_max: np.float64

transistordatabase/transistor.py

Lines changed: 139 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
from jinja2 import Environment, FileSystemLoader
2424
from bson.objectid import ObjectId
2525
from bson import json_util
26+
import pandas as pd
27+
from sklearn.model_selection import train_test_split
2628

2729
# Local libraries
2830
from transistordatabase.constants import *
@@ -404,6 +406,16 @@ def update_wp(self, t_j: float, v_g: float, i_channel: float, switch_or_diode: s
404406
# working point, calculate q_oss
405407
self.wp.graph_v_qoss = self.calc_v_qoss()
406408

409+
# check if lists are not empty
410+
if self.switch.e_on_meas:
411+
self.wp.e_on_meas_fit = self.calc_e_on_off_switch_loss_fit_parameters("on")
412+
else:
413+
self.wp.e_on_meas_fit = None
414+
if self.switch.e_off_meas:
415+
self.wp.e_off_meas_fit = self.calc_e_on_off_switch_loss_fit_parameters("off")
416+
else:
417+
self.wp.e_off_meas_fit = None
418+
407419
def init_loss_matrices(self):
408420
"""Experimental."""
409421
self.init_switch_channel_matrix()
@@ -2146,14 +2158,16 @@ class WP:
21462158
diode_r_channel: float | None
21472159
switch_channel: float | None
21482160
diode_channel: float | None
2149-
e_on: npt.NDArray[np.float64] | None #: Units: Row 1: A; Row 2: J
2150-
e_off: npt.NDArray[np.float64] | None #: Units: Row 1: A; Row 2: J
2151-
e_rr: npt.NDArray[np.float64] | None #: Units: Row 1: A; Row 2: J
2161+
e_on: SwitchEnergyData | None
2162+
e_off: SwitchEnergyData | None
2163+
e_rr: SwitchEnergyData | None
21522164
v_switching_ref: float | None #: Unit: V
21532165
graph_v_coss: npt.NDArray[np.float64] | None #: Units: Row 1: V; Row 2: F
21542166
graph_v_eoss: npt.NDArray[np.float64] | None #: Units: Row 1: V; Row 2: J
21552167
graph_v_qoss: npt.NDArray[np.float64] | None #: Units: Row 1: V; Row 2: C
21562168
parallel_transistors: float | None #: Unit: Number
2169+
e_on_meas_fit: None
2170+
e_off_meas_fit: None
21572171

21582172
def __init__(self):
21592173
self.switch_v_channel = None
@@ -2652,6 +2666,128 @@ def compare_measurement_datasheet(self):
26522666
plt.grid()
26532667
plt.show()
26542668

2669+
@staticmethod
2670+
def fit_function(input_params: tuple, a_current: np.float64, b_current: np.float64, c_current: np.float64, voltage_factor: np.float64,
2671+
voltage_exponent: np.float64, ct_0: np.float64, ct_1: np.float64, ct_2: np.float64):
2672+
"""
2673+
Fit the switching loss curves.
2674+
2675+
:param input_params: (current, voltage, temperature) as tuple
2676+
:type input_params: tuple
2677+
:param a_current: constant offset factor to fit
2678+
:type a_current: np.float64
2679+
:param b_current: linear factor to fit
2680+
:type b_current: np.float64
2681+
:param c_current: quadratic factor to fit
2682+
:type c_current: np.float64
2683+
:param voltage_factor: linear voltage factor to fit
2684+
:type voltage_factor: np.float64
2685+
:param voltage_exponent: voltage exponent factor to fit
2686+
:type voltage_exponent: np.float64
2687+
:param ct_0: constant temperature factor
2688+
:type ct_0: np.float64
2689+
:param ct_1: linear temperature factor
2690+
:type ct_1: np.float64
2691+
:param ct_2: quadratic temperature factor
2692+
:type ct_2: np.float64
2693+
"""
2694+
current, voltage, t_j = input_params
2695+
2696+
loss_current = a_current + b_current * current + c_current * current ** 2
2697+
2698+
loss_voltage_current = loss_current * ((voltage * voltage_factor) ** voltage_exponent)
2699+
2700+
loss_voltage_current_temperature = loss_voltage_current * (ct_0 + t_j * (ct_1 + ct_2 ** 2))
2701+
2702+
return loss_voltage_current_temperature
2703+
2704+
def calc_e_on_off_switch_loss_fit_parameters(self, on_off_key: str):
2705+
"""
2706+
Fit the parameters for the turn-on and the turn-off losses.
2707+
2708+
:param on_off_key: "on" or "off"
2709+
:type on_off_key: str
2710+
"""
2711+
df = pd.DataFrame()
2712+
2713+
if on_off_key == "on":
2714+
for lossfile in self.switch.e_on_meas:
2715+
voltage = np.full_like(lossfile.graph_i_e[0], lossfile.v_supply)
2716+
temperature = np.full_like(lossfile.graph_i_e[0], lossfile.t_j)
2717+
df_local = pd.DataFrame({"current": lossfile.graph_i_e[0], "energy": lossfile.graph_i_e[1], "voltage": voltage, "temperature": temperature})
2718+
df = pd.concat([df, df_local], axis=0)
2719+
elif on_off_key == "off":
2720+
for lossfile in self.switch.e_off_meas:
2721+
voltage = np.full_like(lossfile.graph_i_e[0], lossfile.v_supply)
2722+
temperature = np.full_like(lossfile.graph_i_e[0], lossfile.t_j)
2723+
df_local = pd.DataFrame({"current": lossfile.graph_i_e[0], "energy": lossfile.graph_i_e[1], "voltage": voltage, "temperature": temperature})
2724+
df = pd.concat([df, df_local], axis=0)
2725+
else:
2726+
raise ValueError("on_off_key must be 'on' or 'off'.")
2727+
2728+
df_to_split = df.copy().drop(columns=["energy"])
2729+
2730+
X_train, X_test, y_train, y_test = train_test_split(
2731+
df_to_split, df["energy"], test_size=0.3, random_state=42)
2732+
popt, pcov = curve_fit(self.fit_function, (X_train["current"], X_train["voltage"], X_train["temperature"]), y_train, maxfev=int(1e6))
2733+
2734+
a_current, b_current, c_current, voltage_factor, voltage_exponent, ct_0, ct_1, ct_2 = popt
2735+
2736+
fitted_switching_factors = SwitchingLossFitFactors(
2737+
a_current=a_current,
2738+
b_current=b_current,
2739+
c_current=c_current,
2740+
voltage_factor=voltage_factor,
2741+
voltage_exponent=voltage_exponent,
2742+
ct_0=ct_0,
2743+
ct_1=ct_1,
2744+
ct_2=ct_2,
2745+
temperature_min=df["temperature"].min(),
2746+
temperature_max=df["temperature"].max(),
2747+
voltage_min=df["voltage"].min(),
2748+
voltage_max=df["voltage"].max(),
2749+
current_min=df["current"].min(),
2750+
current_max=df["current"].max()
2751+
)
2752+
2753+
return fitted_switching_factors
2754+
2755+
def generate_energy_loss_curve_from_fit_factors(self, on_off_key: str, voltage: np.float64, temperature: np.float64):
2756+
"""
2757+
Generate the turn-on/off loss over current from the fit factors.
2758+
2759+
:param on_off_key: "on" or "off"
2760+
:type on_off_key: str
2761+
:param voltage: Voltage in V
2762+
:type voltage: np.float64
2763+
:param temperature: Temperature in °C
2764+
:type temperature: np.float64
2765+
"""
2766+
if on_off_key == "on":
2767+
current_vec = np.linspace(0, self.wp.e_on_meas_fit.current_max)
2768+
energy_vec = self.fit_function(
2769+
(current_vec, voltage, temperature), self.wp.e_on_meas_fit.a_current, self.wp.e_on_meas_fit.b_current,
2770+
self.wp.e_on_meas_fit.c_current, self.wp.e_on_meas_fit.voltage_factor, self.wp.e_on_meas_fit.voltage_exponent, self.wp.e_on_meas_fit.ct_0,
2771+
self.wp.e_on_meas_fit.ct_1, self.wp.e_on_meas_fit.ct_2)
2772+
elif on_off_key == "off":
2773+
current_vec = np.linspace(0, self.wp.e_off_meas_fit.current_max)
2774+
energy_vec = self.fit_function(
2775+
(current_vec, voltage, temperature), self.wp.e_off_meas_fit.a_current, self.wp.e_off_meas_fit.b_current,
2776+
self.wp.e_off_meas_fit.c_current, self.wp.e_off_meas_fit.voltage_factor, self.wp.e_off_meas_fit.voltage_exponent, self.wp.e_off_meas_fit.ct_0,
2777+
self.wp.e_off_meas_fit.ct_1, self.wp.e_off_meas_fit.ct_2)
2778+
else:
2779+
raise ValueError("on_off_key must be 'on' or 'off'.")
2780+
2781+
# correct data with the energy in c_oss
2782+
energy_in_capacitance_at_dpt_voltage = np.interp(voltage, self.graph_v_eoss[0], self.graph_v_ecoss[1])
2783+
2784+
if on_off_key == "on":
2785+
energy_vec_corrected = energy_vec + energy_in_capacitance_at_dpt_voltage
2786+
elif on_off_key == "off":
2787+
energy_vec_corrected = energy_vec - energy_in_capacitance_at_dpt_voltage
2788+
2789+
return current_vec, energy_vec, energy_vec_corrected
2790+
26552791

26562792
def attach_units(trans: dict, devices: dict):
26572793
"""

0 commit comments

Comments
 (0)