Skip to content

Commit

Permalink
Merge pull request #47 from upb-lea/component_study
Browse files Browse the repository at this point in the history
Update stacked transformer optimization
  • Loading branch information
gituser789 authored Sep 8, 2023
2 parents 275cc4d + 724b90a commit 8807938
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 26 deletions.
28 changes: 19 additions & 9 deletions femmt/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,14 +406,16 @@ def set_air_gaps(self, air_gaps: AirGaps):

self.air_gaps = air_gaps

def set_winding_windows(self, winding_windows: list[WindingWindow]):
def set_winding_windows(self, winding_windows: list[WindingWindow], mesh_accuracy: float = 0.5):
"""
Adds the winding windows to the model. Creates the windings list, which contains the conductors
from the virtual winding windows but sorted by the winding_number (ascending).
Sets empty lists for excitation parameters
:param winding_windows: List of WindingWindow objects
:type winding_windows: list[WindingWindow]
:param mesh_accuracy: a mesh_accuracy of 0.5 is recommended. Do not change this parameter, except performing thousands of simulations, e.g. a Pareto optimization. In this case, the value can be set e.g. to 0.8
:type mesh_accuracy: float
"""
self.winding_windows = winding_windows
windings = []
Expand Down Expand Up @@ -458,7 +460,7 @@ def set_winding_windows(self, winding_windows: list[WindingWindow]):
vww.turns.append(0)

# Default values for global_accuracy and padding
self.mesh_data = MeshData(0.5, 1.5, mu_0, self.core.core_inner_diameter, self.core.window_w, self.windings)
self.mesh_data = MeshData(mesh_accuracy, 1.5, mu_0, self.core.core_inner_diameter, self.core.window_w, self.windings)

