summaryrefslogtreecommitdiff
path: root/coil_parasitics.py
diff options
context:
space:
mode:
Diffstat (limited to 'coil_parasitics.py')
-rw-r--r--coil_parasitics.py124
1 files changed, 116 insertions, 8 deletions
diff --git a/coil_parasitics.py b/coil_parasitics.py
index 46552c7..3ed02dd 100644
--- a/coil_parasitics.py
+++ b/coil_parasitics.py
@@ -116,7 +116,7 @@ def cli():
@cli.command()
@click.option('-d', '--sim-dir', type=click.Path(dir_okay=True, file_okay=False, path_type=Path))
@click.argument('mesh_file', type=click.Path(dir_okay=False, path_type=Path))
-def self_capacitance(mesh_file, sim_dir):
+def capacitance_matrix(mesh_file, sim_dir):
physical = dict(enumerate_mesh_bodies(mesh_file))
if sim_dir is not None:
sim_dir = Path(sim_dir)
@@ -133,14 +133,14 @@ def self_capacitance(mesh_file, sim_dir):
'Unit Charge': str(constants.elementary_charge)})
air = elmer.load_material('air', sim, 'coil_parasitics_materials.yml')
- ro4003c = elmer.load_material('ro4003c', sim, 'coil_parasitics_materials.yml')
+ fr4 = elmer.load_material('fr4', sim, 'coil_parasitics_materials.yml')
solver_electrostatic = elmer.load_solver('Electrostatics_Capacitance', sim, 'coil_parasitics_solvers.yml')
solver_electrostatic.data['Potential Difference'] = '1.0'
eqn = elmer.Equation(sim, 'main', [solver_electrostatic])
bdy_sub = elmer.Body(sim, 'substrate', [physical['substrate'][1]])
- bdy_sub.material = ro4003c
+ bdy_sub.material = fr4
bdy_sub.equation = eqn
bdy_ab = elmer.Body(sim, 'airbox', [physical['airbox'][1]])
@@ -202,7 +202,7 @@ def inductance(mesh_file, sim_dir, solver_method):
'Unit Charge': str(constants.elementary_charge)})
air = elmer.load_material('air', sim, 'coil_mag_materials.yml')
- ro4003c = elmer.load_material('ro4003c', sim, 'coil_mag_materials.yml')
+ fr4 = elmer.load_material('fr4', sim, 'coil_mag_materials.yml')
copper = elmer.load_material('copper', sim, 'coil_mag_materials.yml')
solver_current = elmer.load_solver('Static_Current_Conduction', sim, 'coil_mag_solvers.yml')
@@ -219,7 +219,7 @@ def inductance(mesh_file, sim_dir, solver_method):
bdy_trace.equation = copper_eqn
bdy_sub = elmer.Body(sim, 'substrate', [physical['substrate'][1]])
- bdy_sub.material = ro4003c
+ bdy_sub.material = fr4
bdy_sub.equation = air_eqn
bdy_ab = elmer.Body(sim, 'airbox', [physical['airbox'][1]])
@@ -313,7 +313,7 @@ def mutual_inductance(mesh_file, sim_dir, reference_field):
'Unit Charge': str(constants.elementary_charge)})
air = elmer.load_material('air', sim, 'coil_mag_materials.yml')
- ro4003c = elmer.load_material('ro4003c', sim, 'coil_mag_materials.yml')
+ fr4 = elmer.load_material('fr4', sim, 'coil_mag_materials.yml')
copper = elmer.load_material('copper', sim, 'coil_mag_materials.yml')
solver_current = elmer.load_solver('Static_Current_Conduction', sim, 'coil_mag_solvers.yml')
@@ -332,11 +332,11 @@ def mutual_inductance(mesh_file, sim_dir, reference_field):
bdy_trace2.equation = copper_eqn
bdy_sub1 = elmer.Body(sim, 'substrate1', [physical['substrate1'][1]])
- bdy_sub1.material = ro4003c
+ bdy_sub1.material = fr4
bdy_sub1.equation = air_eqn
bdy_sub2 = elmer.Body(sim, 'substrate2', [physical['substrate2'][1]])
- bdy_sub2.material = ro4003c
+ bdy_sub2.material = fr4
bdy_sub2.equation = air_eqn
@@ -422,6 +422,114 @@ def mutual_inductance(mesh_file, sim_dir, reference_field):
print(f'Mutual inductance calucated from field: {format_si(Lm, "H")}')
+@cli.command()
+@click.option('-d', '--sim-dir', type=click.Path(dir_okay=True, file_okay=False, path_type=Path))
+@click.argument('mesh_file', type=click.Path(dir_okay=False, path_type=Path))
+def self_capacitance(mesh_file, sim_dir):
+ physical = dict(enumerate_mesh_bodies(mesh_file))
+
+ if sim_dir is not None:
+ sim_dir = Path(sim_dir)
+ sim_dir.mkdir(exist_ok=True)
+
+ sim = elmer.load_simulation('3D_steady', 'self_capacitance_sim.yml')
+ mesh_dir = '.'
+ mesh_fn = 'mesh'
+ sim.header['Mesh DB'] = f'"{mesh_dir}" "{mesh_fn}"'
+ sim.constants.update({
+ 'Permittivity of Vacuum': str(constants.epsilon_0),
+ 'Gravity(4)': f'0 -1 0 {constants.g}',
+ 'Boltzmann Constant': str(constants.Boltzmann),
+ 'Unit Charge': str(constants.elementary_charge)})
+
+ air = elmer.load_material('air', sim, 'coil_mag_materials.yml')
+ fr4 = elmer.load_material('fr4', sim, 'coil_mag_materials.yml')
+ copper = elmer.load_material('copper', sim, 'coil_mag_materials.yml')
+
+ solver_current = elmer.load_solver('StaticCurrent', sim, 'self_capacitance_solvers.yml')
+ solver_estat = elmer.load_solver('Electrostatics', sim, 'self_capacitance_solvers.yml')
+
+ copper_eqn = elmer.Equation(sim, 'copperEqn', [solver_current, solver_estat])
+ air_eqn = elmer.Equation(sim, 'airEqn', [solver_estat])
+
+ bdy_trace = elmer.Body(sim, 'trace', [physical['trace'][1]])
+ bdy_trace.material = copper
+ bdy_trace.equation = copper_eqn
+
+ bdy_sub = elmer.Body(sim, 'substrate', [physical['substrate'][1]])
+ bdy_sub.material = fr4
+ bdy_sub.equation = air_eqn
+
+ bdy_ab = elmer.Body(sim, 'airbox', [physical['airbox'][1]])
+ bdy_ab.material = air
+ bdy_ab.equation = air_eqn
+
+ bdy_if_top = elmer.Body(sim, 'interface_top', [physical['interface_top'][1]])
+ bdy_if_top.material = copper
+ bdy_if_top.equation = copper_eqn
+
+ bdy_if_bottom = elmer.Body(sim, 'interface_bottom', [physical['interface_bottom'][1]])
+ bdy_if_bottom.material = copper
+ bdy_if_bottom.equation = copper_eqn
+
+ potential_force = elmer.BodyForce(sim, 'electric_potential', {'Potential': 'Equals "PotentialStat"'})
+ bdy_trace.body_force = potential_force
+
+ # boundaries
+ boundary_airbox = elmer.Boundary(sim, 'FarField', [physical['airbox_surface'][1]])
+ boundary_airbox.data['Electric Infinity BC'] = 'True'
+
+ boundary_vplus = elmer.Boundary(sim, 'Vplus', [physical['interface_top'][1]])
+ boundary_vplus.data['PotentialStat'] = 'Real 1.0'
+ boundary_vplus.data['Save Scalars'] = True
+
+ boundary_vminus = elmer.Boundary(sim, 'Vminus', [physical['interface_bottom'][1]])
+ boundary_vminus.data['PotentialStat'] = 'Real 0.0'
+
+ with tempfile.TemporaryDirectory() as tmpdir:
+ tmpdir = sim_dir if sim_dir else Path(tmpdir)
+
+ sim.write_startinfo(tmpdir)
+ sim.write_sif(tmpdir)
+ # Convert mesh from gmsh to elemer formats. Also scale it from 1 unit = 1 mm to 1 unit = 1 m (SI units)
+ elmer_grid(mesh_file.absolute(), 'mesh', cwd=tmpdir, scale=[1e-3, 1e-3, 1e-3],
+ stdout_log=(tmpdir / 'ElmerGrid_stdout.log'),
+ stderr_log=(tmpdir / 'ElmerGrid_stderr.log'))
+ solver_stdout, solver_stderr = (tmpdir / 'ElmerSolver_stdout.log'), (tmpdir / 'ElmerSolver_stderr.log')
+ res = elmer_solver(tmpdir,
+ stdout_log=solver_stdout,
+ stderr_log=solver_stderr)
+
+ P, R, U_mag = None, None, None
+ solver_error = False
+ for l in res.stdout.splitlines():
+ if (m := re.fullmatch(r'StatCurrentSolve:\s*Total Heating Power\s*:\s*([0-9.+-Ee]+)\s*', l)):
+ P = float(m.group(1))
+ elif (m := re.fullmatch(r'StatCurrentSolve:\s*Effective Resistance\s*:\s*([0-9.+-Ee]+)\s*', l)):
+ R = float(m.group(1))
+ elif (m := re.fullmatch(r'MagnetoDynamicsCalcFields:\s*ElectroMagnetic Field Energy\s*:\s*([0-9.+-Ee]+)\s*', l)):
+ U_mag = float(m.group(1))
+ elif re.fullmatch(r'IterSolve: Linear iteration did not converge to tolerance', l):
+ solver_error = True
+
+ if solver_error:
+ raise click.ClickException(f'Error: One of the solvers did not converge. See log files for details:\n{solver_stdout.absolute()}\n{solver_stderr.absolute()}')
+ elif P is None or R is None or U_mag is None:
+ raise click.ClickException(f'Error during solver execution. Electrical parameters could not be calculated. See log files for details:\n{solver_stdout.absolute()}\n{solver_stderr.absolute()}')
+
+ V = math.sqrt(P*R)
+ I = math.sqrt(P/R)
+ L = 2*U_mag / (I**2)
+
+ assert math.isclose(V, 1.0, abs_tol=1e-3)
+
+ print(f'Total magnetic field energy: {format_si(U_mag, "J")}')
+ print(f'Reference coil current: {format_si(I, "Ω")}')
+ print(f'Coil resistance calculated by solver: {format_si(R, "Ω")}')
+ print(f'Inductance calucated from field: {format_si(L, "H")}')
+
+
+
if __name__ == '__main__':
cli()