GenericStructure#
- class simpleEMS.components.GenericStructure(params: GenericParams, sim: SimSetup)#
Bases:
SimToolsArbitrary structure assembled from CSXCAD primitives.
Each
create_*method adds one primitive to the CSXCAD structure and returns it, so a caller can transform it further or register its edges with the FDTD grid. Shared quantities – the trace elevation, the copper thickness, the port impedance, the substrate footprint – default to the matching value onparamsand only need to be passed when a primitive differs from it.- Parameters:
params (GenericParams) – Substrate, frequency and mesh parameters.
sim (SimSetup) – Named tuple containing the CSXCAD geometry and openEMS FDTD engine.
Methods Summary
add_field_dump(sim, params[, output_path, ...])Add a field dump box to the simulation setup.
compute_nf2ff_3d(nf2ff, freq[, output_path, ...])Compute the 3D far-field radiation pattern over a full theta/phi sweep (theta in [0, 180] deg, phi in [0, 360] deg, 2 deg steps).
compute_sim_data(sim, port[, output_path])Compute S-parameters, impedance, VSWR, and port power/voltage/current from simulation results, for plotting and post-processing.
create_cpw([name, z_elevation_mm, ...])Create a straight coplanar waveguide (CPW) segment.
create_cpw_lumped_port([name, prop_dir, ...])Create a coplanar waveguide port from one lumped port per slot.
create_cpw_port([name, prop_dir, excite, ...])Create a coplanar waveguide port on a CPW segment.
create_curved_bend([name, z_elevation_mm, ...])Create a curved (circular-arc) bend.
create_gcpw([name, z_elevation_mm, ...])Create a straight grounded (conductor-backed) CPW segment.
create_ground([name, start, stop, priority])Create a copper ground plane from two corner points.
create_lumped_port(port_nr, start, stop[, ...])Create a lumped port for S-parameter extraction.
create_mesh([smooth_ratio])Generate the FDTD mesh for everything added so far.
create_microstrip([name, z_elevation_mm, ...])Create a straight rectangular microstrip trace.
create_miter([name, z_elevation_mm, ...])Create a 90-degree mitered bend.
create_nf2ff([sim])Create the near-field-to-far-field (NF2FF) recording box.
create_radial_stub([name, z_elevation_mm, ...])Create a radial (fan-shaped) stub.
create_substrate([name, start, stop, eps_r, ...])Create a dielectric substrate from two corner points.
create_taper([name, z_elevation_mm, ...])Create a trapezoidal taper trace.
create_via([name, antipad_diameter_mm, ...])Create a plated through-hole via as a solid conductor.
export_csxcad_xml_to_step(structure_xml_path)Load a
structure.xmlfile and export it to STEP AP242 format.export_gerber(sim[, output_path, options, ...])Export CSXCAD geometry to Gerber format, one file per copper layer.
export_step(sim[, output_path])Export CSXCAD geometry to a colored, multi-layer STEP AP242 file using CadQuery.
export_stl(sim[, output_path])Export the CSXCAD structure to STL files (FDTD backend only).
export_touchstone(freqs[, s11, s21, ...])Export S-parameters to a Touchstone
.sNpfile.plot_2d_directivity(nf2ff, freq[, ...])Plot the 2D directivity pattern (xz-plane, phi=0) at a specified frequency, annotated with the half-power beamwidth (HPBW).
plot_2d_rad_pattern(nf2ff, freq[, ...])Plot the 2D E-field radiation pattern at a specified frequency.
plot_3d_directivity(nf2ff_3d_result, freq[, ...])Plot the 3D directivity pattern of an antenna at a specified frequency.
plot_3d_gain(nf2ff_3d_result, freq, input_power)Plot the 3D gain pattern of an antenna at a specified frequency.
plot_3d_power(nf2ff_3d_result, freq[, ...])Plot the 3D radiated power pattern of an antenna at a specified frequency.
plot_group_delay(freqs, s21[, x_label, ...])Compute and plot the group delay as a function of frequency.
plot_impedance(freqs, z11[, x_label, ...])Plot the input impedance (Z11) as a function of frequency.
plot_phase(freqs, s21[, x_label, y_label, title])Plot the transmission phase (angle of S21) as a function of frequency.
plot_s_param(freqs, s11[, s21, x_label, ...])Plot S-parameters (S11 and optionally S21) against frequency.
plot_smith_chart(freqs, s11[, label, charac_imp])Plot S11 data on a Smith chart.
plot_vswr(freqs, vswr[, x_label, y_label, ...])Plot the voltage standing wave ratio (VSWR) as a function of frequency.
print_and_save_params(params[, output_path])Print the simulation parameters to the console and save them to
params/params.txt.run_simulation(sim[, output_path])Run the simulation and write results to
output_path.save_plots([output_path, file_format])Save all currently open matplotlib figures to
output_path / "plots".Display all generated plots.
write_and_show_structure(sim[, output_path, ...])Display the simulation geometry.
Methods Documentation
- static add_field_dump(sim: SimSetup, params: SimParams, output_path: Path | None = None, dump_freq: float | None = None, dump_type: DumpType = DumpType.efield_frequency) None#
Add a field dump box to the simulation setup.
Configures and attaches a field/current dump of the requested
dump_typeto the CSXCAD structure. The box follows the simulation box in x and y –params.simulation_boxwhen defined, or the same geometry-padded box the FDTD mesher builds when it isNone(seesimpleEMS.fdtd_mesh.auto_simulation_bounds()) – and spans z from 0 to the top of the copper layer (substrate_thickness_mm + copper_thickness_mm).- Parameters:
sim (SimSetup) – Simulation setup named tuple returned by
setup_simulation.params (SimParams) – Parameter object supplying
simulation_box,lambda0,substrate_thickness_mm,copper_thickness_mmandmain_freq, used to size and configure the dump.output_path (Path, optional) – Directory the dump data will be written under (a
field_dumpsubdirectory is created). Defaults tocwd / "Sim_Path".dump_freq (float, optional) – Frequency of a frequency-domain dump. Defaults to
params.main_freq.dump_type (DumpType, optional) – Type of field/current dump to add (time-domain or frequency-domain E-field, H-field, current, current density, or SAR). Default is
DumpType.efield_frequency.
- Return type:
None
- static compute_nf2ff_3d(nf2ff: nf2ff, freq: float, output_path: Path | None = None, read_cached: bool = False) nf2ff_results#
Compute the 3D far-field radiation pattern over a full theta/phi sweep (theta in [0, 180] deg, phi in [0, 360] deg, 2 deg steps).
The resulting far-field data can be used for visualization, directivity/gain/power analysis, and post-processing of antenna performance via
plot_3d_directivity,plot_3d_gain, andplot_3d_power.- Parameters:
nf2ff (object) – The near-field-to-far-field (NF2FF) object containing the simulation data.
freq (float) – Frequency (in Hz) at which the 3D far-field pattern is evaluated. Must be a scalar.
output_path (Path, optional) – Path to the directory where the simulation result is saved. Defaults to
cwd / "Sim_Path".read_cached (bool, optional) – If True, read cached NF2FF results instead of re-computing. Default is False.
- Returns:
The NF2FF result object for the full theta/phi sweep, holding (among other fields)
E_norm,Dmax,Prad,theta, andphi.- Return type:
nf2ff_results
- Raises:
TypeError – If
freqis not a scalar (e.g. an array of frequencies).
- static compute_sim_data(sim: SimSetup, port: LumpedPort | list[LumpedPort], output_path: Path | None = None) SimData#
Compute S-parameters, impedance, VSWR, and port power/voltage/current from simulation results, for plotting and post-processing.
For the FDTD backend this calls
CalcPorton the given port(s) and derives S11 (and S21 for two-port setups), Z11, VSWR, and input power from the port voltage/current waves. For the FEM backend theportargument is ignored and results are instead read from the GetDP sweep output previously written tooutput_pathbyrun_simulation.- Parameters:
sim (SimSetup) – Simulation setup named tuple returned by
setup_simulation; suppliesfreqs,backend_engine, andcharac_imp.port (LumpedPort or list of LumpedPort) – The openEMS port object representing a single-port simulation, or a two-element list
[port1, port2]for a two-port simulation. Ignored whensim.backend_engine == "FEM".output_path (Path, optional) – Directory the simulation results were written to. Defaults to
cwd(FDTD backend) orcwd / "Sim_Path"(FEM backend, to match the default used byrun_simulation).
- Returns:
Named tuple containing:
- freqsNDArray
Frequency points used in post-processing.
- s11NDArray
Complex S11 values across the frequency range.
- s21NDArray or None
Complex S21 values across the frequency range, or
Nonefor a single-port simulation.
- z11NDArray
Complex Z11 values across the frequency range.
- vswrNDArray
VSWR values across the frequency range, computed from S11 (clipped to
|S11| <= 0.999to avoid division by zero).
- input_powerfloat
Time-averaged input power at the driven port.
- port_voltageNDArray
Total complex voltage at the driven port across the frequency range.
- port_currentNDArray
Total complex current at the driven port across the frequency range.
- ref_impedancefloat
Reference impedance
charac_imp(fromsim) that S11 and Z11 were computed against.
- Return type:
SimData
- create_cpw(name: str = 'cpw', *, position: tuple[float, float], trace_width_mm: float, gap_mm: float, ground_width_mm: float, length_mm: float, z_elevation_mm: float | None = None, copper_thickness_mm: float | None = None, rotation: float = 0, priority: int = 6) tuple[CSPrimitives, CSPrimitives, CSPrimitives]#
Create a straight coplanar waveguide (CPW) segment.
Three parallel copper pours sharing
z_elevation_mm/copper_thickness_mm: a central signal trace of widthtrace_width_mm, flanked on both sides by a slot of widthgap_mmand then a ground pour of widthground_width_mm. Nothing is drawn underneath – this is the plain, ungrounded line, whose return path is the two coplanar pours alone.A ground plane does not belong under it on its own. Pours that are not tied to that plane are free to drift apart in potential, and the parallel-plate mode between them and it starts to carry power; a plane comes with the stitching vias that hold the pours to it, which is
create_gcpw(), the conductor-backed line.Feed a CPW segment with
create_cpw_port(), not a lumped port: the mode lives in the two slots, and a lumped port can only drive one gap at a single point.positionis the midpoint of the signal trace’s input edge, so the segment butts flush against the end of the incoming line. In the unrotated frame it runs+y, with the trace centred oncxand the two pours flanking it inx; the output edge – where the next primitive starts – is(cx, cy + length_mm)beforerotationis applied.The segment also asks
create_mesh()for four mesh lines across each slot – its two edges plus the interior – which the automatic mesher would otherwise leave unresolved: a slot is thinner than the resolution at which it stops subdividing an interval, so it would get one line at its midpoint, which is both too coarse for the region the mode lives in and makes every boxcreate_cpw_port()hands openEMS a box with no extent. Arotationthat leaves the slots off-axis cannot be expressed as an axis-aligned line, so nothing is requested for it andcreate_cpw_port()raises on that grid.- Parameters:
name (str, optional) – Base name for the segment’s properties: the trace goes on
"<name>_trace"and the pours on"<name>_ground_1"and"<name>_ground_2". Default"cpw".position (tuple[float, float]) –
(x, y)midpoint of the trace’s input edge, in the unrotated frame.trace_width_mm (float) – Width of the central signal trace.
gap_mm (float) – Width of the slot separating the signal trace from each ground pour.
ground_width_mm (float) – Width of each of the two ground pours.
length_mm (float) – Segment length along y, in the unrotated frame.
z_elevation_mm (float | None, optional) – Z position of the conductors’ bottom face. Defaults to the substrate’s top face.
copper_thickness_mm (float | None, optional) – Conductor thickness along z. Defaults to
params.copper_thickness_mm.rotation (float, optional) – Rotation in degrees, counter-clockwise about
position. Default0.priority (int, optional) – CSXCAD priority of the trace and both pours; where primitives overlap, the higher priority wins. Default
6.
- Returns:
The signal trace and the two ground pours, in the order
(trace, ground_lo, ground_hi)(lo/hiby x in the unrotated frame).- Return type:
tuple[CSPrimitives, CSPrimitives, CSPrimitives]
- create_cpw_lumped_port(name: str = 'cpw_lumped_port', *, port_nr: int, start: list[float], stop: list[float], gap_mm: float, prop_dir: str = 'y', excite: float = 0, impedance: float | None = None, priority: int = 7) CPWLumpedPort#
Create a coplanar waveguide port from one lumped port per slot.
The alternative to
create_cpw_port(), and the one to reach for when the line’s conductors have thickness. openEMS’s CPW port is drawn entirely on onezplane, so on a line with real copper on it the probes sit on a face of that copper rather than across the slot, and the current probe’s loop has to guess where inzthe conductor ends. This port instead gives each slot a lumped port whose box fills the slot – the gap across, the port length along the run, and the whole conductor thickness inz.Both slots are driven signal pour -> ground pour, which puts their excitation vectors in opposition along the slot axis and so excites the odd mode the line carries rather than the even parallel-plate one a single lumped port would. Each is terminated in
2 * impedance, which isimpedancein parallel, and the two are returned as oneCPWLumpedPortthat behaves like any other openEMS port.Corners follow
create_cpw_port():startandstopare two opposite corners of the signal trace, never of the slots or the pours, andgap_mmis how far past each trace edge the boxes reach. The one difference isz, which here must differ between the two – that span is the conductor thickness the port fills.startis the reference plane, so a port feeding a line starts where the line starts and a port terminating one starts at its far end, withstopbehindstart.Call this before
create_mesh(), the opposite ofcreate_cpw_port(). openEMS’s CPW port reads the grid to place its probes on it, so it has to come after; a lumped port never looks at the grid, and the mesher should see its boxes and the lines it asks for – above all the one on the port’s far edge, which is what fixes the port’s length instead of letting it snap to whatever the grid happened to offer.- Parameters:
name (str, optional) – Base name for the two slot ports, which take the suffixes
"_lo_"and"_hi_"(by position along the slot axis) as the prefix on their probe file names. Default"cpw_lumped_port".port_nr (int) – Port number (1-indexed), shared by both slots – they are one port, and it is the returned object that carries the number.
start (list[float]) –
[x, y, z]opposite corners of the port’s signal trace. Alongprop_dirthey give the reference plane and the end of the run; along the other in-plane axis, the two edges of the trace; inz, the bottom and top of the conductor.stop (list[float]) –
[x, y, z]opposite corners of the port’s signal trace. Alongprop_dirthey give the reference plane and the end of the run; along the other in-plane axis, the two edges of the trace; inz, the bottom and top of the conductor.gap_mm (float) – Width of the slot on each side of the trace. Not covered by
start/stop: it is how far past each trace edge the slot boxes reach.prop_dir (str, optional) – In-plane axis the run follows,
"x"or"y". Default"y". It cannot be inferred, since the corners differ on both in-plane axes – one span is the run, the other the trace width.excite (float, optional) – Excitation amplitude.
0(default) is a matched load, nonzero drives the port.impedance (float | None, optional) – Reference impedance of the pair, in ohms. Each slot is terminated in twice it. Defaults to
params.charac_imp.priority (int, optional) – CSXCAD priority for the port’s primitives.
- Returns:
The created port (needed for post-simulation
CalcPort).- Return type:
CPWLumpedPort
- Raises:
ValueError – If
prop_diris not"x"or"y"; ifstartandstopagree alongprop_dir, along the trace-width axis, or inz; or if the mesh has already been generated.
See also
create_cpwthe segment this port feeds.
create_cpw_portopenEMS’s own CPW port, for a zero-thickness line.
- create_cpw_port(name: str = 'cpw_port', *, port_nr: int, start: list[float], stop: list[float], gap_mm: float, prop_dir: str = 'y', excite: float = 0, impedance: float | None = None, feed_shift_mm: float | None = None, meas_plane_shift_mm: float | None = None, priority: int = 7) CPWPort#
Create a coplanar waveguide port on a CPW segment.
The CPW mode is odd: the signal trace swings against both ground pours at once, and the voltage that defines it is the field across the two slots together. A lumped port cannot represent that – it drives a single gap at a single point, so it excites the wrong field and reports the wrong impedance. openEMS’s CPW port instead places voltage probes across both slots at three planes along the run and current probes between them, which gives the propagation constant and the line’s own characteristic impedance as well as a clean single-mode excitation.
Like
create_lumped_port(), and unlike the rotatable primitives, the port is given as two opposite corners of the signal trace it sits on – the same pair openEMS itself takes. The corners span the trace only, never the slots or the pours;gap_mmadds those. They share onez, because every part of the port is a sheet.prop_dirsays which of the two in-plane axes the run follows, leaving the other one to span the trace width, and the direction along it is the sign ofstop - start: a port that feeds a segment starts where the segment starts, and a port that terminates one starts at its far end and runs back into it, withstopbehindstart.startis the reference plane – the plane the termination sits on and the S-parameters are referenced to – so it is the corner worth placing deliberately. Both it and the sharedzare snapped onto the mesh, since a sheet the grid has no line on covers no cells at all: openEMS drops it, excitation included.Two ordering rules come from openEMS, not from here. The port reads the grid to place its probes on it, so the mesh must already exist – build the geometry, call
create_mesh(), then add CPW ports. And the port draws its own zero-thickness trace, on the samecpw_tracepropertycreate_cpw()uses, so it lands inside the segment’s own copper rather than beside it.- Parameters:
name (str, optional) – Name of the CSXCAD property the trace sheet openEMS draws for the port is added to, kept distinct from the segment it sits on so it reads as the port’s own copper. Default
"cpw_port".port_nr (int) – Port number (1-indexed).
start (list[float]) –
[x, y, z]opposite corners of the port’s trace sheet. Bothzvalues must be equal. Alongprop_dirthey give the reference plane and the end of the run; along the other in-plane axis, the two edges of the signal trace.stop (list[float]) –
[x, y, z]opposite corners of the port’s trace sheet. Bothzvalues must be equal. Alongprop_dirthey give the reference plane and the end of the run; along the other in-plane axis, the two edges of the signal trace.gap_mm (float) – Width of the slot on each side of the trace. Not covered by
start/stop: it is how far past each trace edge the probes, the excitation and the termination reach.prop_dir (str, optional) – In-plane axis the run follows,
"x"or"y". Default"y". It cannot be inferred, since the corners differ on both in-plane axes – one span is the run, the other the trace width.excite (float, optional) – Excitation amplitude.
0(default) is a matched load, nonzero drives the port.impedance (float | None, optional) – Termination resistance in ohms, placed at the reference plane. Defaults to
params.charac_imp.feed_shift_mm (float | None, optional) – Distance from the reference plane to the excitation plane.
None(default) excites at the reference plane.meas_plane_shift_mm (float | None, optional) – Distance from the reference plane to the measurement plane.
None(default) measures at the middle of the run.priority (int, optional) – CSXCAD priority for the port’s primitives.
- Returns:
The created port object (needed for post-simulation
CalcPort).- Return type:
CPWPort
- Raises:
ValueError – If
prop_diris not"x"or"y", ifstartandstopdisagree in z or agree alongprop_dir, if the mesh has not been generated yet, or if either slot holds fewer than two mesh lines – which would collapse every probe, excitation and termination box the port spans across it onto a single line.
- create_curved_bend(name: str = 'curved_bend', *, position: tuple[float, float], width_mm: float, bend_radius_mm: float, z_elevation_mm: float | None = None, copper_thickness_mm: float | None = None, rotation: float = 0, turn: str = 'left', bend_angle: float = 90, num_segments: int = 60, priority: int = 6) CSPrimitives#
Create a curved (circular-arc) bend.
An alternative to
create_miter()that joins twowidth_mm-wide arms with a constant-width band swept along a circular arc instead of a mitered corner block. The primitive is an annular sector: the outer edge is an arc of radiusbend_radius_mm + width_mm/2and the inner edge an arc of radiusbend_radius_mm - width_mm/2, both centred on the bend’s centre of curvature;bend_radius_mmitself is the radius of the arm’s centreline.positionis the midpoint of the input edge, so the band butts flush against the end of the incoming arm rather than straddling it. In the unrotated frame the arm arrives travelling+y, the centre of curvature sits at(cx - bend_radius_mm, cy), and the arc sweepsbend_angledegrees from there.rotationis degrees CCW aboutposition, which keeps the join flush at any angle.turnis the handedness of the bend as seen by a wave travelling along the incoming arm, with the same meaning as increate_miter():"left"curves towards the arm’s left (-xatrotation=0),"right"towards its right (+x). The two are mirror images, sorotationalone cannot swap them.The outgoing arm’s input edge – where the next primitive should start – is centred at
(cx - bend_radius_mm + bend_radius_mm*cos(a), cy + bend_radius_mm*sin(a))forturn="left", or the mirror image aboutcxforturn="right", witha = radians(bend_angle)beforerotationis applied.- Parameters:
name (str, optional) – Name of the CSXCAD property the bend is added to. Default
"curved_bend".position (tuple[float, float]) –
(x, y)midpoint of the input edge, in the unrotated frame.width_mm (float) – Width of the arms joined by the bend.
bend_radius_mm (float) – Radius of the arm’s centreline through the bend. Must exceed
width_mm / 2so the inner edge does not cross the centre of curvature.z_elevation_mm (float | None, optional) – Z position of the bend’s bottom face. Defaults to the substrate’s top face.
copper_thickness_mm (float | None, optional) – Bend thickness along z. Defaults to
params.copper_thickness_mm.rotation (float, optional) – Rotation in degrees, counter-clockwise about
position. Default0.turn (str, optional) – Bend handedness,
"left"or"right". Default"left".bend_angle (float, optional) – Angle swept by the arc, in degrees, in
(0, 360]. Default90.num_segments (int, optional) – Number of polygon segments approximating each arc. Default
60.priority (int, optional) – CSXCAD priority of the primitive; where primitives overlap, the higher priority wins. Default
6.
- Returns:
The bend primitive.
- Return type:
CSPrimitives
- Raises:
ValueError – If
bend_radius_mmdoes not exceedwidth_mm / 2,turnis neither"left"nor"right", orbend_anglelies outside(0, 360].
- create_gcpw(name: str = 'gcpw', *, position: tuple[float, float], trace_width_mm: float, gap_mm: float, ground_width_mm: float, length_mm: float, via_diameter_mm: float, via_pitch_mm: float, via_z_bottom_mm: float, via_z_top_mm: float, z_elevation_mm: float | None = None, copper_thickness_mm: float | None = None, rotation: float = 0, priority: int = 6) tuple[CSPrimitives, CSPrimitives, CSPrimitives]#
Create a straight grounded (conductor-backed) CPW segment.
Everything
create_cpw()draws – a central signal trace flanked by a slot and a ground pour on each side – plus a row of stitching vias (viacreate_via()) centred along each pour, evenly spaced byvia_pitch_mmwith one via inset by its radius from each end of the segment, so its disc lands fully inside the ground pour rather than straddling the edge.The vias are what make the line conductor-backed: they tie the coplanar pours to the plane underneath, which this method does not draw – add it with
create_ground(), whose footprint is the whole board rather than this one segment. Keepvia_pitch_mmwell inside lambda/10, or the two pours drift apart in potential between stitches and the parallel-plate mode between them and the backside ground starts to carry power.Feed the segment with
create_cpw_port(), not a lumped port, for the reason given increate_cpw(); the slot mesh lines that port needs are requested here too, by the same call that draws the pours.positionis the midpoint of the signal trace’s input edge, so the segment butts flush against the end of the incoming line. In the unrotated frame it runs+y, with the trace centred oncxand the two pours flanking it inx; the output edge – where the next primitive starts – is(cx, cy + length_mm)beforerotationis applied.- Parameters:
name (str, optional) – Base name for the segment’s properties: the trace goes on
"<name>_trace", the pours on"<name>_ground_1"and"<name>_ground_2", and each stitching via on"<name>_via_<row>_<side>". Default"gcpw".position (tuple[float, float]) –
(x, y)midpoint of the trace’s input edge, in the unrotated frame.trace_width_mm (float) – Width of the central signal trace.
gap_mm (float) – Width of the slot separating the signal trace from each ground pour.
ground_width_mm (float) – Width of each of the two ground pours.
length_mm (float) – Segment length along y, in the unrotated frame.
via_diameter_mm (float) – Diameter of the stitching vias placed along each ground pour. Must be less than both
length_mmandground_width_mm.via_pitch_mm (float) – Centre-to-centre spacing along the segment between stitching vias.
via_z_bottom_mm (float) – Z extent of the stitching vias – typically the backside ground plane’s bottom face and the top of the copper.
via_z_top_mm (float) – Z extent of the stitching vias – typically the backside ground plane’s bottom face and the top of the copper.
z_elevation_mm (float | None, optional) – Z position of the conductors’ bottom face. Defaults to the substrate’s top face.
copper_thickness_mm (float | None, optional) – Conductor thickness along z. Defaults to
params.copper_thickness_mm.rotation (float, optional) – Rotation in degrees, counter-clockwise about
position. Default0.priority (int, optional) – CSXCAD priority of the trace, the pours and the stitching vias; where primitives overlap, the higher priority wins. Default
6.
- Returns:
The signal trace and the two ground pours, in the order
(trace, ground_lo, ground_hi)(lo/hiby x in the unrotated frame). The stitching vias are reachable by name.- Return type:
tuple[CSPrimitives, CSPrimitives, CSPrimitives]
- Raises:
ValueError – If
via_diameter_mmis not less than bothlength_mmandground_width_mm.
- create_ground(name: str = 'ground', *, start: list[float] | None = None, stop: list[float] | None = None, priority: int = 2) CSPrimitives#
Create a copper ground plane from two corner points.
- Parameters:
name (str, optional) – Name of the CSXCAD property the ground plane is added to. Default
"ground".start (list[float] | None, optional) –
[x, y, z]opposite corners of the ground box. Both default to the footprint inparams: the substrate width and length centred on the origin, one copper thickness belowz = 0.stop (list[float] | None, optional) –
[x, y, z]opposite corners of the ground box. Both default to the footprint inparams: the substrate width and length centred on the origin, one copper thickness belowz = 0.priority (int, optional) – CSXCAD priority of the primitive; where primitives overlap, the higher priority wins. Default
2.
- Returns:
The ground plane primitive.
- Return type:
CSPrimitives
- create_lumped_port(port_nr: int, start: list[float], stop: list[float], direction: str = 'z', impedance: float | None = None, excite: float = 0, priority: int = 6, edges2grid: str = 'y') LumpedPort#
Create a lumped port for S-parameter extraction.
- Parameters:
port_nr (int) – Port number (1-indexed).
start (list[float]) –
[x, y, z]coordinates defining the port box. For a microstrip z-port, this typically spans from just below the ground plane to just above the trace.stop (list[float]) –
[x, y, z]coordinates defining the port box. For a microstrip z-port, this typically spans from just below the ground plane to just above the trace.direction (str) – Excitation direction (
"x","y", or"z").impedance (float | None, optional) – Port reference impedance in ohms. Defaults to
params.charac_imp.excite (float) – Excitation amplitude.
0= matched load, nonzero = driven.priority (int) – CSXCAD mesh priority for the port primitives.
edges2grid (str) – Which transverse edges to snap to the mesh grid. Typically the direction the line runs along, so a mesh line lands on the port plane (
"y"for a line running along y).
- Returns:
The created port object (needed for post-simulation
CalcPort).- Return type:
LumpedPort
- create_mesh(smooth_ratio: float = 1.5) None#
Generate the FDTD mesh for everything added so far.
Scans the primitives already in the CSXCAD structure and builds the grid around them (see
simpleEMS.fdtd_mesh.Mesh), so call this after the geometry and the ports are in place.Any mesh line a primitive asked for while it was being built – a CPW’s slot edges are the only case today – is passed through as a fixed line, so it lands exactly where the primitive needs it rather than wherever the automatic passes would have put it.
- Parameters:
smooth_ratio (float, optional) – Maximum ratio between adjacent mesh cells. Default
1.5.- Return type:
None
- create_microstrip(name: str = 'microstrip', *, position: tuple[float, float], width_mm: float, length_mm: float, z_elevation_mm: float | None = None, copper_thickness_mm: float | None = None, rotation: float = 0, priority: int = 6) CSPrimitives#
Create a straight rectangular microstrip trace.
positionis the midpoint of the input edge, so the trace starts exactly there and butts flush against whatever precedes it. In the unrotated frame it runs+y, spanningx = cx +/- width_mm/2andy = cy .. cy + length_mm; the output edge – where the next primitive starts – is the midpoint ofy = cy + length_mmbeforerotationis applied.- Parameters:
name (str, optional) – Name of the CSXCAD property the trace is added to, e.g.
"feed"– one per trace, so each piece is its own part in the viewer and in the STEP and Gerber exports. Default"microstrip".position (tuple[float, float]) –
(x, y)midpoint of the input edge, in the unrotated frame.width_mm (float) – Trace width, across the direction of travel.
length_mm (float) – Trace length along y, in the unrotated frame.
z_elevation_mm (float | None, optional) – Z position of the trace’s bottom face. Defaults to the substrate’s top face.
copper_thickness_mm (float | None, optional) – Trace thickness along z. Defaults to
params.copper_thickness_mm.rotation (float, optional) – Rotation in degrees, counter-clockwise about
position. Default0.priority (int, optional) – CSXCAD priority of the primitive; where primitives overlap, the higher priority wins. Default
6.
- Returns:
The trace primitive.
- Return type:
CSPrimitives
- create_miter(name: str = 'miter', *, position: tuple[float, float], width_mm: float, miter_distance_mm: float, z_elevation_mm: float | None = None, copper_thickness_mm: float | None = None, rotation: float = 0, turn: str = 'left', priority: int = 6) CSPrimitives#
Create a 90-degree mitered bend.
The primitive is the square corner block that joins two
width_mm-wide arms; the arms themselves are separate (seecreate_microstrip).positionis the midpoint of the input edge, so the block sits wholly beyond it and butts flush against the end of the incoming arm rather than straddling it. In the unrotated frame the arm arrives travelling+y, the block spansy = cy .. cy + width_mm, the outgoing arm leaves through the-xedge with its centre line atposition + (-width_mm/2, +width_mm/2), and the outer corner is(+hw, cy + width_mm).rotationis degrees CCW aboutposition, which keeps the join flush at any angle.turnis the handedness of the bend as seen by a wave travelling along the incoming arm:"left"exits to the arm’s left (-xatrotation=0),"right"to its right (+x). The two are mirror images, sorotationalone cannot swap them; being defined relative to the direction of travel,turnkeeps its meaning at anyrotation.miter_distance_mmis the cutback from the outer corner along each edge, in the same units aswidth_mm, and must lie in[0, width_mm]. It maps to the usual miter percentage asM = miter_distance_mm / (2*width_mm)—M = 0is an unmitered square,M = 0.5cuts the full diagonal (a triangle).- Parameters:
name (str, optional) – Name of the CSXCAD property the miter is added to. Default
"miter".position (tuple[float, float]) –
(x, y)midpoint of the input edge, in the unrotated frame.width_mm (float) – Width of the arms joined by the miter.
miter_distance_mm (float) – Cutback from the outer corner, in
[0, width_mm].z_elevation_mm (float | None, optional) – Z position of the miter’s bottom face. Defaults to the substrate’s top face.
copper_thickness_mm (float | None, optional) – Miter thickness along z. Defaults to
params.copper_thickness_mm.rotation (float, optional) – Rotation in degrees, counter-clockwise about
position. Default0.turn (str, optional) – Bend handedness,
"left"or"right". Default"left".priority (int, optional) – CSXCAD priority of the primitive; where primitives overlap, the higher priority wins. Default
6.
- Returns:
The miter primitive.
- Return type:
CSPrimitives
- Raises:
ValueError – If
miter_distance_mmlies outside[0, width_mm], orturnis neither"left"nor"right".
- static create_nf2ff(sim: SimSetup | None = None) nf2ff#
Create the near-field-to-far-field (NF2FF) recording box.
- Parameters:
sim (SimSetup, optional) – Simulation setup named tuple returned by
setup_simulation. Omit for the standalone STEP-FEM workflow (simulate_step_FEM), which has noSimSetup–Nonealways returns aFEMNF2FFadapter.- Returns:
nf2ff – NF2FF object. For the FEM backend (or when
simis omitted) this is aFEMNF2FFadapter that exposes the sameCalcNF2FFinterface, so the radiation-plotting methods work identically for both backends.- Return type:
object
- create_radial_stub(name: str = 'radial_stub', *, position: tuple[float, float], inner_radius_mm: float, outer_radius_mm: float, angle_start: float, angle_end: float, z_elevation_mm: float | None = None, copper_thickness_mm: float | None = None, rotation: float = 0, num_segments: int = 60, priority: int = 6) CSPrimitives#
Create a radial (fan-shaped) stub.
positionis the midpoint of the stub’s neck (its flat inner edge), so the copper starts exactly there.angle_start/angle_endare in degrees, measured from+x, and set the fan opening; the fan points along their bisector, androtationturns the whole fan a further amount CCW aboutposition. Withhalf_spanhalf the opening, the neck is2*inner_radius_mm*sin(half_span)wide and the stub reachesouter_radius_mm - inner_radius_mm*cos(half_span)radially beyondposition.- Parameters:
name (str, optional) – Name of the CSXCAD property the stub is added to. Default
"radial_stub".position (tuple[float, float]) –
(x, y)midpoint of the stub’s neck, in the unrotated frame.inner_radius_mm (float) – Radii of the fan’s inner (neck) and outer edges.
outer_radius_mm (float) – Radii of the fan’s inner (neck) and outer edges.
angle_start (float) – Fan opening bounds, in degrees, measured from
+x.angle_end (float) – Fan opening bounds, in degrees, measured from
+x.z_elevation_mm (float | None, optional) – Z position of the stub’s bottom face. Defaults to the substrate’s top face.
copper_thickness_mm (float | None, optional) – Stub thickness along z. Defaults to
params.copper_thickness_mm.rotation (float, optional) – Rotation in degrees, counter-clockwise about
position. Default0.num_segments (int, optional) – Number of polygon segments approximating the outer arc. Default
60.priority (int, optional) – CSXCAD priority of the primitive; where primitives overlap, the higher priority wins. Default
6.
- Returns:
The radial stub primitive.
- Return type:
CSPrimitives
- create_substrate(name: str = 'substrate', *, start: list[float] | None = None, stop: list[float] | None = None, eps_r: float | None = None, tand: float | None = None, main_freq: float | None = None, priority: int = 0) CSPrimitives#
Create a dielectric substrate from two corner points.
Also asks
create_mesh()forparams.substrate_cellsmesh lines through the thickness, since the field between a trace and the ground plane under it varies across exactly that region and the automatic mesher leaves a thin substrate with a single line in it.- Parameters:
name (str, optional) – Name of the CSXCAD property the substrate is added to. Default
"substrate".start (list[float] | None, optional) –
[x, y, z]opposite corners of the substrate box. Both default to the footprint inparams: the substrate width and length centred on the origin, fromz = 0to the substrate thickness.stop (list[float] | None, optional) –
[x, y, z]opposite corners of the substrate box. Both default to the footprint inparams: the substrate width and length centred on the origin, fromz = 0to the substrate thickness.eps_r (float | None, optional) – Relative permittivity. Defaults to
params.substrate_eps_r.tand (float | None, optional) – Loss tangent. Defaults to
params.substrate_tand.main_freq (float | None, optional) – Frequency in Hz used to convert
tandinto an equivalent conductivity (kappa). Defaults toparams.main_freq.priority (int, optional) – CSXCAD priority of the primitive; where primitives overlap, the higher priority wins. Default
0.
- Returns:
The substrate box primitive.
- Return type:
CSPrimitives
- create_taper(name: str = 'taper', *, position: tuple[float, float], width1_mm: float, width2_mm: float, length_mm: float, z_elevation_mm: float | None = None, copper_thickness_mm: float | None = None, rotation: float = 0, priority: int = 6) CSPrimitives#
Create a trapezoidal taper trace.
positionis the midpoint of the input edge, the onewidth1_mmwide, so the taper sits wholly beyond it and butts flush against the end of the incoming arm. In the unrotated frame the taper runs+y: it iswidth1_mmwide aty = cyandwidth2_mmwide aty = cy + length_mm, which is where the next primitive starts.- Parameters:
name (str, optional) – Name of the CSXCAD property the taper is added to. Default
"taper".position (tuple[float, float]) –
(x, y)midpoint of the input edge, in the unrotated frame.width1_mm (float) – Trace width at the input (
position) and output ends.width2_mm (float) – Trace width at the input (
position) and output ends.length_mm (float) – Taper length along y, in the unrotated frame.
z_elevation_mm (float | None, optional) – Z position of the trace’s bottom face. Defaults to the substrate’s top face.
copper_thickness_mm (float | None, optional) – Trace thickness along z. Defaults to
params.copper_thickness_mm.rotation (float, optional) – Rotation in degrees, counter-clockwise about
position. Default0.priority (int, optional) – CSXCAD priority of the primitive; where primitives overlap, the higher priority wins. Default
6.
- Returns:
The taper primitive.
- Return type:
CSPrimitives
- create_via(name: str = 'via', *, position: tuple[float, float], via_diameter_mm: float, z_bottom_mm: float, z_top_mm: float, antipad_diameter_mm: float | None = None, antipad_layers: list[float] | None = None, antipad_thickness_mm: float | None = None, antipad_eps_r: float | None = None, priority: int = 6, antipad_priority: int = 4) CSPrimitives#
Create a plated through-hole via as a solid conductor.
The barrel is a solid metal cylinder rather than a plated shell around a drilled hole. Copper’s skin depth is a fraction of a micron at these frequencies, so a plated wall and a solid barrel are the same conductor seen from outside, while the wall thickness would otherwise be a feature orders of magnitude finer than the requested mesh resolution – and the FDTD timestep follows the smallest cell in the grid.
No pad or annular ring is drawn; the barrel lands directly on whatever copper is already at its ends. Clearances are placed only at the elevations named in
antipad_layers, and each is a ring of dielectric – the substrate by default – with the same thickness as the copper layer it cuts through; a zero-thickness sheet has no volume for the grid to resolve and would not reliably clear the plane.The ring starts at the barrel wall and runs outwards to
antipad_diameter_mm, so it never overlaps the via. A solid disc would work in FDTD, where the barrel’s higher priority wins inside the hole, but the STEP export carries no priorities: the FEM path sees only the geometry, and a dielectric disc intersecting the metal barrel is an ambiguous solid for Gmsh to mesh. An annulus is unambiguous for both.- Parameters:
name (str, optional) – Name of the CSXCAD property the barrel is added to, e.g.
"short_via". Clearance discs go on"<name>_antipad". Default"via".position (tuple[float, float]) –
(x, y)centre of the via.via_diameter_mm (float) – Finished outer diameter of the conductor – the drill diameter plus twice the plating thickness, as a fab would state it.
z_bottom_mm (float) – Extent of the barrel along z.
z_top_mm (float) – Extent of the barrel along z.
antipad_diameter_mm (float | None) – Outer diameter of the clearance rings; their inner diameter is
via_diameter_mm. Required whenantipad_layersis given, and must exceedvia_diameter_mm. DefaultNone.antipad_layers (list[float] | None) – Elevations at which to place a clearance ring, each the bottom face of the copper layer being cleared. Default
None, no antipads.antipad_thickness_mm (float | None, optional) – Thickness of each clearance ring along z. Defaults to
params.copper_thickness_mm, i.e. the thickness of the plane it cuts.antipad_eps_r (float | None, optional) – Relative permittivity filling the clearance rings. Defaults to
params.substrate_eps_r(with its loss), which suits a plane buried in the stack-up. Pass1.0for a plane on an outer face, where the clearance opens to air.priority (int, optional) – CSXCAD priority of the barrel; where primitives overlap, the higher priority wins. Default
6.antipad_priority (int, optional) – CSXCAD priority of the clearance rings. Keep it above the plane being cleared so the ring wins over the copper it clears. Default
4.
- Returns:
The via barrel primitive.
- Return type:
CSPrimitives
- Raises:
ValueError – If
antipad_layersis given without anantipad_diameter_mm, or the antipad is no larger than the via.
- static export_csxcad_xml_to_step(structure_xml_path: str | Path, output_path: Path | None = None) None#
Load a
structure.xmlfile and export it to STEP AP242 format.Useful for re-exporting a structure to STEP without re-running the simulation, given a
structure.xmlpreviously written bywrite_and_show_structure.- Parameters:
structure_xml_path (str or Path) – Path to the
structure.xmlfile exported by CSXCAD / openEMS.output_path (Path, optional) – Directory to save the
stepsubdirectory under. Defaults tocwd / "Sim_Path".
- Return type:
None
- static export_gerber(sim: SimSetup, output_path: Path | None = None, options: dict[str, list] | None = None, prefix: str = 'layout') list[Path]#
Export CSXCAD geometry to Gerber format, one file per copper layer.
- Parameters:
sim (SimSetup) – Simulation setup named tuple returned by
setup_simulation.output_path (Path, optional) – Directory to save the
gerbersubdirectory under. Defaults tocwd / "Sim_Path".options (dict[str, list], optional) – Dictionary of export options. Supported key
"ignore": a list of property names to skip. Defaults to{}.prefix (str, optional) – File name prefix. Default
"layout".
- Returns:
The Gerber and drill files written.
- Return type:
list of Path
Notes
CSXCAD carries no layer information, so layers are inferred from the Z position of the metal: the highest metal is the top layer (
F_Cu), the lowest the bottom layer (B_Cu), and anything in between an inner layer. Z-axis cylinders (vias) are written to an Excellon drill file and the substrate footprint to the board outline. SeesimpleEMS.export_gerber.export_gerber().
- static export_step(sim: SimSetup, output_path: Path | None = None) None#
Export CSXCAD geometry to a colored, multi-layer STEP AP242 file using CadQuery.
- Parameters:
sim (SimSetup) – Simulation setup named tuple returned by
setup_simulation.output_path (Path, optional) – Directory to save the
stepsubdirectory under. Defaults tocwd / "Sim_Path".
- Return type:
None
- static export_stl(sim: SimSetup, output_path: Path | None = None) None#
Export the CSXCAD structure to STL files (FDTD backend only).
Reads the
structure.xmlpreviously written bywrite_and_show_structureand exports it to STL via AppCSXCAD.- Parameters:
output_path (Path, optional) – Directory containing
structure.xml. STL files are written to astlsubdirectory. Defaults tocwd / "Sim_Path".- Raises:
ValueError – If
structure.xmldoes not exist inoutput_path(i.e.write_and_show_structurewas not called first).
- static export_touchstone(freqs: ndarray[tuple[Any, ...], dtype[_ScalarT]], s11: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None, *, s21: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None, s_matrix: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None, charac_imp: float = 50.0, output_path: Path | None = None, filename: str = 's_param') Path#
Export S-parameters to a Touchstone
.sNpfile.Writes the provided S-parameter data to
output_path / "touchstone"in Touchstone version 1 format. Pass eithers11(pluss21for a two-port) or the fulls_matrix; the port count sets the file extension.- Parameters:
freqs (NDArray) – Frequency points (in Hz) to export.
s11 (NDArray, optional) – Complex S11 values across the frequency range. Required unless
s_matrixis given.s21 (NDArray, optional) – Complex S21 values across the frequency range. If provided, a two-port (
.s2p) network is written; otherwise a single-port (.s1p) network is written. Default isNone.s_matrix (NDArray, optional) – Complex S-parameters of shape
(F, P, P), withs_matrix[:, i, j]holding S(i+1)(j+1). Writes every S-parameter of aP-port network. Cannot be combined withs11ors21. Default isNone.charac_imp (float, optional) – Reference impedance (in ohms) recorded in the Touchstone file. Default is
50.0.output_path (Path, optional) – Directory to save the
touchstonesubdirectory under. Defaults tocwd / "Sim_Path".filename (str, optional) – Base name of the exported file (extension is added automatically). Default is
"s_param".
- Returns:
Path of the written Touchstone file.
- Return type:
Path
- Raises:
ValueError – If neither
s11nors_matrixis given, or ifs_matrixis combined withs11/s21.
Notes
With
s11ands21, only S11 and S21 are populated; S12 and S22 are written as zero (the reverse-direction parameters are not simulated). Passs_matrixto export all of them.
- static plot_2d_directivity(nf2ff: nf2ff, freq: float, output_path: Path | None = None, read_cached: bool = False) None#
Plot the 2D directivity pattern (xz-plane, phi=0) at a specified frequency, annotated with the half-power beamwidth (HPBW).
Computes directivity (in dBi) from NF2FF E-field data, plots it as a polar pattern, and marks the -3 dB beamwidth, main-lobe direction, and peak magnitude around the pattern’s maximum.
- Parameters:
nf2ff (object) – The near-field-to-far-field (NF2FF) object containing the simulation data.
freq (float) – Frequency (in Hz) at which the directivity is evaluated. Must be a scalar.
output_path (Path, optional) – Path to the directory where the simulation result is saved. Defaults to
cwd / "Sim_Path".read_cached (bool, optional) – If True, read cached NF2FF results instead of re-computing. Default is False.
- Returns:
Plots the 2D directivity pattern; does not return a value.
- Return type:
None
- Raises:
TypeError – If
freqis not a scalar (e.g. an array of frequencies).ValueError – If the -3 dB HPBW crossings cannot be found on either side of the peak.
- static plot_2d_rad_pattern(nf2ff: nf2ff, freq: float, output_path: Path | None = None, read_cached: bool = False) None#
Plot the 2D E-field radiation pattern at a specified frequency.
Computes far-field E-field cuts in the xz-plane (phi=0) and xy-plane (theta=90) from NF2FF data and plots both as normalized polar patterns (in dB) side by side.
- Parameters:
nf2ff (object) – The near-field-to-far-field (NF2FF) object containing the simulation data.
freq (float) – Frequency (in Hz) at which the radiation pattern is evaluated. Must be a scalar.
output_path (Path, optional) – Path to the directory where the simulation result is saved. Defaults to
cwd / "Sim_Path".read_cached (bool, optional) – If True, read cached NF2FF results instead of re-computing. Default is False.
- Returns:
Generates the 2D radiation pattern plot; does not return a value.
- Return type:
None
- Raises:
TypeError – If
freqis not a scalar (e.g. an array of frequencies).
- static plot_3d_directivity(nf2ff_3d_result: nf2ff_results, freq: float, output_path: Path | None = None) None#
Plot the 3D directivity pattern of an antenna at a specified frequency.
Visualizes the directivity pattern (in dBi) of the antenna in 3D space, based on the far-field results from
compute_nf2ff_3d, and saves the mesh as a VTK file underoutput_path / "3D_plots".- Parameters:
nf2ff_3d_result (nf2ff_results) – The 3D far-field result object returned by
compute_nf2ff_3d.freq (float) – The frequency (in Hz) at which the 3D directivity pattern is evaluated. Must be a scalar; used only for plot/file labeling.
output_path (Path, optional) – Path to the directory where the simulation result is saved. Defaults to
cwd / "Sim_Path".
- Returns:
Opens an interactive 3D plot window and saves the mesh to
3D_plots/3D_directivity.vtk; does not return a value.- Return type:
None
- Raises:
TypeError – If
freqis not a scalar (e.g. an array of frequencies).
- static plot_3d_gain(nf2ff_3d_result: nf2ff_results, freq: float, input_power: float, output_path: Path | None = None) None#
Plot the 3D gain pattern of an antenna at a specified frequency.
Visualizes the realized gain pattern (in dBi) of the antenna in 3D space: gain is directivity (from
compute_nf2ff_3d) scaled by the radiation efficiencyPrad / input_power. Saves the mesh underoutput_path / "3D_plots".- Parameters:
nf2ff_3d_result (nf2ff_results) – The 3D far-field result object returned by
compute_nf2ff_3d.freq (float) – The frequency (in Hz) the pattern was computed at. Used only for plot/file labeling.
input_power (float) – Input power at the port (same units as
Prad), used to normalize directivity into realized gain.output_path (Path, optional) – Path to the directory where the simulation result is saved. Defaults to
cwd / "Sim_Path".
- Returns:
Opens an interactive 3D plot window and saves the mesh to
3D_plots/3D_Gain.vtk; does not return a value.- Return type:
None
- static plot_3d_power(nf2ff_3d_result: nf2ff_results, freq: float, output_path: Path | None = None) None#
Plot the 3D radiated power pattern of an antenna at a specified frequency.
Visualizes the normalized radiated power pattern (in dB) of the antenna in 3D space, based on the
P_radfield of the far-field results fromcompute_nf2ff_3d. Saves the mesh underoutput_path / "3D_plots".- Parameters:
nf2ff_3d_result (nf2ff_results) – The 3D far-field result object returned by
compute_nf2ff_3d.freq (float) – The frequency (in Hz) the pattern was computed at. Used only for plot/file labeling.
output_path (Path, optional) – Path to the directory where the simulation result is saved. Defaults to
cwd / "Sim_Path".
- Returns:
Opens an interactive 3D plot window and saves the mesh to
3D_plots/3D_Power.vtk; does not return a value.- Return type:
None
- static plot_group_delay(freqs: ndarray[tuple[Any, ...], dtype[_ScalarT]], s21: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None, x_label: str = 'Frequency', y_label: str = 'Group Delay', title: str = 'Group Delay vs Frequency') None#
Compute and plot the group delay as a function of frequency.
The group delay is computed from the frequency derivative of the unwrapped phase of S21 and displayed in seconds (via an engineering time-unit axis formatter).
- Parameters:
freqs (NDArray) – A 1D array of frequencies (in Hz) to plot on the x-axis.
s21 (NDArray) – A 1D array of complex S21 values corresponding to each frequency.
x_label (str, optional) – Label for the x-axis. Default is
"Frequency".y_label (str, optional) – Label for the y-axis. Default is
"Group Delay".title (str, optional) – Title of the plot. Default is
"Group Delay vs Frequency".
- Returns:
Displays the group delay plot in a new figure; does not return a value.
- Return type:
None
- static plot_impedance(freqs: ndarray[tuple[Any, ...], dtype[_ScalarT]], z11: ndarray[tuple[Any, ...], dtype[_ScalarT]], x_label: str = 'Frequency', y_label: str = 'Z11', title: str = 'Z11 vs Frequency') None#
Plot the input impedance (Z11) as a function of frequency.
Opens a new figure and plots the real and imaginary parts of Z11, in ohms, as separate traces over the given frequency range.
- Parameters:
freqs (NDArray) – A 1D array of frequencies (in Hz) to plot on the x-axis.
z11 (NDArray) – A 1D array of complex Z11 values (in ohms) corresponding to each frequency.
x_label (str, optional) – Label for the x-axis. Default is
"Frequency".y_label (str, optional) – Label for the y-axis. Default is
"Z11".title (str, optional) – Title of the plot. Default is
"Z11 vs Frequency".
- Returns:
Displays the impedance plot in a new figure; does not return a value.
- Return type:
None
- static plot_phase(freqs: ndarray[tuple[Any, ...], dtype[_ScalarT]], s21: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None, x_label: str = 'Frequency', y_label: str = 'Phase (deg)', title: str = 'Phase vs Frequency') None#
Plot the transmission phase (angle of S21) as a function of frequency.
Opens a new figure and plots the phase of S21, in degrees, over the given frequency range.
- Parameters:
freqs (NDArray) – A 1D array of frequencies (in Hz) to plot on the x-axis.
s21 (NDArray) – A 1D array of complex S21 values corresponding to each frequency.
x_label (str, optional) – Label for the x-axis. Default is
"Frequency".y_label (str, optional) – Label for the y-axis. Default is
"Phase (deg)".title (str, optional) – Title of the plot. Default is
"Phase vs Frequency".
- Returns:
Displays the phase plot in a new figure; does not return a value.
- Return type:
None
- static plot_s_param(freqs: ndarray[tuple[Any, ...], dtype[_ScalarT]], s11: ndarray[tuple[Any, ...], dtype[_ScalarT]], s21: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None, x_label: str = 'Frequency', y_label: str = 'S-parameter (dB)', title: str = 'S-parameters vs Frequency', label_s11: str | None = None, label_s21: str | None = None) None#
Plot S-parameters (S11 and optionally S21) against frequency.
Draws onto the current matplotlib axes (call
plt.figure()beforehand to start a new figure). Boths11ands21are expected as complex/linear values; they are converted to dB (20*log10(|.|)) internally before plotting.- Parameters:
freqs (NDArray) – A 1D array of frequencies (in Hz) to plot on the x-axis.
s11 (NDArray) – A 1D array of complex (linear) S11 values.
s21 (NDArray, optional) – A 1D array of complex (linear) S21 values for two-port networks. If
None(default), only S11 is plotted.x_label (str, optional) – Label for the x-axis. Default is
"Frequency".y_label (str, optional) – Label for the y-axis. Default is
"S-parameter (dB)".title (str, optional) – Title of the plot. Default is
"S-parameters vs Frequency".label_s11 (str, optional) – Legend label for the S11 trace. Defaults to
"S11".label_s21 (str, optional) – Legend label for the S21 trace. Defaults to
"S21".
- Returns:
Draws the plot on the current axes; does not return a value.
- Return type:
None
- static plot_smith_chart(freqs: ndarray[tuple[Any, ...], dtype[_ScalarT]], s11: ndarray[tuple[Any, ...], dtype[_ScalarT]], label: str = '', charac_imp: float = 50.0) None#
Plot S11 data on a Smith chart.
Opens a new figure with a Smith-chart projection and plots the complex reflection coefficient (S11) over the given frequency range, marking the value at the midpoint frequency.
- Parameters:
freqs (NDArray) – A 1D array of frequencies (in Hz) corresponding to the S11 data.
s11 (NDArray) – A 1D array of complex S11 (reflection coefficient) values.
label (str, optional) – Label used for the plot legend. Default is an empty string.
charac_imp (float, optional) – Characteristic (normalizing) impedance of the chart, in ohms. Default is
50.0.
- Returns:
Displays the Smith chart in a new figure; does not return a value.
- Return type:
None
Notes
pysmithchart is used to render the Smith chart.
- static plot_vswr(freqs: ndarray[tuple[Any, ...], dtype[_ScalarT]], vswr: ndarray[tuple[Any, ...], dtype[_ScalarT]], x_label: str = 'Frequency', y_label: str = 'VSWR', label: str = 'VSWR', title: str = 'VSWR vs Frequency') None#
Plot the voltage standing wave ratio (VSWR) as a function of frequency.
Opens a new figure and plots VSWR over the given frequency range, to evaluate impedance matching performance.
- Parameters:
freqs (NDArray) – A 1D array of frequencies (in Hz) to plot on the x-axis.
vswr (NDArray) – A 1D array of VSWR values corresponding to each frequency.
x_label (str, optional) – Label for the x-axis. Default is
"Frequency".y_label (str, optional) – Label for the y-axis. Default is
"VSWR".label (str, optional) – Label used for the plot legend. Default is
"VSWR".title (str, optional) – Title of the plot. Default is
"VSWR vs Frequency".
- Returns:
Displays the VSWR plot in a new figure; does not return a value.
- Return type:
None
- static print_and_save_params(params: SimParams, output_path: Path | None = None) None#
Print the simulation parameters to the console and save them to
params/params.txt.- Parameters:
params (SimParams) – Parameter object whose dataclass fields are printed and saved.
output_path (Path, optional) – Directory to save the
paramssubdirectory under. Defaults tocwd / "Sim_Path".
- Returns:
Does not return a value.
- Return type:
None
- static run_simulation(sim: SimSetup, output_path: Path | None = None) None#
Run the simulation and write results to
output_path.Dispatches to the FDTD engine (
FDTD.Run) or, for the FEM backend, to the adaptive GetDP frequency sweep (fem_backend.run_sweep), which performs up tosim.FEM_options.num_solve_pointsfull solves. For the FEM backend this always (re-)meshes first, reusing the existing mesh ifsim.CSX/sim.FEM_optionshaven’t changed since the last mesh in thisoutput_path(e.g. a priorwrite_and_show_structurecall) and rebuilding if they have – so a sweep/optimize loop that calls this directly, varying the geometry across iterations into the sameoutput_path, still gets a fresh mesh each time the geometry actually changes.- Parameters:
sim (SimSetup) – Simulation setup named tuple returned by
setup_simulation.output_path (Path, optional) – Directory to write simulation results to. Defaults to
cwd / "Sim_Path".
- static save_plots(output_path: Path | None = None, file_format: str = 'png') None#
Save all currently open matplotlib figures to
output_path / "plots".Each open figure is resized to 12x6 inches and saved as
plot_<n>.<file_format>, in figure order.- Parameters:
output_path (Path, optional) – Directory to save the
plotssubdirectory under. Defaults tocwd / "Sim_Path".file_format (str, optional) – File format to save the plots as (e.g.
"png","jpg","pdf"). Default is"png".
- Return type:
None
Notes
Call this before
show_plots, sinceshow_plotsblocks until the plot windows are closed.
- static show_plots() None#
Display all generated plots. Blocks until the plot window(s) are closed.
If no matplotlib figures are open and a Qt application instance is already running (e.g. a PyVista/FEM mesh viewer opened by
write_and_show_structure), blocks on that Qt event loop instead and exits the process once it closes. Otherwise callsmatplotlib.pyplot.show()to display any open matplotlib figures.- Returns:
Does not return a value.
- Return type:
None
- static write_and_show_structure(sim: SimSetup, output_path: Path | None = None, mesh_style: str = 'wireframe', theme: str | None = None) None#
Display the simulation geometry.
For the FDTD backend this opens the structure in AppCSXCAD. For the FEM backend it (re-)meshes the current
CSX/FEM_optionswith Gmsh – reusing the existing mesh instead of rebuilding if neither has changed since the last call on thisoutput_path– and renders it with PyVista, coloring cells by their Gmsh physical-group id.- Parameters:
sim (SimSetup) – Simulation setup named tuple returned by
setup_simulation.output_path (Path, optional) – Directory to write/read the structure XML (FDTD) or mesh files (FEM). Defaults to
cwd / "Sim_Path", created if missing.mesh_style (str) – FEM mesh only. PyVista
add_meshrepresentation:"surface","wireframe"(default), or"points". Mesh cells are colored by their Gmsh physical-group id (CellEntityIds: dielectric, PEC, port, absorbing boundary, …).theme (str, optional) – FEM mesh only.
None(default) keeps the active simpleEMS theme (seesimpleEMS.plot_theme.use_dark_theme()). A PyVista theme name –"dark","default","document"or"paraview"– is applied globally viapyvista.set_plot_theme().
- Raises:
ValueError – If
themeis not one of PyVista’s native theme names.