Transfer Functions And Tipper Diagnostics#
The transfer-function tools in pycsamt.emtools focus on the
vertical-field response, usually called the tipper. The tipper relates
the vertical magnetic field to the horizontal magnetic field:
Hz = Tx Hx + Ty Hy
where Tx and Ty are complex, frequency-dependent transfer
functions. When the subsurface is laterally uniform, the vertical field
is weak. When current is channelled by lateral conductors or sharp
resistivity contrasts, the tipper grows and induction arrows become one
of the fastest qualitative diagnostics for conductor position, strike,
and period-dependent structure.
This page covers two related workflows:
Workflow |
Main tools |
Purpose |
|---|---|---|
EDI or |
|
Work from assembled transfer functions, usually EDI files. |
Spectra-direct tipper diagnostics |
|
Work from spectral estimates before a final EDI has been written. |
All public functions used below are exported from pycsamt.emtools,
so the examples use the two-level import style.
Use A Dataset With Tipper#
Many AMT/CSAMT data sets contain only horizontal electric and magnetic
channels. Those files can have valid impedance but no vertical magnetic
transfer function. The tipper functions will then return graceful
"no tipper" messages.
For induction-vector work, first verify that the selected survey really has tipper data. The bundled KAP03 long-period MT profile is useful for examples because it includes vertical-field measurements.
1from pathlib import Path
2
3from pycsamt.emtools import ensure_sites
4
5edi_dir = Path("data/MT/kap03lmt_edis")
6sites = ensure_sites(
7 edi_dir,
8 recursive=True,
9 on_dup="replace",
10 strict=False,
11 verbose=0,
12)
If a plot says "no tipper", check the data before changing plotting
options. Missing tipper is a data-content issue, not necessarily a
failed plot.
What The Tipper Stores#
For each station and frequency, pyCSAMT expects a two-component complex tipper:
Quantity |
Meaning |
|---|---|
|
Complex coefficient relating |
|
Complex coefficient relating |
|
In-phase part. Commonly used for Parkinson induction arrows. |
|
Quadrature part. Useful for checking frequency-dependent or inductive behavior that is out of phase with the horizontal field. |
|
Magnitude, often summarized as
|
You usually do not need to extract these arrays manually. The plotting functions read them from the site objects. Still, understanding the components helps interpret the figures.
Choose Periods And Bands#
Tipper diagnostics are strongly period-dependent. A station may be weak at short period, strong at mid-period, and weak again at long period. Choose periods and period bands deliberately.
1import numpy as np
2
3# Example period choices for a broad-band MT profile.
4periods = [25.0, 650.0, 2000.0, 17000.0]
5short_band = (25.0, 200.0)
6long_band = (2000.0, 17000.0)
7
8print("periods:", periods)
9print("short band:", short_band)
10print("long band:", long_band)
periods: [25.0, 650.0, 2000.0, 17000.0]
short band: (25.0, 200.0)
long band: (2000.0, 17000.0)
Use the same period choices across maps, roses, and sections when you want the figures to support one interpretation.
Single-Station Hodograms#
Start with plot_tipper_hodograms when inspecting one station. It
plots Tx and Ty in the complex plane, with colors split by period
band.
1import matplotlib.pyplot as plt
2
3from pycsamt.emtools import plot_tipper_hodograms
4
5fig = plot_tipper_hodograms(
6 sites,
7 station="kap151",
8 bands=[
9 (25.0, 200.0),
10 (200.0, 2000.0),
11 (2000.0, 17000.0),
12 ],
13 unit_circle=True,
14 normalize=False,
15)
16fig.savefig("tf_tipper_hodograms.png", dpi=200, bbox_inches="tight")
17plt.close(fig)
Read a hodogram before reading arrows. It shows whether a station has a smooth, coherent complex response or a scattered cloud. A large loop outside the unit circle can be real for strong 3-D/lateral induction; it is not automatically an error.
Set normalize=True only when comparing shape rather than amplitude.
For conductor-strength interpretation, keep the raw amplitude.
Single-Station Polar View#
plot_tipper_polar converts one station’s tipper into azimuth and
magnitude versus period. The polar angle is the tipper direction, radius
is magnitude, and color is log-period.
1import matplotlib.pyplot as plt
2
3from pycsamt.emtools import plot_tipper_polar
4
5ax = plot_tipper_polar(
6 sites,
7 station="kap151",
8 component="real",
9)
10ax.figure.savefig("tf_tipper_polar.png", dpi=200, bbox_inches="tight")
11plt.close(ax.figure)
Valid components are "real", "imag", and "abs". Use
"real" for a Parkinson-style conductor-direction reading, use
"imag" to inspect the quadrature response, and use "abs" when
you mainly care about magnitude.
Induction Map At One Period#
plot_induction_map draws real and imaginary induction arrows at a
single target period. The function picks the nearest available period
for each station.
1import matplotlib.pyplot as plt
2
3from pycsamt.emtools import plot_induction_map
4
5ax = plot_induction_map(
6 sites,
7 period=2000.0,
8 convention="park",
9 show_real=True,
10 show_imag=True,
11 scale=4.0,
12 station_labels=True,
13 reference_arrow=0.1,
14)
15ax.figure.savefig("tf_induction_map.png", dpi=200, bbox_inches="tight")
16plt.close(ax.figure)
The station coordinates come from easting/northing, x/y, or lon/lat when available. If none are present, pyCSAMT falls back to an index along a line. That fallback is still useful for a profile, but do not interpret the x-axis as real distance unless the source data contain real coordinates.
scale controls arrow length in plot coordinates. If arrows are too
small or overlap badly, adjust scale rather than changing the tipper
data.
Compare Several Periods On One Axis#
plot_induction_arrows overlays arrows from several requested periods
on one profile axis.
1import matplotlib.pyplot as plt
2
3from pycsamt.emtools import plot_induction_arrows
4
5ax = plot_induction_arrows(
6 sites,
7 periods=[25.0, 650.0, 2000.0, 17000.0],
8 convention="park",
9 scale=1.0,
10 normalize=True,
11 strike_ticks=False,
12)
13ax.figure.savefig("tf_induction_arrows.png", dpi=200, bbox_inches="tight")
14plt.close(ax.figure)
Use this for a fast period comparison, not as the final publication figure. Many periods on one axis can become visually crowded. If the period behavior matters, follow with a period section or a multi-period map.
Sign Conventions#
Induction-vector interpretation depends on convention. The two common views are Parkinson and Wiese. They are rotated relative to each other, so a figure can be misread if the convention is not stated.
plot_induction_convention puts Parkinson/Wiese and real/imaginary
components in one 2-by-2 figure.
1import matplotlib.pyplot as plt
2
3from pycsamt.emtools import plot_induction_convention
4
5plot_induction_convention(
6 sites,
7 period=650.0,
8 station_labels=False,
9)
10plt.gcf().savefig("tf_induction_convention.png", dpi=200, bbox_inches="tight")
11plt.close()
Use this plot when communicating with collaborators or comparing to a paper. It makes sign and component choices visible instead of leaving them implicit.
Period Pseudosection#
plot_induction_section shows tipper magnitude or component strength
over stations and period.
1import matplotlib.pyplot as plt
2
3from pycsamt.emtools import plot_induction_section
4
5ax = plot_induction_section(
6 sites,
7 component="abs",
8 n_periods=30,
9 cmap="RdBu_r",
10 section="pseudosection",
11)
12ax.figure.savefig("tf_induction_section.png", dpi=200, bbox_inches="tight")
13plt.close(ax.figure)
Use component="abs" for anomaly strength, "real" for in-phase
strength, and "imag" for quadrature strength. A section is the best
single view for answering: where along the line is the tipper strong,
and at what periods?
Induction Rose#
plot_induction_rose summarizes arrow azimuths over all stations and
selected periods.
1import matplotlib.pyplot as plt
2
3from pycsamt.emtools import plot_induction_rose
4
5ax = plot_induction_rose(
6 sites,
7 component="real",
8 pband=(25.0, 200.0),
9 nbins=36,
10 title="Short-period induction azimuths",
11)
12ax.figure.savefig("tf_induction_rose_short.png", dpi=200, bbox_inches="tight")
13plt.close(ax.figure)
14
15ax = plot_induction_rose(
16 sites,
17 component="real",
18 pband=(2000.0, 17000.0),
19 nbins=36,
20 title="Long-period induction azimuths",
21)
22ax.figure.savefig("tf_induction_rose_long.png", dpi=200, bbox_inches="tight")
23plt.close(ax.figure)
Compare short and long period roses before claiming a regional conductor. A short-period rose may be scattered because shallow heterogeneity points in many directions. A long-period rose that tightens into one sector can support a deeper, more coherent conductive structure.
Multi-Period Map#
plot_induction_multiperiod_map stacks one map panel per period and
is the most report-ready induction-vector figure. It can use real EDI
tipper, or an explicit tipper_data override.
1import matplotlib.pyplot as plt
2
3from pycsamt.emtools import plot_induction_multiperiod_map
4
5fig, axes = plot_induction_multiperiod_map(
6 sites,
7 periods=[25.0, 650.0, 2000.0, 17000.0],
8 convention="park",
9 arrow_scale=6.0,
10 reference_arrow=0.1,
11 show_background_cbar=False,
12 station_labels=False,
13 title="Induction vectors across period",
14)
15fig.savefig("tf_induction_multiperiod_map.png", dpi=200, bbox_inches="tight")
16plt.close(fig)
When background is not supplied, the function draws a synthetic
terrain-like background. That background is a visual placeholder, not a
real DEM. For a report, pass your own background and
background_extent.
The fallback EDI read path in this function can only use a single tipper
component in some situations. When you need full two-component vectors,
pass tipper_data explicitly as a dictionary keyed by period:
1import matplotlib.pyplot as plt
2import numpy as np
3
4# Each value is an array with shape (n_stations, 2):
5# column 0 is Tx, column 1 is Ty. Replace these synthetic
6# rows with processed Tx/Ty values from your own workflow.
7n_stations = 26
8tipper_data = {}
9for period, tx, ty in [
10 (25.0, 0.08 + 0.02j, 0.02 + 0.01j),
11 (650.0, 0.22 + 0.05j, 0.10 + 0.03j),
12 (2000.0, 0.16 + 0.03j, 0.18 + 0.04j),
13 (17000.0, 0.05 + 0.01j, 0.20 + 0.04j),
14]:
15 tipper_data[period] = np.tile(
16 np.array([[tx, ty]], dtype=complex),
17 (n_stations, 1),
18 )
19
20fig, axes = plot_induction_multiperiod_map(
21 sites,
22 periods=list(tipper_data),
23 tipper_data=tipper_data,
24 arrow_scale=6.0,
25 show_background_cbar=False,
26)
27fig.savefig(
28 "tf_induction_multiperiod_map_synthetic.png",
29 dpi=200,
30 bbox_inches="tight",
31)
32plt.close(fig)
The station order in each tipper_data array must match the station
order returned by ensure_sites for the input survey.
Spectra-Direct Workflows#
The spectra-direct helpers work before final EDI assembly. They expect
Spectra objects or dictionaries of spectra objects and recover the
tipper from spectral estimates.
Use these functions when your workflow is still at the spectra stage:
Function |
Use |
|---|---|
|
Draw real and imaginary induction arrows from one or more spectra objects. |
|
Inspect one spectra object’s tipper azimuth and magnitude. |
|
Summarize spectra-derived induction azimuths over a period band. |
1import matplotlib.pyplot as plt
2import numpy as np
3
4from pycsamt.emtools import (
5 plot_induction_map_from_spectra,
6 plot_induction_rose_from_spectra,
7 plot_tipper_polar_from_spectra,
8)
9from pycsamt.z.tipper import Tipper
10
11class SpectraWithTipper:
12 def __init__(self, name, tx_scale, ty_scale):
13 self.name = name
14 self.freq = np.array([0.1, 0.01, 0.001])
15 periods = 1.0 / self.freq
16 tx = tx_scale * (0.08 + 0.02j) * np.sqrt(periods / periods[0])
17 ty = ty_scale * (0.04 + 0.01j) * np.sqrt(periods / periods[0])
18 self._tipper = np.column_stack([tx, ty])
19
20 def to_Z(self, estimate_error=False):
21 tipper = Tipper(tipper_array=self._tipper, freq=self.freq)
22 return None, tipper
23
24spectra_by_station = {
25 "S001": SpectraWithTipper("S001", 1.0, 0.6),
26 "S002": SpectraWithTipper("S002", 1.4, 0.9),
27 "S003": SpectraWithTipper("S003", 0.8, 1.3),
28}
29
30coords = {
31 "S001": (0.0, 0.0),
32 "S002": (500.0, 0.0),
33 "S003": (1000.0, 0.0),
34}
35
36plot_induction_map_from_spectra(
37 spectra_by_station,
38 coords=coords,
39 period=100.0,
40)
41plt.gcf().savefig("tf_spectra_induction_map.png", dpi=200, bbox_inches="tight")
42plt.close()
43
44plot_tipper_polar_from_spectra(
45 {"S001": spectra_by_station["S001"]},
46 component="real",
47)
48plt.gcf().savefig("tf_spectra_tipper_polar.png", dpi=200, bbox_inches="tight")
49plt.close()
50
51plot_induction_rose_from_spectra(
52 spectra_by_station,
53 component="real",
54 pband=(10.0, 1000.0),
55)
56plt.gcf().savefig("tf_spectra_induction_rose.png", dpi=200, bbox_inches="tight")
57plt.close()
For spectra maps, coords are plot coordinates (x, y). A bare
Spectra object does not carry reliable map geometry.
Recommended Workflow#
A robust tipper interpretation keeps the raw station behavior, the period behavior, and the sign convention visible:
1from pathlib import Path
2
3import matplotlib.pyplot as plt
4
5from pycsamt.emtools import (
6 ensure_sites,
7 plot_induction_convention,
8 plot_induction_map,
9 plot_induction_multiperiod_map,
10 plot_induction_rose,
11 plot_induction_section,
12 plot_tipper_hodograms,
13 plot_tipper_polar,
14)
15
16sites = ensure_sites(
17 Path("data/MT/kap03lmt_edis"),
18 recursive=True,
19)
20
21strongest_station = "kap151"
22periods = [25.0, 650.0, 2000.0, 17000.0]
23
24plot_tipper_hodograms(
25 sites,
26 station=strongest_station,
27 bands=[(25.0, 200.0), (200.0, 2000.0), (2000.0, 17000.0)],
28).savefig("tf_recommended_hodograms.png", dpi=200, bbox_inches="tight")
29plt.close()
30
31ax = plot_tipper_polar(
32 sites,
33 station=strongest_station,
34 component="real",
35)
36ax.figure.savefig("tf_recommended_polar.png", dpi=200, bbox_inches="tight")
37plt.close(ax.figure)
38
39ax = plot_induction_map(
40 sites,
41 period=2000.0,
42 convention="park",
43 show_real=True,
44 show_imag=True,
45 scale=4.0,
46)
47ax.figure.savefig("tf_recommended_map.png", dpi=200, bbox_inches="tight")
48plt.close(ax.figure)
49
50plot_induction_convention(
51 sites,
52 period=650.0,
53 station_labels=False,
54)
55plt.gcf().savefig("tf_recommended_convention.png", dpi=200, bbox_inches="tight")
56plt.close()
57
58ax = plot_induction_rose(
59 sites,
60 component="real",
61 pband=(25.0, 200.0),
62 title="Short-period induction azimuths",
63)
64ax.figure.savefig("tf_recommended_rose_short.png", dpi=200, bbox_inches="tight")
65plt.close(ax.figure)
66
67ax = plot_induction_rose(
68 sites,
69 component="real",
70 pband=(2000.0, 17000.0),
71 title="Long-period induction azimuths",
72)
73ax.figure.savefig("tf_recommended_rose_long.png", dpi=200, bbox_inches="tight")
74plt.close(ax.figure)
75
76ax = plot_induction_section(
77 sites,
78 component="abs",
79 n_periods=30,
80)
81ax.figure.savefig("tf_recommended_section.png", dpi=200, bbox_inches="tight")
82plt.close(ax.figure)
83
84fig, axes = plot_induction_multiperiod_map(
85 sites,
86 periods=periods,
87 convention="park",
88 arrow_scale=6.0,
89 show_background_cbar=False,
90 station_labels=False,
91)
92fig.savefig(
93 "tf_recommended_multiperiod_map.png",
94 dpi=200,
95 bbox_inches="tight",
96)
97plt.close(fig)
This sequence answers the practical questions in order: which station is strong, whether its response is coherent, where the profile responds, which convention is being used, whether azimuths tighten with period, and how the anomaly migrates across period.
Common Pitfalls#
Do not use tipper tools on surveys without vertical-field data and then
interpret "no tipper" as a geological result.
Always state the sign convention. Parkinson and Wiese views are rotated relative to each other.
Do not interpret index-based map axes as geographic distance. If EDI coordinates are missing, the plots may fall back to station index.
Do not collapse all periods too early. A strong whole-band station may be strong only over a narrow period window.
Do not treat synthetic or placeholder backgrounds as real topography in multi-period maps. Pass a real background raster for publication.
Worked Example#
The gallery example uses the KAP03 MT profile with real tipper data. It moves from station-level hodograms and polar plots to maps, convention comparisons, roses, period sections, and a multi-period publication-style map.
Open the rendered gallery page here: Induction arrows and tipper diagnostics (pycsamt.emtools.tf).