Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gui improvement #112

Merged
merged 7 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 68 additions & 31 deletions femmt/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,13 @@ def fft(period_vector_t_i: npt.ArrayLike, sample_factor: int = 1000, plot: str =
def plot_fourier_coefficients(frequency_list, amplitude_list, phi_rad_list, sample_factor: int = 1000,
figure_directory: str = None):
"""Plot fourier coefficients in a visual figure."""
time_period = 1 / min(frequency_list)
# dc and ac handling
nonzero_frequencies = [f for f in frequency_list if f != 0]
if nonzero_frequencies:
time_period = 1 / min(nonzero_frequencies)
else:
time_period = 1
# time_period = 1 / min(frequency_list)

t_interp = np.linspace(0, time_period, sample_factor)
reconstructed_signal = 0
Expand Down Expand Up @@ -830,6 +836,7 @@ def plot_fourier_coefficients(frequency_list, amplitude_list, phi_rad_list, samp
plt.tight_layout()
if figure_directory is not None:
plt.savefig(figure_directory, bbox_inches="tight")
plt.close('all') # close the figures to remove the warning when you run many figures

# plt.show()

Expand Down Expand Up @@ -1064,43 +1071,73 @@ def visualize_simulation_results(simulation_result_file_path: str, store_figure_
"""Visualize the simulation results by a figure."""
with open(simulation_result_file_path, "r") as fd:
loaded_results_dict = json.loads(fd.read())
# core eddy and hysteresis losses
loss_core_eddy_current = loaded_results_dict["total_losses"]["eddy_core"]
loss_core_hysteresis = loaded_results_dict["total_losses"]["hyst_core_fundamental_freq"]
# Inductances and winding losses
windings_inductance = []
windings_loss = []

# Initialize accumulators for cumulative losses and inductances
cumulative_core_hysteresis = 0
cumulative_core_eddy = 0
cumulative_losses = []
cumulative_inductances = []
windings_labels = []
# Dynamically for 3 windings
for i in range(1, 3):
winding_key = f"winding{i}"
if winding_key in loaded_results_dict["single_sweeps"][0]:
windings_inductance.append(loaded_results_dict["single_sweeps"][0][winding_key]["flux_over_current"][0])
windings_loss.append(loaded_results_dict["total_losses"][winding_key]["total"])
windings_labels.append(f"Winding {i}")

# Plotting results
fig, ax = plt.subplots()
bar_width = 0.35

# Plot core losses
ax.bar(0, loss_core_hysteresis, width=bar_width, label='Core Hysteresis Loss')
ax.bar(0, loss_core_eddy_current, bottom=loss_core_hysteresis, width=bar_width, label='Core Eddy Current Loss')
for index, sweep in enumerate(loaded_results_dict["single_sweeps"]):
freq = sweep['f']
loss_core_eddy_current = sweep.get("core_eddy_losses", 0)
loss_core_hysteresis = sweep.get("core_hyst_losses", 0)

# Accumulate core losses
cumulative_core_hysteresis += loss_core_hysteresis
cumulative_core_eddy += loss_core_eddy_current

# Plotting for each frequency
fig, ax = plt.subplots()
ax.bar(0, loss_core_hysteresis, width=0.35, label='Core Hysteresis Loss')
ax.bar(0, loss_core_eddy_current, bottom=loss_core_hysteresis, width=0.35, label='Core Eddy Current Loss')

for i in range(1, 4):
winding_key = f"winding{i}"
if winding_key in sweep:
inductance = sweep[winding_key].get("flux_over_current", [0])[0]
loss = sweep[winding_key].get("winding_losses", 0)

if len(cumulative_losses) < i:
cumulative_losses.append(loss)
cumulative_inductances.append(inductance)
windings_labels.append(f"Winding {i}")
else:
cumulative_losses[i - 1] += loss
cumulative_inductances[i - 1] += inductance

# Plot for current frequency
ax.bar(i, loss, width=0.35, label=f'{windings_labels[i - 1]} Loss at {freq} Hz')

ax.set_ylabel('Losses in W')
ax.set_title(f'Loss Distribution at {freq} Hz')
ax.legend()
plt.grid(True)

# Save plot for the current frequency
base_path, ext = os.path.splitext(store_figure_file_path)
filename = f"{base_path}_{index}{ext}"
plt.savefig(filename, bbox_inches="tight")
plt.close(fig)

# Plot cumulative results for core and windings
fig, ax = plt.subplots()
ax.bar(0, cumulative_core_hysteresis, width=0.35, label='Cumulative Core Hysteresis Loss')
ax.bar(0, cumulative_core_eddy, bottom=cumulative_core_hysteresis, width=0.35, label='Cumulative Core Eddy Current Loss')

# Plot winding inductances and losses
for index, (inductance, loss) in enumerate(zip(windings_inductance, windings_loss), start=1):
ax.bar(index, loss, width=bar_width, label=f'{windings_labels[index - 1]} Loss')
print(f"{windings_labels[index - 1]} Inductance: {inductance} H")
print(f"{windings_labels[index - 1]} Loss: {loss} W")
for index, loss in enumerate(cumulative_losses):
ax.bar(index + 1, loss, width=0.35, label=f'{windings_labels[index]} Cumulative Loss')

ax.set_ylabel('Losses in W')
ax.set_title('Loss Distribution in Magnetic Components')
ax.set_xticks(list(range(len(windings_labels) + 1)))
ax.set_ylabel('total Losses in W')
ax.set_title('Loss Distribution in Magnetic Components for all frequencies')
ax.set_xticks(range(len(windings_labels) + 1))
ax.set_xticklabels(['Core'] + windings_labels)
ax.legend()

plt.grid(True)
plt.savefig(store_figure_file_path, bbox_inches="tight")
base_path, ext = os.path.splitext(store_figure_file_path)
cumulative_filename = f"{base_path}_total_freq{ext}"
plt.savefig(cumulative_filename, bbox_inches="tight")

if show_plot:
plt.show()
Expand Down
12 changes: 11 additions & 1 deletion femmt/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,9 +562,19 @@ def add_air_gap(self, leg_position: AirGapLegPosition, height: float, position_v
elif self.method == AirGapMethod.Percent:
if position_value > 100 or position_value < 0:
raise Exception("AirGap position values for the percent method need to be between 0 and 100.")
# Calculate the maximum and minimum position in percent considering the winding window height and air gap length
max_position = 100 - (height / self.core.window_h) * 51
min_position = (height / self.core.window_h) * 51

# Adjust the position value if it exceeds the bounds of 0 to 100 percent
if position_value > max_position:
position_value = max_position
elif position_value < min_position:
position_value = min_position

position = position_value / 100 * self.core.window_h - self.core.window_h / 2

# When the position is above the winding window it needs to be adjusted
# # When the position is above the winding window it needs to be adjusted
if position + height / 2 > self.core.window_h / 2:
position -= (position + height / 2) - self.core.window_h / 2
elif position - height / 2 < -self.core.window_h / 2:
Expand Down
90 changes: 49 additions & 41 deletions gui/femmt_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -2753,7 +2753,16 @@ def md_get_frequency_lists(self) -> List:
winding2_frequency_list = []
winding2_amplitude_list = []
winding2_phi_rad_list = []
# case to handle dc in exitation sweeb
if self.md_dc_checkBox.isChecked():
winding1_frequency_list.append(0) # DC frequency is 0 Hz
winding1_amplitude_list.append(comma_str_to_point_float(self.md_winding1_idc_lineEdit.text()))
winding1_phi_rad_list.append(0) # DC phase is typically 0

if self.md_simulation_type_comboBox.currentText() != self.translation_dict['inductor']:
winding2_frequency_list.append(0) # DC frequency is 0 Hz
winding2_amplitude_list.append(comma_str_to_point_float(self.md_winding2_idc_lineEdit.text()))
winding2_phi_rad_list.append(0) # DC phase is typically 0
if self.md_fk1_checkBox.isChecked():
winding1_frequency_list.append(1 * comma_str_to_point_float(self.md_base_frequency_lineEdit.text()))
winding1_amplitude_list.append(comma_str_to_point_float(self.md_winding1_ik1_lineEdit.text()))
Expand Down Expand Up @@ -3240,47 +3249,46 @@ def md_action_run_simulation(self) -> None:
# Read back results
# -----------------------------------------------

self.md_simulation_QLabel.setText('simulation fertig.')

# loaded_results_dict = fmt.visualize_simulation_results(geo.file_data.femm_results_log_path, './results.png', show_plot=False)
loaded_results_dict = fmt.visualize_simulation_results(geo.file_data.e_m_results_log_path,
geo.file_data.results_em_simulation, show_plot=False)
# pixmap = QPixmap("./results.png")
pixmap = QPixmap(geo.file_data.results_em_simulation)
self.md_loss_plot_label.setPixmap(pixmap)
self.md_loss_plot_label.setMask(pixmap.mask())
self.md_loss_plot_label.show()

# inductance = loaded_results_dict["single_sweeps"][0]["winding1"]["flux_over_current"][0]
loss_core_eddy_current = loaded_results_dict["total_losses"]["eddy_core"]
loss_core_hysteresis = loaded_results_dict["total_losses"]["hyst_core_fundamental_freq"]
# loss_winding_1 = loaded_results_dict["total_losses"]["winding1"]["total"]
self.md_loss_core_hysteresis_label.setText(f"Core Hysteresis loss: {loss_core_hysteresis} W")
self.md_loss_core_eddy_current_label.setText(f"Core Eddy Current loss: {loss_core_eddy_current} W")
# self.md_loss_winding1_label.setText(f"Winding 1 loss: {loss_winding_1} W")
# self.md_inductance_label.setText(f"Primary Inductance: {inductance} H")
inductances = []
windings_loss = []
for i in range(1, 3): # for 3 windings
winding_key = f"winding{i}"
if winding_key in loaded_results_dict["single_sweeps"][0]:
inductances.append(loaded_results_dict["single_sweeps"][0][winding_key]["flux_over_current"][0])
windings_loss.append(loaded_results_dict["total_losses"][winding_key]["total"])

# show them just for 2 windings in GUI
if self.md_simulation_type_comboBox.currentText() == self.translation_dict['inductor']:
self.md_loss_winding1_label.setText(f"Winding 1 loss: {windings_loss[0]} W")
self.md_inductance1_label.setText(f"Primary Inductance: {inductances[0]} H")
elif self.md_simulation_type_comboBox.currentText() == self.translation_dict['transformer']:
self.md_loss_winding1_label.setText(f"Winding 1 loss: {windings_loss[0]} W")
self.md_loss_winding2_label.setText(f"Winding 2 loss: {windings_loss[1]} W")
self.md_inductance1_label.setText(f"Primary Inductance: {inductances[0]} H")
self.md_inductance2_label.setText(f"Secondary Inductance: {inductances[1]} H")

# log_path = geo.e_m_results_log_path
# simulation_results = str(fmt.read_results_log(log_path))
# print(simulation_results)
# self.md_simulation_output_textBrowser.setText(simulation_results)
self.md_simulation_QLabel.setText('simulation complete.')
loaded_results_dict = fmt.visualize_simulation_results(geo.file_data.e_m_results_log_path, geo.file_data.results_em_simulation, show_plot=False)

for index, sweep in enumerate(loaded_results_dict["single_sweeps"]):
# Frequency-specific losses
freq_label = getattr(self, f'md_freq{index + 1}')
# loss_plot_label = getattr(self, f'md_loss_plot_label1')
hysteresis_label = getattr(self, f'md_loss_core_hysteresis_label{index + 1}')
eddy_current_label = getattr(self, f'md_loss_core_eddy_current_label{index + 1}')
winding1_loss_label = getattr(self, f'md_loss_winding1_label{index + 1}')
inductance1_label = getattr(self, f'md_inductance1_label{index + 1}')

if self.md_simulation_type_comboBox.currentText() == self.translation_dict['transformer']:
winding2_loss_label = getattr(self, f'md_loss_winding2_label{index + 1}')
inductance2_label = getattr(self, f'md_inductance2_label{index + 1}')

# Update frequency label
freq_label.setText(f"Frequency: {sweep['f']} Hz")

# image for loss plot
base_path, ext = os.path.splitext(geo.file_data.results_em_simulation)
cumulative_filename = f"{base_path}_total_freq{ext}"
pixmap = QPixmap(cumulative_filename)
if not pixmap.isNull():
# to show more than one figure in the future:
# loss_plot_label.setPixmap(pixmap)
# loss_plot_label.show()
# just for shown one figure:
self.md_loss_plot_label1.setPixmap(pixmap)
self.md_loss_plot_label1.show()

# loss labels
hysteresis_label.setText(f"Core Hysteresis loss: {sweep.get('core_hyst_losses', 0)} W")
eddy_current_label.setText(f"Core Eddy Current loss: {sweep.get('core_eddy_losses', 0)} W")
winding1_loss_label.setText(f"Winding 1 loss: {sweep['winding1'].get('winding_losses', 0)} W")
inductance1_label.setText(f"Primary Inductance: {sweep['winding1'].get('flux_over_current', [0])[0]} H")
# transformer case
if self.md_simulation_type_comboBox.currentText() == self.translation_dict['transformer']:
winding2_loss_label.setText(f"Winding 2 loss: {sweep['winding2'].get('winding_losses', 0)} W")
inductance2_label.setText(f"Secondary Inductance: {sweep['winding2'].get('flux_over_current', [0])[0]} H")

def inductancecalc(self):
"""Calculate inductance from given geometries."""
Expand Down
Loading
Loading