def set_core(self, core: Core):
"""Adds the core to the model
Expand Down Expand Up @@ -1081,7 +1083,11 @@ def excitation_sweep(self, frequency_list: List, current_list_list: List, phi_de
self.write_simulation_parameters_to_pro_files()
self.visualize()

def component_study(self, time_current_vectors: List[List[List[float]]]):
def component_study(self, time_current_vectors: List[List[List[float]]], fft_filter_value_factor: float = 0.01):
"""
:param fft_filter_value_factor: Factor to filter frequencies from the fft. E.g. 0.01 [default] removes all amplitudes below 1 % of the maximum amplitude from the result-frequency list
:type fft_filter_value_factor: float
"""

# winding losses
frequency_current_phase_deg_list = []
Expand All @@ -1093,7 +1099,7 @@ def component_study(self, time_current_vectors: List[List[List[float]]]):
for time_current_vector in time_current_vectors:

# collect winding losses simulation input parameters
[frequency_list, amplitude, phi_rad] = ff.fft(time_current_vector, mode='time')
[frequency_list, amplitude, phi_rad] = ff.fft(time_current_vector, mode='time', filter_value_factor=fft_filter_value_factor)
phi_deg = np.rad2deg(phi_rad)
frequency_current_phase_deg_list.append([frequency_list, amplitude, phi_deg])

Expand Down Expand Up @@ -1135,8 +1141,8 @@ def component_study(self, time_current_vectors: List[List[List[float]]]):
self.excitation_sweep(frequency_list, current_list_list, phi_deg_list_list, inductance_dict=inductance_dict,
core_hyst_loss=float(p_hyst))

def center_tapped_pre_study(self, time_current_vectors: List[List[List[float]]], plot_waveforms: bool = False)\
-> Dict:
def center_tapped_pre_study(self, time_current_vectors: List[List[List[float]]], plot_waveforms: bool = False,
fft_filter_value_factor: float = 0.01) -> Dict:
"""
As magnetizing currents are often non-sinusoidal, some corrections in the simulation current waveforms
are needed. This function calculates the new current waveforms for the center tapped study to get
Expand All @@ -1146,6 +1152,8 @@ def center_tapped_pre_study(self, time_current_vectors: List[List[List[float]]],
:type time_current_vectors: List[List[List[float]]]
:param plot_waveforms: True to watch the pre-calculated waveforms
:type plot_waveforms: bool
:param fft_filter_value_factor: Factor to filter frequencies from the fft. E.g. 0.01 [default] removes all amplitudes below 1 % of the maximum amplitude from the result-frequency list
:type fft_filter_value_factor: float
:return: new current waveform vector
:rtype: Dict
Expand Down Expand Up @@ -1214,19 +1222,21 @@ def split_time_current_vectors_center_tapped(time_current_vectors: List[List[Lis

return center_tapped_time_current_vectors

def linear_loss_excitation(time_current_vectors: List[List[List[float]]]):
def linear_loss_excitation(time_current_vectors: List[List[List[float]]], fft_filter_value_factor: float = 0.01):
"""
Perform FFT to get the primary and secondary currents to calculate the wire losses.
These losses can be 'linear added' to get the total winding losses.
:param time_current_vectors: primary and secondary current waveforms over time
:type time_current_vectors: List[List[List[float]]]
:param fft_filter_value_factor: Factor to filter frequencies from the fft. E.g. 0.01 [default] removes all amplitudes below 1 % of the maximum amplitude from the result-frequency list
:type fft_filter_value_factor: float
"""
# winding losses
frequency_current_phase_deg_list = []
# collect winding losses simulation input parameters
for time_current_vector in time_current_vectors:
[frequency_list, amplitude, phi_rad] = ff.fft(time_current_vector, mode='time')
[frequency_list, amplitude, phi_rad] = ff.fft(time_current_vector, mode='time', filter_value_factor=fft_filter_value_factor)
phi_deg = np.rad2deg(phi_rad)
frequency_current_phase_deg_list.append([frequency_list, amplitude, phi_deg])

Expand Down Expand Up @@ -1301,7 +1311,7 @@ def linear_loss_excitation(time_current_vectors: List[List[List[float]]]):

# Linear Loss Excitation
time_current_vectors = split_time_current_vectors_center_tapped(time_current_vectors)
frequency_list, frequency_current_phase_deg_list = linear_loss_excitation(time_current_vectors)
frequency_list, frequency_current_phase_deg_list = linear_loss_excitation(time_current_vectors, fft_filter_value_factor)

if plot_waveforms:
i_1 = hyst_loss_amplitudes[0] * np.cos(time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[0]))
Expand Down
8 changes: 5 additions & 3 deletions femmt/examples/advanced_sto.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@

# misc
working_directory=os.path.join(os.path.dirname(__file__), "example_results", "optuna_stacked_transformer_optimization"),
fft_filter_value_factor=0.05,
mesh_accuracy=0.8,

permeability_datasource=fmt.MaterialDataSource.Measurement,
permeability_datatype=fmt.MeasurementDataType.ComplexPermeability,
Expand All @@ -69,11 +71,11 @@
permittivity_measurement_setup=fmt.MeasurementSetup.LEA_LK
)

study_name = "2023-08-30"
study_name = "2023-09-01"

if __name__ == '__main__':
time_start = datetime.datetime.now()

fmt.StackedTransformerOptimization.FemSimulation.start_proceed_study(study_name, dab_transformer_config, 10, number_objectives=4, sampler=optuna.samplers.NSGAIIISampler(), show_geometries=False)
# fmt.StackedTransformerOptimization.FemSimulation.show_study_results(study_name, dab_transformer_config, percent_error_difference_l_h = 100, percent_error_difference_l_s12=100)
# fmt.StackedTransformerOptimization.FemSimulation.re_simulate_single_result(study_name, dab_transformer_config, 6)
#fmt.StackedTransformerOptimization.FemSimulation.show_study_results(study_name, dab_transformer_config, percent_error_difference_l_h = 100, percent_error_difference_l_s12=100)
#fmt.StackedTransformerOptimization.FemSimulation.re_simulate_single_result(study_name, dab_transformer_config, 6)
38 changes: 24 additions & 14 deletions femmt/optimization/sto.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,13 @@ def objective(trial, config: StoSingleInputConfig,
winding_temperature=config.temperature)

geo.set_insulation(insulation)
geo.set_winding_windows([coil_window, transformer_window])
geo.set_winding_windows([coil_window, transformer_window], config.mesh_accuracy)

geo.create_model(freq=target_and_fixed_parameters.fundamental_frequency, pre_visualize_geometry=show_geometries)

center_tapped_study_excitation = geo.center_tapped_pre_study(
time_current_vectors=[[target_and_fixed_parameters.time_extracted_vec, target_and_fixed_parameters.current_extracted_1_vec], [target_and_fixed_parameters.time_extracted_vec, target_and_fixed_parameters.current_extracted_2_vec]])
time_current_vectors=[[target_and_fixed_parameters.time_extracted_vec, target_and_fixed_parameters.current_extracted_1_vec], [target_and_fixed_parameters.time_extracted_vec, target_and_fixed_parameters.current_extracted_2_vec]],
fft_filter_value_factor=config.fft_filter_value_factor)

geo.stacked_core_center_tapped_study(center_tapped_study_excitation, number_primary_coil_turns=primary_coil_turns)

Expand Down Expand Up @@ -262,8 +263,10 @@ def objective(trial, config: StoSingleInputConfig,
# Get inductance values
difference_l_h = config.l_h_target - geo.L_h
difference_l_s12 = config.l_s12_target - geo.L_s12
# print(f"{difference_l_h}")
# print(f"{difference_l_s12}")

trial.set_user_attr("l_h", geo.L_h)
trial.set_user_attr("l_s12", geo.L_s12)

# TODO: Normalize on goal values here or the whole generation on min and max? for each feature inbetween 0 and 1
# norm_total_loss, norm_difference_l_h, norm_difference_l_s12 = total_loss/10, abs(difference_l_h/config.l_h_target), abs(difference_l_s12/config.l_s12_target)
# return norm_total_loss, norm_difference_l_h, norm_difference_l_s12
Expand Down Expand Up @@ -379,7 +382,7 @@ def objective_directions(number_objectives: int):
study_in_memory.add_trials(study_in_storage.trials)
study_in_memory.optimize(func, n_trials=number_trials, show_progress_bar=True)

study_in_storage.add_trials(study_in_memory.trials[(-number_trials - 1):-1])
study_in_storage.add_trials(study_in_memory.trials[-number_trials:])

@staticmethod
def show_study_results(study_name: str, config: StoSingleInputConfig,
Expand Down Expand Up @@ -440,17 +443,25 @@ def show_study_results3(study_name: str, config: StoSingleInputConfig,
fig.show()

@staticmethod
def re_simulate_single_result(study_name: str, config: StoSingleInputConfig, number_trial: int):
def re_simulate_single_result(study_name: str, config: StoSingleInputConfig, number_trial: int,
fft_filter_value_factor: float = 0.01, mesh_accuracy: float = 0.5):
"""
Performs a single simulation study (inductance, core loss, winding loss) and shows the geometry of
number_trial design inside the study 'study_name'.
Note: This function does not use the fft_filter_value_factor and mesh_accuracy from the config-file.
The values are given separate. In case of re-simulation, you may want to have more accurate results.
:param study_name: name of the study
:type study_name: str
:param config: stacked transformer configuration file
:type config: StoSingleInputConfig
:param number_trial: number of trial to simulate
:type number_trial: int
:param fft_filter_value_factor: Factor to filter frequencies from the fft. E.g. 0.01 [default] removes all amplitudes below 1 % of the maximum amplitude from the result-frequency list
:type fft_filter_value_factor: float
:param mesh_accuracy: a mesh_accuracy of 0.5 is recommended. Do not change this parameter, except performing thousands of simulations, e.g. a Pareto optimization. In this case, the value can be set e.g. to 0.8
:type mesh_accuracy: float
"""
target_and_fixed_parameters = femmt.optimization.StackedTransformerOptimization.calculate_fix_parameters(config)

Expand Down Expand Up @@ -484,9 +495,6 @@ def re_simulate_single_result(study_name: str, config: StoSingleInputConfig, num
window_h_top = config.insulations.iso_top_core + config.insulations.iso_bot_core + number_rows_coil_winding * primary_litz_diameter + (
number_rows_coil_winding - 1) * config.insulations.iso_primary_to_primary

print(f"{config.insulations.iso_primary_inner_bobbin = }")
print(f"{iso_left_core = }")

primary_additional_bobbin = config.insulations.iso_primary_inner_bobbin - iso_left_core

# Maximum coil air gap depends on the maximum window height top
Expand All @@ -512,7 +520,8 @@ def re_simulate_single_result(study_name: str, config: StoSingleInputConfig, num

geo = femmt.MagneticComponent(component_type=femmt.ComponentType.IntegratedTransformer,
working_directory=target_and_fixed_parameters.working_directories.fem_working_directory,
verbosity=femmt.Verbosity.Silent, simulation_name=f"Single_Case_{loaded_trial._trial_id}")
verbosity=femmt.Verbosity.Silent, simulation_name=f"Single_Case_{loaded_trial._trial_id - 1}")
# Note: The _trial_id starts counting from 1, while the normal cases count from zero. So a correction needs to be made

core_dimensions = femmt.dtos.StackedCoreDimensions(core_inner_diameter=core_inner_diameter, window_w=window_w,
window_h_top=window_h_top, window_h_bot=window_h_bot)
Expand Down Expand Up @@ -551,13 +560,13 @@ def re_simulate_single_result(study_name: str, config: StoSingleInputConfig, num

# insulation
iso_top_core=config.insulations.iso_top_core, iso_bot_core=config.insulations.iso_bot_core,
iso_left_core=config.insulations.iso_left_core_min, iso_right_core=config.insulations.iso_right_core,
iso_left_core=iso_left_core, iso_right_core=config.insulations.iso_right_core,
iso_primary_to_primary=config.insulations.iso_primary_to_primary,
iso_secondary_to_secondary=config.insulations.iso_secondary_to_secondary,
iso_primary_to_secondary=config.insulations.iso_primary_to_secondary,
bobbin_coil_top=config.insulations.iso_top_core,
bobbin_coil_bot=config.insulations.iso_bot_core,
bobbin_coil_left=iso_left_core,
bobbin_coil_left=config.insulations.iso_primary_inner_bobbin,
bobbin_coil_right=config.insulations.iso_right_core,
center_foil_additional_bobbin=0e-3,
interleaving_scheme=femmt.InterleavingSchemesFoilLitz.ter_3_4_sec_ter_4_3_sec,
Expand All @@ -568,7 +577,7 @@ def re_simulate_single_result(study_name: str, config: StoSingleInputConfig, num
winding_temperature=config.temperature)

geo.set_insulation(insulation)
geo.set_winding_windows([coil_window, transformer_window])
geo.set_winding_windows([coil_window, transformer_window], mesh_accuracy=mesh_accuracy)

geo.create_model(freq=target_and_fixed_parameters.fundamental_frequency, pre_visualize_geometry=True)

Expand All @@ -581,7 +590,8 @@ def re_simulate_single_result(study_name: str, config: StoSingleInputConfig, num
time_current_vectors=[[target_and_fixed_parameters.time_extracted_vec,
target_and_fixed_parameters.current_extracted_1_vec],
[target_and_fixed_parameters.time_extracted_vec,
target_and_fixed_parameters.current_extracted_2_vec]])
target_and_fixed_parameters.current_extracted_2_vec]],
fft_filter_value_factor=fft_filter_value_factor)

geo.stacked_core_center_tapped_study(center_tapped_study_excitation,
number_primary_coil_turns=primary_coil_turns)
2 changes: 2 additions & 0 deletions femmt/optimization/sto_dtos.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class StoSingleInputConfig:

# misc
working_directory: str
fft_filter_value_factor: float
mesh_accuracy: float

# data sources
permeability_datasource: MaterialDataSource
Expand Down

0 comments on commit 8807938

Please sign in to comment.