csemx Quickstart
A plain-language guide to assembling your first csemx bundle.
This guide is non-normative: it explains, but it does not rule. The full rules live in the specification. If anything here seems to disagree with the specification, the specification wins.
Who this is for
You are a contractor or data provider who has been asked to deliver frequency-domain CSEM data as a csemx bundle. You do not need to be a programmer, and you do not need to install anything to follow this guide. By the end you should know what goes in each file and be able to start filling them in with your own survey.
What a bundle is
A csemx bundle is a single file named like mysurvey.csemx.zip. It is an
ordinary ZIP archive — the same kind of ZIP file every operating system can
open. Inside the ZIP is one folder (its name is your choice, using only
letters, digits, _, ., and -), and inside that folder sit six core
files:
manifest.yaml— a short text file stating the survey-wide facts every reader needs: survey name, contractor, acquisition dates, coordinate system, and sign convention.tx.csv— one row for each transmitter element, saying what kind of source it is.tx_vertices.csv— the surveyed positions (easting, northing, elevation) that trace each transmitter on the ground.rx.csv— one row for each receiver element, saying what kind of sensor it is.rx_vertices.csv— the surveyed positions that place each receiver.data.csv— the measurements: one row per measured value, tied to one transmitter, one receiver, and one frequency.
A bundle may additionally contain:
groups.csv— optional labels that collect stations into named lines, arrays, or other groupings.notes.md— an optional free-text file where you describe the survey in your own words: instruments, processing history, anything a colleague should know.- Parquet equivalents — any table may be delivered as a
.parquetfile instead of.csv(for exampledata.parquet). Parquet is a compressed binary format used for very large tables. If you are assembling a bundle by hand, use CSV.
Laid out as a file tree:
mysurvey/
├── manifest.yaml
├── tx.csv
├── tx_vertices.csv
├── rx.csv
├── rx_vertices.csv
├── data.csv
├── groups.csv (optional)
└── notes.md (optional)
That is the whole format. The rest of this guide walks through a small example of every file.
Before you start: a warning about spreadsheets
Before entering data in Excel or similar software, format all station-ID and component-ID columns as text. Otherwise values such as
001may be changed to1, and long identifiers may be reformatted or converted to scientific notation. Export tables as UTF-8 comma-delimited CSV files.
After exporting, reopen the exported CSV file in a plain-text editor (Notepad, TextEdit in plain-text mode, or similar) — not in the spreadsheet program — and check:
- Leading zeros are still there: a station ID
001has not become1. - No identifier has been converted to a date or to scientific notation.
- Decimal values use a period (
1465.50), not a comma. - The column names in the header row are unchanged.
- Optional values you left blank are still blank — nothing has filled in
0,NA, or anything else.
Spreadsheets are a fine way to assemble the tables if you follow these steps. A plain-text editor avoids the problem entirely.
A small example survey
The rest of this guide uses one tiny synthetic survey:
- One transmitter station
TX01with a single grounded-wire source, componentE1: a 400 m cable with an electrode at each end. - Receiver station
001with two sensors: an electric dipoleEx(two electrodes 100 m apart) and a vertical magnetic coilBz. - Receiver station
002with one electric dipoleEx. - Measurements at two frequencies, 0.5 Hz and 2 Hz.
All values are synthetic. Every excerpt below is complete and consistent: you can trace any station or component ID from one table to the next.
manifest.yaml
format:
name: csemx
version: "0.2"
domain: frequency
survey:
name: "Quickstart Example"
revision: 1
acquired_start: "2026-06-10"
acquired_end: "2026-06-12"
contractor: "Example Geophysics Ltd"
contractor_reference: "EG-2026-042"
coordinate_system:
epsg_horizontal: 32612
elevation:
epsg_vertical: 4979
sign:
time_dependence: "exp(+iwt)"
In plain terms:
formatanddomain— write these exactly as shown for a version 0.2 bundle.survey— your survey name, your company name, and your job or contract reference.revisionstarts at 1 and goes up by one each time you re-ship a corrected delivery. The acquisition dates are written in quotes; use either two plain dates or two full UTC timestamps, not a mixture.coordinate_system.epsg_horizontal— the EPSG code of the projected map grid (in meters) used for every easting and northing in the bundle. Here32612means WGS84 / UTM zone 12N. Your surveyor or processor will know the right code.elevation.epsg_vertical— the EPSG code defining what “elevation” means.4979is GPS (ellipsoidal) height, the recommended choice;3855is height above sea level (EGM2008 geoid).sign.time_dependence— the phase sign convention used in processing, written exactly asexp(+iwt)orexp(-iwt). Ask whoever processed the data; it is not a guess.
The full rules for the manifest are in specification §4.
tx.csv
One row per transmitter element:
tx_station_id,tx_component_id,geometry_type
TX01,E1,wire
tx_station_idandtx_component_idtogether name this element. A station can hold several elements (for example two crossed cables), each with its own component ID.geometry_typeiswire(an electric-dipole cable),loop(a closed loop), orpoint(a small coil treated as an oriented point).
A wire’s position and direction come entirely from its vertices (next file),
so no other columns are needed here. A point transmitter would additionally
need azimuth_deg, dip_deg, and point_moment_area_m2 columns for its coil
axis and area — see specification §5.
tx_vertices.csv
The surveyed points that trace each transmitter:
tx_station_id,tx_component_id,vertex_index,easting,northing,elev
TX01,E1,0,551000.00,3625000.00,1478.00
TX01,E1,1,551400.00,3625000.00,1481.00
- The first two columns repeat the element’s IDs from
tx.csv, spelled identically. vertex_indexcounts 0, 1, 2, … along the element. A wire needs at least two vertices, a loop at least three, a point exactly one.eastingandnorthingare map-grid coordinates in meters;elevis height in meters, positive up.- Vertex order carries meaning: for a wire transmitter the first vertex is the negative electrode and the last is the positive electrode (specification §3.4). List the points in the order that matches your wiring.
rx.csv
One row per receiver element:
rx_station_id,rx_component_id,geometry_type,azimuth_deg,dip_deg
001,Ex,wire,,
001,Bz,point,0,90
002,Ex,wire,,
- Station
001has two elements; station002has one. - The electric dipoles are
wirerows. Their orientation comes from their vertices, soazimuth_deganddip_degare left blank — a blank cell means “not applicable”, and that is fine. - The magnetic coil
Bzis apointrow, so it needs its axis: azimuth 0°, dip 90° means the coil axis points straight down. - Names like
ExandBzare conventional labels, but the format never reads direction from a name — geometry always comes from the vertex positions or the azimuth/dip values (specification §3.9).
rx_vertices.csv
rx_station_id,rx_component_id,vertex_index,easting,northing,elev
001,Ex,0,552000.00,3625000.00,1466.00
001,Ex,1,552100.00,3625000.00,1465.00
001,Bz,0,552050.00,3625000.00,1465.50
002,Ex,0,552400.00,3625000.00,1459.00
002,Ex,1,552500.00,3625000.00,1458.00
- Each electric dipole has two vertices; for a wire receiver the first vertex is the voltmeter’s positive terminal (specification §3.4).
- The point coil
Bzhas exactly one vertex.
data.csv
One row per measured value:
tx_station_id,tx_component_id,rx_station_id,rx_component_id,frequency,real,imag,err_real,err_imag
TX01,E1,001,Ex,0.5,4.6e-7,-6.2e-8,1.1e-8,1.0e-8
TX01,E1,001,Ex,2,3.1e-7,-1.4e-7,1.3e-8,1.2e-8
TX01,E1,001,Bz,0.5,8.2e-12,-1.5e-12,3.0e-13,2.8e-13
TX01,E1,002,Ex,0.5,9.4e-8,-1.8e-8,4.0e-9,3.8e-9
TX01,E1,002,Ex,2,NaN,NaN,NaN,NaN
- The first four columns say which transmitter and which receiver produced the measurement, using the same IDs as the tables above.
frequencyis in hertz and is greater than zero (exactly0is reserved for DC data — specification §3.12).realandimagare the two parts of one complex measurement, normalized by transmitter current;err_realanderr_imagare their uncertainties (zero or positive). If your processing does not produce uncertainties, writeNaNin both error columns — never invent numbers to fill them. The measurement unit is fixed by the receiver type — volts per amp for wires and loops, tesla per amp for point coils (specification §3.6) — so no unit column is ever written.- The last row shows a missing measurement: it was attempted but produced
no usable result, so all four measurement values are
NaN(“not a number”).realandimaggo missing together, and so doerr_realanderr_imag— never fill in one of a pair without the other, and never leave them blank. - No two rows may repeat the same transmitter + receiver + frequency combination.
How the tables connect
Every table is linked by the same simple idea: matching ID columns.
Take the transmitter. The row TX01,E1,wire in tx.csv declares that the
element exists. The two rows in tx_vertices.csv that also say TX01,E1
place it on the ground. And every row of data.csv that says TX01,E1
records a measurement made with it. The same pattern connects rx.csv,
rx_vertices.csv, and data.csv through the receiver IDs — trace 001 and
Ex through the excerpts above and you will cross three files.
For this to work, IDs must match exactly, character for character. TX01
and tx01 are different. 001 and 1 are different — which is why the
spreadsheet warning above matters so much. IDs use only letters, digits, _,
and -, and they are text, not numbers.
In database language, a column whose values must match another table is called a foreign key (see the glossary). You do not need the term to build a bundle — you only need the IDs to line up.
Optional: groups.csv
If your stations are organized into survey lines, arrays, or other named
collections, you can record that in groups.csv. Using the same stations as
above, one survey line containing the transmitter and both receivers:
group_kind,group_id,element_kind,station_id,component_id,sequence
line,L100,tx,TX01,,0
line,L100,rx,001,,0
line,L100,rx,002,,1
group_kindnames the kind of grouping (lineis the one kind defined by the specification;arrayis recommended; other names are yours to choose).element_kindsays whether the row refers to a transmitter (tx) or receiver (rx) station, andstation_idmust matchtx.csvorrx.csvaccordingly.- A blank
component_idmeans the whole station belongs to the group; fill it in to include only one component. sequencegives the order along a line, counted separately for transmitters and receivers. Leave it blank if the order is unknown.
Grouping is purely descriptive — it never changes what a measurement means (specification §10). If you have no useful groupings, omit the file.
Packing the ZIP
Put every file in one folder (for example mysurvey/), then compress that
folder into a ZIP archive using your operating system’s built-in “compress”
feature, and name the result mysurvey.csemx.zip. The ZIP must contain the
folder itself at the top level — not the loose files.
Checking your work
You do not need validation software to inspect or begin creating a csemx bundle. The files are ordinary YAML, CSV, Markdown, or Parquet files. Producers should validate completed bundles before delivery.
There are three levels of support:
1. Manual inspection. Open the files in a plain-text editor and check them yourself. The most valuable checks:
- The header row of each table spells the column names exactly as the
specification does: lower-case, with underscores (
tx_station_id, notTX Station ID). - Every transmitter named in
data.csv(its station ID + component ID pair) has a row intx.csvand positions intx_vertices.csv; every receiver likewise inrx.csvandrx_vertices.csv. IDs match exactly, including leading zeros and letter case. - No station + component pair appears twice in
tx.csvorrx.csv, and no twodata.csvrows share the same transmitter + receiver + frequency. - Vertex counts are right: exactly 1 for a point, at least 2 for a wire, at
least 3 for a loop, with
vertex_indexcounting 0, 1, 2, … for each element. - In
data.csv,realandimagare either both filled or bothNaNin each row, and likewiseerr_realanderr_imag— never blank, and never one of a pair without the other. A missing measurement has all fourNaN; a filled measurement may haveNaNerrors only when no uncertainties were produced. - Blank cells appear only in optional or not-applicable fields;
NaNappears only in the four measurement columns.
2. First-bundle assistance. If you are preparing your first csemx delivery, you can send a draft bundle to the project feedback address, csemx@deepbluegeophysics.com, and ask for it to be checked. The Feedback section of the repository README lists the other feedback channels and how comments are handled.
3. Standalone validator (planned). After v1.0, the project plans a standalone validator: a single downloadable program for Windows, macOS, and Linux that checks a bundle and lists any problems, with nothing else to install. Until then, the repository also ships a Python-based validator for those who use Python (see the README), but it is not required to produce a correct bundle.
Glossary
- bundle — the whole delivery: one folder of csemx files packed into a
.csemx.ziparchive. - manifest — the
manifest.yamlfile: the bundle’s cover sheet, stating survey-wide facts such as the coordinate system and sign convention. - table — data arranged in rows and columns, stored as a CSV or Parquet
file.
tx.csvanddata.csvabove are tables. - row and column — a row is one record (one transmitter element, one
measurement); a column is one named field every row can fill in (such as
easting). The first line of a CSV file names the columns. - datum — one measured value. In csemx, the complex response in one row
of
data.csv: itsrealandimagparts together. - component — one individual source or sensor element at a station, named
by a component ID such as
E1,Ex, orBz. Station001in therx.csvexample above has two components. - foreign key — a column whose values must match values in another table.
tx_station_idindata.csvis a foreign key: every value in it must also appear intx.csv(see “How the tables connect” above). - unique key — the column, or combination of columns, that no two rows of
a table may share. In
rx.csvthe pairrx_station_id+rx_component_idis the unique key: each element is listed once. - normative — binding. A normative rule in the specification must be followed for a bundle to be valid.
- non-normative — explanatory only. This quickstart is non-normative: it helps you read the rules but never replaces them.
- required — must be present and filled in (said of a file, column, or value).
- optional — may be left out entirely, or left blank where it does not
apply — like
azimuth_degfor the wire rows in therx.csvexample. - validator — software that checks a finished bundle against the specification’s rules and reports any problems.
- extension column — an extra, producer-defined column whose name starts
with
ext_(for exampleext_grid_x). It carries your own additional information; standard readers are free to ignore it.
Where to go next
- The specification — the full, normative rules, including a larger worked example (§13) with loop and borehole geometries.
- The example bundles — complete small bundles you
can open, inspect, and copy from, including a fill-in template bundle
(
examples/template.csemx/) with pre-headed tables and a manifest whose every key is explained in comments. - The rationale — why the format is designed the way it is.