{"id":39915624,"url":"https://github.com/antmicro/gerber2ems","last_synced_at":"2026-01-27T05:00:57.022Z","repository":{"id":210213550,"uuid":"719551090","full_name":"antmicro/gerber2ems","owner":"antmicro","description":"Python interface to OpenEMS,  for PCB trace simulation. Accepts Gerber files as input. Features automatic grid generation and postprocessing.","archived":false,"fork":false,"pushed_at":"2026-01-20T13:45:32.000Z","size":15763,"stargazers_count":195,"open_issues_count":8,"forks_count":26,"subscribers_count":18,"default_branch":"main","last_synced_at":"2026-01-20T22:19:51.055Z","etag":null,"topics":["electromagnetic-simulation","fdtd","gerber-files","openems","pcb-layout","s-parameters"],"latest_commit_sha":null,"homepage":"https://antmicro.com/blog/2025/07/recent-improvements-to-antmicros-signal-integrity-simulation-flow/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antmicro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-11-16T12:10:24.000Z","updated_at":"2026-01-20T13:45:36.000Z","dependencies_parsed_at":"2025-04-02T11:26:06.403Z","dependency_job_id":"8a47027c-433a-4a8f-9a0e-961a836e0f30","html_url":"https://github.com/antmicro/gerber2ems","commit_stats":null,"previous_names":["antmicro/gerber2ems"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/antmicro/gerber2ems","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antmicro%2Fgerber2ems","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antmicro%2Fgerber2ems/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antmicro%2Fgerber2ems/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antmicro%2Fgerber2ems/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antmicro","download_url":"https://codeload.github.com/antmicro/gerber2ems/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antmicro%2Fgerber2ems/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28803641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T03:44:14.111Z","status":"ssl_error","status_checked_at":"2026-01-27T03:43:33.507Z","response_time":168,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["electromagnetic-simulation","fdtd","gerber-files","openems","pcb-layout","s-parameters"],"created_at":"2026-01-18T17:00:28.233Z","updated_at":"2026-01-27T05:00:57.015Z","avatar_url":"https://github.com/antmicro.png","language":"Python","funding_links":[],"categories":["Tools"],"sub_categories":[],"readme":"# gerber2ems - openEMS simulation based on Gerber files\n\nCopyright (c) 2023-2025 [Antmicro](https://www.antmicro.com)\n\nThis project is a Python script that aims to streamline signal integrity simulations using open source tools.\nIt takes PCB production files as input (Gerber, drill files, stackup information) and simulates trace SI performance using [openEMS](https://github.com/thliebig/openEMS-Project/) - a free and open source electromagnetic field solver that uses the FDTD method.\n\n## Installation\n\n### [OpenEMS](https://www.openems.de/)\n\n\nInstall the following packages (on Debian/Ubuntu):\n\n```bash\nsudo apt update\nsudo apt install build-essential cmake git libhdf5-dev libvtk9-dev libboost-all-dev libcgal-dev libtinyxml-dev qtbase5-dev libvtk9-qt-dev cython3 pip\npip install --break-system-packages numpy scipy matplotlib h5py setuptools # Preferred as Debian installs old numpy version which often results in version conflicts\n```\n\nClone the repository, compile and install openEMS:\n\nIt is recommended to use the `bb991bb3` commit, as this is the latest one tested with gerber2ems.\n```bash\ngit clone https://github.com/thliebig/openEMS-Project.git\npushd ./openEMS-Project\ngit checkout bb991bb3\ngit submodule update --init --recursive\n./update_openEMS.sh ~/opt/openEMS --python\npopd\n```\n\n### Script installation\n\n1. Install the dependencies:\n```bash\nsudo apt install gerbv python3.11 pipx\npipx ensurepath\n```\n\n2. Clone and install gerber2ems\n```bash\ngit clone https://github.com/antmicro/gerber2ems.git\npushd ./gerber2ems\npipx install --system-site-packages .\npopd\n```\n\n\u003e [!NOTE]\n\u003e I you want to use `ems2paraview` command run also `sudo apt install paraview python3-paraview`.\n\nYou can test `gerber2ems` with built-in examples.\nThe examples are slices of our open hardware [Signal Integrity Test Board](https://openhardware.antmicro.com/boards/si-simulation-test-board/), which were generated using the [KiCad SI wrapper](https://github.com/antmicro/kicad-si-simulation-wrapper).\nSelected examples contain VNA measurements in dedicated vna.csv files, which allows us to compare openEMS simulation results with real life measurements.\n```bash\ncd ./gerber2ems/examples/stub_short\ngerber2ems -a\n```\n\n## Usage\n\nFor quick lookup, use `gerber2ems --help`.\n\nTo simulate a trace, follow these steps:\n\n* Prepare input files and put them in the `fab/` folder (described in detail in the [PCB Input File Preparation section](#pcb-input-files-preparation))\n* Prepare the config `simulation.json` file (described in detail in the [Config Preparation section](#config-preparation))\n* Run `gerber2ems -a` (process described in the [Geometry Creation section](#geometry-creation))\n* View the results in `ems/results` (described in detail in the [Results section](#results))\n* Run `gerber2ems -a --export-field` and use Paraview to view an animation of the E-field (described in detail in the [Paraview section](#paraview))\n\n## Results\n\nThe simulation output of the `stub_short` example is shown below.\nThis software returns the following types of output:\n\n### S-parameter and impedance data\n\nImpedance and S-parameter data gathered during the simulations, stored in CSV format with a header.\n\n### S-parameter chart\n\nPlot of each S-parameter measured during each excitation.\n\n![](./docs/images/S_x1.png)\n\n### Smith chart\n\nPlot of parameter S-11 for each excitation.\n\n![](./docs/images/S_11_smith.png)\n\n### Impedance chart\n\nPlot of each excited port vs. frequency.\n\n![](./docs/images/Z_1.png)\n\nThe `stub_short` example contains a `vna.csv` file, which can be used to verify simulation results.\n\n![](./docs/images/Z_ems+vna.png)\n\n## How it works\n\n### Project preparation\n\nSimulating an entire PCB is extremely resource-intensive, so it is important to separate a region of interest as small in size as possible - unneeded traces, pours etc., should be removed. \nIf entire layers are redundant, you can remove them in later steps.\n\nPorts of interest should be marked by a virtual component in positions files. Their designator should begin with \"SP\" and be followed by port number. \n\nOrigin point for drill files should be placed in bottom-left corner.\n\nEvery trace or pour that is somehow terminated in reality and will exist in the simulation should also be terminated using a simulation port or connected to ground.\n\nFor now, capacitors are not simulated and, for high frequency simulation, they can be aproximated by shorting them using a trace.\n\n### PCB input file preparation\n\nThis script requires multiple input files for geometry creation. \nThey should all reside in the \"fab\" folder and are listed below:\n\n* Gerber files - each simulated copper layer should have a corresponding Gerber file named in the following format: \"\\\u003coptional-text\\\u003e-\\\u003cname-from-stackup-file\\\u003e.gbr\"\n\n* Stackup file - a file describing the PCB stackup, named \"stackup.json\". \nExample format:\n\n    ```\n    {\n        \"layers\": [\n            {\n                \"name\": \"F.Cu\",\n                \"type\": \"copper\",\n                \"color\": null,\n                \"thickness\": 0.035,\n                \"material\": null,\n                \"epsilon\": null,\n                \"lossTangent\": null\n            },\n            {\n                \"name\": \"dielectric 1\",\n                \"type\": \"core\",\n                \"color\": null,\n                \"thickness\": 0.2,\n                \"material\": \"FR4\",\n                \"epsilon\": 4.5,\n                \"lossTangent\": 0.02\n            }\n        ],\n        \"format_version\": \"1.0\"\n    }\n    ```\n\n* Drill file - Drill file in excellon format with plated through-holes.\nFilename should end with \"-PTH.drl\"\n\n* Position file - File describing positions of ports.\n  * Filename should end with \"-pos.csv\"\n  * Coordinates should be given in relation to bottom left corner\n  * The area of the port is calculated using the formulas in the table below, based on the `Width` and `Length` values from the `simulation.json` file:\n\n    | Rotation [°] | `X` span                       | `Y` span                       | Wave travel direction |\n    | ------------ | ------------------------------ | ------------------------------ | --------------------- |\n    | 0            | `(PosX-Width/2, PosX+Width/2)` | `(PosY, PosY+Length)`          | Along `Y`             |\n    | 90           | `(PosX-Length, PosX)`          | `(PosY-Width/2, PosY+Width/2)` | Opposite to `X`       |\n    | 180          | `(PosX-Width/2, PosX+Width/2)` | `(PosY-Length, PosY)`          | Opposite to `Y`       |\n    | 270          | `(PosX, PosX+Length)`          | `(PosY-Width/2, PosY+Width/2)` | Along `X`             |\n\n  * Example file:\n\n    ```\n    # Ref     Val              Package                PosX       PosY       Rot  Side\n    SP1       Simulation_Port  Simulation_Port      3.0000    11.7500  180.0000  top\n    ```\n\n### Config preparation\n\nThe `simulation.json` file configures the entire simulation. \nYou can find sample files in the `example_gerbers` folder. \nAll dimensions in this file are specified in **micrometers**. \nThis config file consists of three sections:\n\n#### Miscellaneous\n\n* `format_version` - specifies the format of the config file\nWhen writing a new config, it should be the newest supported version (visible in the `constants.py` file)\n* `frequency` - `start` specifies the lowest frequency of interest and `stop` the highest (in Hz)\n* `max_steps` - max number of simulation steps after which the simulation will stop unconditionally\n* `pixel_size` - size of pixel in microns. Used during gerber conversion (default: 5) (due to a limitation of libcairo, this needs to be increased for larger boards, but try to keep as low as possible)\n* `via/plating_thickness` - via plating thickness (micrometers)\n* `via/filling_epsilon` - dielectric constant of the material the vias are filled in with\nIf they are not filled in, it should be 1\n\n#### Grid\n\n* `inter_layers` - number of grid lines in Z axis between neighboring PCB layers (default: 4)\n* `optimal` - basic mesh grid pitch (micrometers) (used for cells on metal edge) (default: 50)\n* `diagonal` - mesh grid pitch (micrometers) (used for regions with diagonal paths) (default: 50)\n* `perpendicular` - mesh grid pitch (micrometers) (used for regions with paths perpendicular to grid) (default: 200)\n* `max` - maximum mesh grid pitch (micrometers) (used outside of the board area) (default: 500)\n* `cell_ratio/xy` - optimal neighboring cell size ratio (X/Y axis) (default: 1.2)\n* `cell_ratio/xy` - optimal neighboring cell size ratio (Z axis) (default: 1.5)\n* `margin/xy` - margin size in X/Y axis (micrometers) (how far beyond pcb the grid spreads) (default: 1000)\n* `margin/z` - margin size in Z axis (micrometers) (default: 1000).\n* `margin/from_trace` - Limit simulation space based on nets-of-interest bounding box (default: True) (if False, board b-box is used).\n\nGrid pitch options should follow `optimal`\u003c=`diagonal`\u003c=`perpendicular`\u003c=`max`\u003c=`λmin/10`\n\n#### Ports\n\n`ports` is a list of ports. Each port has the following parameters:\n\n* `width` - width of the port (micrometers)\n* `length` - length of the port (ports are currently composed of microstripline fragments whose length should be at least 8x mesh cell size) (micrometers)\n* `impedance` - terminating impedance of the port (impedance of driver or receiver) (Ohms)\n* `layer` - the number of the copper layer where the port is located (counting from the top)\n* `plane` - the number of the copper layer where the reference plane of the microstrip is located (counting from the top)\n* `excite` - whether the simulator should use this port as an input port (for multiple excited ports, they will be excited in separate simulations).\n\n#### differential_pairs/traces\n\n`differential_pairs`/`traces` are lists of simulated signals. Each signal can have following fields:\n\n* `start_p`, `stop_p`, `start_n`, `stop_n` - port numbers used for signal (differential_pair)\n* `start`, `stop` - port numbers used for signal (single ended trace)\n* `name` - optional name that allows to identify the signal\n* `nets` - list of nets to be included during grid generation (e.g. `[\"/CSI_A_CLK_N\",\"/CSI_A_CLK_P\"]`). If not specified, data from `netinfo.json` file will be used. In case the file is also not present, all nets (except GND) will be considered during grid generation.  \n\n### Geometry creation\n\nThis is an automatic step commenced with the `-g` flag.\nThe script locates all the files needed for creating the geometry (Gerbers, drill files, pnp files, stackup file, simulation config file).\nThen it converts Gerber files to PNG using gerbv.\nThe PNG's are then processed into triangles and input into the geometry.\nThis also adds via geometries as well as port geometries.\nEverything is placed on correct Z heights using the stackup file.\n\nYou can view the generated geometry, which is saved to `ems/geometry/geometry.xml`, using AppCSXCAD (installed during openEMS installation).\n\n### Simulation\n\nThis is an automatic step commenced with the `-s` flag.\nThe script loads the geometry and config files. \nIt inputs all the information into the engine and starts the simulations, iterating over every excited port.\n\nAt this step, the user should verify if the indicated number of timesteps is sufficient. \nThe engine recommends that it should be at least 3x as long as the pulse:\n\n    ```\n    Excitation signal length is: 3211 timesteps (3.18343e-10s)\n    Max. number of timesteps: 10000 ( --\u003e 3.11429 * Excitation signal length)\n    ```\n\nThe simulator converts the geometry into voxels and starts solving Maxwell equations for each edge in the mesh.\nIt does that for a number of timesteps (maximum number specified in config) and then exits.\nFor each timestep, electric field data from planes between copper planes is saved to files in the `ems/simulation` folder. Port voltage and current data is also saved.\n\nDuring the simulation, one of the ports is excited using a gaussian pulse (wideband frequency content).\nThis pulse traverses the network and exits using ports (it can also get emitted outside the board). \n\nYou can monitor the simulation by looking at the engine output:\n\n    ```\n    [@ 20s] Timestep: 4620 || Speed:  294.4 MC/s (3.372e-03 s/TS) || Energy: ~4.16e-16 (- 7.15dB)\n    ```\nThis way you can see:\n* what timestep you are on\n* how many mesh voxels per second the simulator processes \n* how much energy is left in the system\n\nThe energy should drop during the simulation as it exits through the ports (after the excitation pulse ends), however due to inaccuracies and energy radiated it won't drop to 0.\n\nAfter the simulation finishes, the user can verify the data using `Paraview` (described in a [section below](#paraview)).\n\n### Postprocessing\n\nThis is an automatic step commenced with the `-p` flag.\nThe script loads simulation data for each excited port. \nIt then computes an FFT to get data in the frequency domain. \nIt then converts the incident and reflected wave data to impedance and S parameters. \nThese are saved in CSV format in the `ems/results/S-parameters` folder. \nThis data is also automatically plotted and the plots are saved to `ems/results`.\n\n## Paraview\n\nTo view simulation data in Paraview, follow these steps:\n\n* Run `gerber2ems -a --export-field \u003cdump locations\u003e`\n* Run `ems2paraview \u003cport\u003e`\n\n`\u003cport\u003e` is a simulated port number, defined in the `simulation.json`,\nto list all available ports use: `ems2paraview -l`\n\n`dump locations` can be skipped (dump at all possible locations), or you can choose one or more keywords from the following list:\n\n* `outer` - dump a field 100 um above the board surface\n* `cu-outer` - dump a field on the outer cooper Z-position\n* `cu-inner` - dump a field on the inner cooper Z-position\n* `substrate` - dump a field in the middle of each dielectric layer\n\n`--oversampling \u003cint num\u003e` - can be added to increase the frequency of exporting fields (normally OpenEMS dumps a field once per few hundreds timesteps) (`\u003cint num\u003e` defaults to 4)\n\n\u003e [!WARNING]  \n\u003e Field exports can easily take hundreds GB of storage\n\n## Animation\n\nTo generate an animation:\n\n1. Generate a PCB blend model (See [picknblend](https://antmicro.github.io/picknblend/quickstart.html))\n2. Run `gerber2ems` with the `--export-field` flag and increased oversampling (`--oversampling 16`) (See the [Paraview section](#paraview))\n3. Convert the generated `*.vtr` files to grayscale pngs (run `ems2png`)\n4. Open the PCB blend in `blender` and append [EMS_Plane](EMS_Plane.blend) (`File`\u003e\u003e`Append..`\u003e\u003e`EMS_Plane.blend/Object/EMS_Plane`)\n5. Set plane dimensions (it should be roughly the same as the slice size)\n6. Enter the `Shading` workspace\n7. In each texture node on the left, click the folder icon and select a png generated in the third step with the lowest number (e.g. `simulation_images/e_field_0_0000` for the first trace, `simulation_images/e_field_1_0000` for the second).\n8. If the animation should show only a single trace, substitute one texture node with an RGB node set to black\n9. On texture nodes, change source type from `Single Image` to `Image Sequence` and update the `Frames` field with the number of images generated for the corresponding trace\n10. Set view mode to `rendered` and position `EMS_Plane` just above the corresponding trace on the PCB texture (you may want to switch to a frame where the field is stronger and covers most of the trace)\n11. Select `EMS_Plane` and apply any type of keyframe on the first and last frame of the image sequence\n12. In `blendcfg.yaml` add a new preset:\n\n    ```yaml\n    ems_animation:\n    CAMERAS:\n        PHOTO1: true\n    POSITIONS:\n        TOP: true\n    RENDERER:\n        FPS: 25\n    SCENE:\n        RENDERED_OBJECT: Object/EMS_Plane\n    OUTPUTS:\n        - ANIMATION:\n    ```\n\n13. Run `pcbooth -b \u003cPCB_name\u003e.blend -c ems_animation`\n\nSample animation:\n\n| Top side                                             | Bottom side                                             |\n| ---------------------------------------------------- | ------------------------------------------------------- |\n| ![](./docs/images/EMS_Field_Propagation_CE7_Top.gif) | ![](./docs/images/EMS_Field_Propagation_CE7_Bottom.gif) |\n\n\u003e [!TIP]\n\u003e Consider creating a new blend file instead of simply using the output of `picknblend`. In this new file add the `picknblend` output as a linked blender model. This will allow you to reuse the base blender model for showing different trace simulations and will prevent accidental refresh by `gerber2blend`/`picknblend`.\n\n## Licensing\n\nThis project is published under the [Apache-2.0](LICENSE) license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantmicro%2Fgerber2ems","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantmicro%2Fgerber2ems","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantmicro%2Fgerber2ems/lists"}