OpenEMS

OpenEMS PCB Simulation Guide

1 Introduction

This guide provides a practical, step-by-step approach to running 3D electromagnetic PCB simulations using open-source software. Instead of focusing purely on complex theory, this document is highly visual and workflow-oriented. It will take you from a basic 2D board layout all the way to advanced field visualization, giving you the tools to analyze, troubleshoot, and perfect your high-frequency designs with confidence. The workflow and methodology detailed in these steps are directly adapted from the excellent YouTube tutorial available at the video below.

2 Guide to PCB Simulation with OpenEMS

Before diving into the step-by-step simulation, you will need to set up your digital workspace. Because this workflow relies heavily on a chain of open-source software, making sure you have the right tools installed is crucial for a smooth process.

First, you will need a completed board design saved as a .kicad_pcb file, which is typically created in KiCad. For the 3D modeling and simulation setup, you will be using FreeCAD. It is essential that FreeCAD has the custom OpenEMS macro installed and configured beforehand. The heavy mathematical lifting is performed by the OpenEMS FDTD engine itself, which comes bundled with AppCSXCAD for geometry validation. 

Finally, to render and animate the resulting electromagnetic fields, you will need ParaView. Once you have these programs installed and your PCB file ready, you are all set to begin.

Launch FreeCAD and start with a new, empty document to ensure a clean workspace for the simulation setup. 

    Figure 1 – Initial FreeCAD workspace

    Navigate to the Macro menu and run the FreeCAD-OpenEMS-Export.FCMacro script. This bridges FreeCAD with the OpenEMS simulation engine.

    Figure 2 – Executing the OpenEMS export macro

    The OpenEMS Simulation Creator window will open. This interface acts as the central hub for assigning materials, configuring the grid, and setting up simulation parameters. 

    Figure 3 – The OpenEMS Simulation Creator UI

    Click the “KiCAD PCB Import Tool” button. Select your .kicad_pcb layout file and ensure “Fuse coppers” is checked so the tool properly generates vias between layers.

    Figure 4 – KiCAD PCB import tool

    The tool will read the KiCAD data, populating the “FreeCAD Object List” with individual structural components like outlines, pads, and copper areas. 

    Figure 5 – Loaded 2D board components

    Keep an eye on the FreeCAD Report view at the bottom of the screen. The tool handles complex operations in the background to build the 3D geometry. Wait until the log explicitly displays the message “all done” to confirm the process has finished successfully.

    Figure 6 – Generation process in the Report view

    The 3D viewport will now display the fully generated physical representation of the PCB, including the dielectric substrate and copper traces.

    Figure 7 – Fully generated 3D PCB model

    In the Combo View, expand the coppers_fuse feature and drag the individual copper layers out into the main project root. Hide the original coppers_fuse object by selecting it and pressing the Spacebar. Finally, select the board and both extracted copper layers, and apply the “Convert to solid” command to ensure the simulation engine treats them as true 3D volumes rather than hollow surfaces.

    Figure 8 – Reorganizing the imported object tree

    To establish the computational domain, you must manually create a solid box that represents the surrounding “air”. Set the dimensions of this box so that it extends exactly 5 mm beyond the PCB geometry on all sides. This ensures the model is completely enclosed and defines the physical limits for the electromagnetic simulation space.

    Figure 9 – Establishing the air volume

    To establish the computational domain, you must manually create a solid box that represents the surrounding “air”. Set the dimensions of this box so that it extends exactly 5 mm beyond the PCB geometry on all sides. This ensures the model is completely enclosed and defines the physical limits for the electromagnetic simulation space.

    Figure 10 – Simplified logical object tree

    To set up the measurement areas, rename the previously created air001 and air002 objects to efield and hfield, respectively. By repurposing these duplicated volume boxes, you establish the exact spatial volumes where the electric and magnetic fields will be recorded during the simulation.

    Figure 11 – Adding E-field and H-field probe volumes

    In the properties panel, adjust the dimensions for both the efield and hfield boxes. While leaving the length and width as they are, change the height of both objects to exactly 0.50 mm.

    Figure 12 – Setting height for the E-field and H-field probes

    In the 3D view, carefully adjust the placement of the efield box along the Z-axis. Position the box so that it sits directly between the top copper layer and the bottom ground layer. Placing the probe inside the dielectric substrate ensures it accurately captures the electromagnetic fields propagating between the traces.

    Figure 13 – Aligning the efield probe vertically with top and bottom layer

    Next, focus on the placement of the hfield box. Using a close-up view, carefully position it along the Z-axis so that it sits exactly 100.00 μm directly below the efield. This precise vertical offset is crucial for accurately capturing the magnetic field distribution in relation to the electric field.

    Figure 14 – Verifying the 100 μm vertical distance between the efield and hfield probes

    Creating the Input Port add a new primitive object named portin to represent the physical location where the signal will be injected.

    Figure 15 – Adding the input port geometry

    Input the exact dimensions and spatial coordinates for the portin box using the Geometric Primitives tool. It is crucial to set the height of this box to match the exact thickness of the PCB substrate (e.g., 1.58 mm).
    Visually verify in the 3D view that the portin box perfectly overlaps the starting pad of the copper transmission line. More importantly, ensure the port spans the entire vertical gap between the bottom ground plane and the top copper trace, as this physical connection is necessary to inject the signal correctly (Figure – 16 and Figure – 17).

    Figure 16 – Setting the dimensions of the input port to match the substrate thickness

    Figure 17 – Aligning the port to bridge the gap between the ground plane and the top trace

    In the Simulation Creator, switch to Grid Settings and define a general coarse mesh (xyz) with a fixed distance for the overall domain (Figure 18). Add a finer grid setting (xyfine) with a much smaller resolution to accurately capture the detailed geometry of the copper traces (Figure 19). Create a Z-axis specific grid (zfine) using a fixed count method. This ensures the mesh correctly captures extremely thin vertical layers like the copper plating (Figure 20).

    Figure 18 – Setting up the coarse XYZ mesh

    Figure 19 – Creating a fine XY mesh for traces

    Figure 20 – Defining specific mesh layers for the Z-axis

    In Material Settings, review the default PEC material (Figure 21). It will be used for perfectly conducting reference planes like the ground. Create a new metal material named copper to represent the physical characteristics of the PCB traces (Figure 22). Define an air material with an Epsilon and Mue of 1.0 to simulate the vacuum surrounding the board (Figure 23). Add an fr4 material and set its Epsilon (relative permittivity) to match standard dielectric substrate properties (e.g., 4.60) (Figure 24).

    Figure 21 – Default Perfect Electric Conductor (PEC) material

    Figure 22 – Creating the copper material

    Figure 23 – Defining vacuum/air properties

    Figure 24 – Setting the FR4 substrate permittivity

    Configure the input signal as a Gaussian pulse (gauss), specifying the target center frequency and cutoff parameters for the bandwidth you want to test (Figure 25). Under Port Settings, map your portin object as a lumped port. Assign it a 50 Ohm resistance, select the correct excitation axis, and set the field amplitude (Figure 26). Set up the field probes to output data by selecting “Et Dump” for the efield object and “Ht Dump” for the hfield object (Figure 27a and Figure 27b).Navigate to the Simulation Params tab to establish the stopping criteria for the FDTD solver. Set the max timesteps to 100000 and the min decrement to 0.01 (-20.0 dB). Additionally, apply Perfectly Matched Layers (PML) with 8 cells to all spatial boundaries (xmin, xmax, ymin, ymax, zmin, zmax). These PML boundaries act as absorbers for outgoing electromagnetic waves, preventing unwanted artificial reflections from bouncing back into your model (Figure 28).

    Figure 25 – Configuring the Gaussian excitation pulse

    Figure 26 – Setting resistance and amplitude for the lumped port

    Figure 27a – Configuring the electric field dump

    Figure 27b – Configuring the magnetic field dump

    Figure 28 – Applying Perfectly Matched Layer (PML) boundaries

    Return to the Object Assignments tab to map your raw FreeCAD objects to the defined materials, grids, and ports (e.g., assign trace to copper). It is absolutely critical that the list of assignments is ordered exactly as shown in Figure 29. In OpenEMS, this top-to-bottom order dictates the material priority where 3D objects overlap. Matching this exact sequence ensures the simulation geometry is layered and calculated correctly without material conflicts.

    Figure 29 – Assigning objects to materials and grids

    Click “Save Settings” and save the simulation configuration as an .ini file.

    Figure 30 – Saving the configuration file

    Now, Click “Generate OpenEMS Files” and FreeCAD will display a prompt confirming that the main Python execution script has been successfully written to your directory.

    Figure 31 – Script generation confirmation

    Check your project folder. You will find the _openEMS.py script alongside .stl files representing the meshed 3D objects (Figure – 32). Open the generated _openEMS.py script in a standard text editor to make necessary manual adjustments before running (Figure – 33). 

    Figure 32 – Output directory with python script and STL files

    Figure 33 – Opening the Python script for manual editing

    Find the line in the code where the FDTD solver is initialized with time steps and end criteria (Figure – 34). Add the OverSampling=100 argument to the FDTD initialization line. This dramatically improves mathematical stability during the run (Figure – 35).

    Figure 34 – Locating the FDTD initialization variables

    Figure 35 – Adding the OverSampling argument for stability

    Scroll down to the probe configuration section and locate a typo: dumnp_type (Figure – 36). Fix the typo by renaming it to dump_type and save the script (Figure – 37).

    Figure 36 – Identifying the dumnp_type typo in the generated code

    Figure 37 – Correcting the typo to dump_type

    Now, double-click the Python script file _openEMS.py. Assuming Python is properly configured on your system, this action will automatically launch a terminal window and begin executing the simulation sequence.

    Figure 38 – Double-clicking the Python script to automatically launch the simulation

    The script will first launch AppCSXCAD. Use this tool to verify the 3D geometry, material mappings, and mesh integrity before committing to heavy calculations (Figure – 39). In AppCSXCAD, toggle the visibility of dielectric materials like air and FR4 to easily inspect the alignment of the conductive elements (Figure – 40 and Figure – 41).

    Figure 39 – AppCSXCAD geometry validation interface

    Figure 40 – Managing material visibility in the property tree

    Figure 41 – Isolating conductive elements for inspection

    Switch to a 2D planar view. Ensure the mesh lines properly align with the edges of the copper traces to guarantee accurate boundary calculations (Figure – 42). View the board from the side to confirm that the thin vertical layers perfectly fit within the designated Z-axis grid lines (Figure – 43 and Figure – 44).

    Figure 42 – Validating the 2D mesh alignment against geometry

    Figure 43 – Checking Z-axis grid boundaries

    Figure 44 – Ensuring proper mesh density on thin layers

    Close AppCSXCAD to proceed. The command prompt will initialize the FDTD operator and calculate the necessary material data (Figure – 45). Once initialized, the solver begins processing the timesteps, providing a live continuous log in the terminal. This log displays the current timestep, the calculation speed in MegaCells per second (MC/s), and the changing energy levels within the computational domain  (Figure – 46 and Figure – 47).

    Figure 45 – Terminal output during FDTD initialization

    Figure 46 – Terminal confirmation of loaded materials and properties

    Figure 47 – Terminal log monitoring the timestep progress, simulation speed, and system energy

    Once calculations are complete, open ParaView and load the output data. At early timesteps, you will observe the initial electric field injection at the lumped port (Figure – 48). Advance the timeline in ParaView to analyze how the electromagnetic wave propagates along the transmission line and behaves around bends (Figure – 49). Load the magnetic field data to evaluate the H-field distribution, allowing you to identify potential radiation or crosstalk issues around the active trace (Figure 50).

    Figure 48 – Early-stage E-field visualization in ParaView

    Figure 49 – E-field wave propagation along the trace

    Figure 50 – H-field distribution at a specific timestep

    3 Conclusion

    This open-source workflow provides a powerful, cost-free method for 3D PCB simulation. Personally, while installing the OpenEMS macro was challenging, successfully visualizing the electromagnetic fields in ParaView made the effort entirely worthwhile.

    The main limitation is software compatibility: this process relies on FreeCAD 0.19, which only supports older KiCAD 6 files. Overcoming this to support newer KiCAD versions will require further investigation into updated tools or export scripts.

    Our next step is to resolve these version issues and demonstrate two practical examples, a properly designed trace versus a poorly routed one, to show exactly how to analyze and minimize unwanted electromagnetic emissions.

    Emina Imširović

    Emina Imširović

    Junior Electronic Engineer

    A Junior Electronic Engineer with hands-on experience in the complete hardware development lifecycle, from schematic and PCB design to circuit testing and assembly. She is experienced at antenna adjustments and independently researching and implementing practical electronic solutions to meet project needs

    Semblie is a hardware and software development company based in Europe. We believe that great products emerge from ideas that solve real-world problems.