Process reference: impa
Generated from the docstrings of vaft.process.impa:
14 public functions. Each entry is what
vaft.process.describe("impa.<name>") prints.
All process categories
Overview
The array is an insertable midplane probe carrying, at each of eight radial positions, a toroidal-field Hall sensor and a vertical-field sensor. The radial-field sensors are retired: the original design used them only to confirm the probe sat at the midplane, where the radial field is negligible.
The two sets play different roles [1]:
- the Hall channels establish where the array is. The toroidal field goes as one over the major radius, so measuring it against the known coil current gives each sensor’s radius, and the fitted spacing against the rigid as-built pitch gives the probe’s incident angle.
- they also establish how each vertical sensor is aligned. On an interval driven by the toroidal field alone the true vertical field is negligible, so whatever the vertical sensor reads there is crosstalk, and its ratio to the measured toroidal field is that sensor’s misalignment.
- the vertical sensors, once corrected for that crosstalk, carry the physics measurement: the toroidal current density from the radial gradient of the vertical field at the midplane.
Every routine here works on plain arrays, so the machine-specific parts –
raw field codes, shot-era geometry and thresholds – stay in
vaft.machine_mapping.impa and vest.yaml.
| Symbol | Meaning | Unit |
|---|---|---|
| B_meas | field a probe actually measures | T |
| Bt | vacuum toroidal field at a radius, mu0 N I / (2 pi R) | T |
| Bz | vertical field, after compensation | T |
| alpha | probe coupling to the toroidal field, sin of its tilt | - |
| beta | per-probe offset | T |
| kappa | the observable ratio alpha / R | 1/m |
| R0 | major radius of the innermost channel | m |
| I_TF | toroidal field coil current | A |
The measurement model. Each probe sees a mixture of the local poloidal field and the toroidal field::
B_meas_i(t) = alpha_i * Bt(R_i, t) + Bz_i(t) * sqrt(1 - alpha_i**2) + beta_i
Inverting it gives the compensated internal field::
Bz_i = (B_meas_i - alpha_i * Bt(R_i)) / sqrt(1 - alpha_i**2)
Sign. VAFT takes the coil current as the raw field times -3e4, as
vaft.machine_mapping.tf already does, together with a Hall gain of
-2/15 T/V. That is the “Data gain” on the array’s own wiring datasheet,
the authoritative hardware configuration, and it matches neither legacy
script exactly [2]. All three pairings give the same ratio of measured to
toroidal field up to an overall sign, so the fits here are sign-agnostic:
they detect the working polarity from the data rather than assuming a
positive coupling, and only the magnitude of the coupling carries physical
meaning. The shipped default carries that sign since #681 closed #624.
The datasheet leaves the vertical sensors’ own volts-to-tesla gain
unspecified, so those waveforms stay in native volts throughout; see
ImpaCrosstalkFit for what that means for the crosstalk angle.
Geometry and coupling are degenerate. During a toroidal-field-only
interval that field is the only driver, so a probe measures
alpha_i * mu0 * N * I_TF / (2 * pi * R_i) and only the ratio
kappa_i = alpha_i / R_i is observable. Assuming unit coupling yields the
radial position, which is the legacy method; a known radius yields the
coupling instead. The two cannot be recovered together from that data alone.
Geometry is per shot. The array is insertable and its radial position is
set per shot, so self-calibration from the shot’s own clean window is the
primary geometry source, not a fallback, and comparing fitted positions
between shots is meaningless because the probe really did move. A configured
radius in vest.yaml applies only to an era where the array was surveyed
or left fixed, and then takes precedence. A reference shot taken with the
array in the same position can supply the calibration for another, which is
the legacy two-shot arrangement; the single-shot path never requires it.
Functions
find_tf_calibration_window | Find the interval where the toroidal field alone drives the probes. Convention |
fit_impa_crosstalk | Fit the toroidal-field bleed into each vertical sensor. Convention |
fit_impa_geometry | Self-calibrate the array’s radial position from the toroidal-field profile. Convention |
fit_impa_tf_coupling | Fit each probe’s coupling to the toroidal field, at known radii. Convention |
grade_impa_quality | Grade whether an array’s measurements can be trusted, and say why not. Convention |
impa_calibrate_signals | Filter, scale and baseline raw probe records into field units. Convention |
impa_lowpass | Zero-phase low pass reproducing the legacy filter design. Convention |
legacy_impa_compensation | Faithful port of the legacy compensation script, at one time sample. Convention |
legacy_impa_position | Faithful port of the legacy position script, at one time sample. Convention |
process_impa | Run the whole array chain for one shot, from raw records to a graded result. Convention |
remove_bz_crosstalk | Subtract a vertical sensor’s toroidal crosstalk. Convention |
remove_tf_pickup | Recover the vertical field by removing a probe’s toroidal pickup. Convention |
toroidal_field | Vacuum toroidal field at a radius, from the coil current. Convention |
validate_impa | Deprecated compatibility wrapper for grade_impa_quality.
Deprecated |
No function matches.
find_tf_calibration_window
Machine-independentConvention-sensitive
source
find_tf_calibration_window(time, i_tf, ip=None, pf_currents=None, *, criteria=None, b_measured=None)
Find the interval where the toroidal field alone drives the probes.
Calibration needs a stretch of the same shot in which the coil is energised and nothing else is: no plasma current, no poloidal field. That interval is what makes the geometry and coupling fits meaningful, so this reports why it chose the one it did.
| Name | Type | Unit | Description |
|---|---|---|---|
time | array_like | s | Sample times. |
i_tf | array_like | A | Toroidal field coil current. |
ip | array_like, optional | A | Plasma current, used to exclude the discharge. |
pf_currents | array_like, optional | A | Poloidal field coil currents as |
criteria | TfWindowCriteria, optional | - | Thresholds the interval must satisfy. |
b_measured | array_like, optional | T | Conditioned probe records, used to require finite channels. |
| Returns | |||
| — | tuple | - | The chosen |
Convention
The chosen interval is the best-conditioned one, meaning the widest spread in coil current, rather than the longest. A long interval at nearly constant current constrains the fit poorly however many samples it holds, because the fit is a regression against that current.
Both an absolute floor and a fraction of the shot’s own peak are applied, because a shot can be energised weakly overall while still having a usable interval, and a fixed floor alone would either reject it or admit noise on a strong shot.
Processing steps · Defaults · Applicability · Limitations · Provenance
Processing steps
- Validate the time axis.
- Require the coil current above an absolute floor and above a fraction of the shot’s own peak.
- Exclude samples where the plasma current or any poloidal coil exceeds its limit, on median-filtered traces.
- Require every probe channel finite.
- Group what survives into contiguous runs and drop the too-short ones.
- Choose among the survivors by conditioning, not length.
Defaults
The thresholds are hard-coded: an absolute current floor, a fraction of peak, plasma and poloidal current limits, a minimum duration and a dynamic-range floor. The fraction of peak is a validated-workflow value distinguishing the reference shots from a weakly energised one; the rest have no recorded derivation. The median-filter width is an acquisition-era value, one millisecond at the array’s own rate. One configured threshold, the relative noise limit, is read by nothing at all, which is tracked in #625.
Applicability
Machine-independent. The thresholds arrive as an argument.
Limitations
Reasons are returned rather than raised, so a caller must read them: a window can be chosen and still be poor. Without the optional currents the corresponding exclusions simply do not happen, and an interval containing plasma can be selected.
Provenance
vest.yamlimpa.calibration_window, which carries the VEST thresholds and the evidence for the fraction-of-peak value.
fit_impa_crosstalk
Machine-independentConvention-sensitive
source
fit_impa_crosstalk(b_toroidal, b_z_raw, window, *, max_angle_deg=30.0, bz_gain=None)
Fit the toroidal-field bleed into each vertical sensor.
On an interval driven by the toroidal field alone the true vertical field is negligible, so whatever a vertical sensor reads there is crosstalk. Its ratio to the measured toroidal field is that sensor’s misalignment.
| Name | Type | Unit | Description |
|---|---|---|---|
b_toroidal | array_like | T | Toroidal field at each sensor. |
b_z_raw | array_like | V | Raw vertical-sensor records, in native units. |
window | TfCalibrationWindow | - | The toroidal-field-only interval. |
max_angle_deg | float, optional | deg | Largest misalignment still treated as physical. |
bz_gain | float, optional | T/V | Volts-to-tesla gain for the vertical sensors, if known. |
| Returns | |||
| — | ImpaCrosstalkFit | - | Per-sensor slope, offset and goodness of fit; the misalignment angle only when a gain was supplied. |
Convention
The slope is volts per tesla, not a dimensionless projection, because the wiring datasheet leaves the vertical sensors’ gain unspecified and those waveforms stay in volts. Without a gain the angle cannot be formed and is returned as NaN rather than silently wrong.
Defaults · Applicability · Limitations · Provenance
Defaults
The maximum angle is hard-coded with no recorded derivation.
Applicability
Machine-independent.
Limitations
Rests on the vertical field being negligible over the window, which is what makes the window selection load-bearing. A linear fit only: a sensor responding non-linearly keeps a residual.
Provenance
- Yang et al., Rev. Sci. Instrum. 85, 11D809 (2014), for the alignment role of the two sensor sets;
vest.yamlimpa.crosstalkfor the configured thresholds.
fit_impa_geometry
Machine-independentConvention-sensitive
source
fit_impa_geometry(b_measured, i_tf, window, *, pitch=0.05, z=0.0, turns=24, r0_initial=0.4, r_bounds=(0.1, 0.9), fit_pitch=False)
Self-calibrate the array’s radial position from the toroidal-field profile.
| Name | Type | Unit | Description |
|---|---|---|---|
b_measured | array_like | T | Conditioned probe records as |
i_tf | array_like | A | Toroidal field coil current. |
window | TfCalibrationWindow | - | The interval to fit over. |
pitch | float, optional | m | As-built spacing between channels. |
z | float, optional | m | Height of the array. |
turns | int, optional | - | Coil turns. |
r0_initial | float, optional | m | Starting guess for the innermost channel’s radius. |
r_bounds | tuple of float, optional | m | Bounds on that radius. |
fit_pitch | bool, optional | - | Whether to fit the spacing as well as the position. |
| Returns | |||
| — | ImpaGeometryFit | - | The fitted radii, the spacing, the incident angle and the residual statistics. |
Convention
This is the half of the degeneracy that assuming unit coupling resolves,
which is the legacy method: a rigid array of known spacing is slid along the
one-over-radius profile until it matches. The other half is
fit_impa_tf_coupling.
The coupling sign is detected, not assumed. The measured sign follows the configured Hall gain’s polarity, which this function has no reason to know. An incident angle of zero is a purely radial insertion in the midplane.
Processing steps · Defaults · Applicability · Limitations · Provenance
Processing steps
- Keep the channels finite across the window.
- Detect the working polarity from the data.
- Solve a bounded least squares for the innermost radius, and the spacing when asked.
- Form the residual and its normalized form.
- Recover the incident angle from the ratio of fitted to as-built spacing.
Defaults
The spacing is machine-specific, the array’s rigid as-built value. The
starting guess and the radial bounds are machine-specific too, spanning the
vessel. turns = 24 is the VEST coil.
Applicability
Machine-independent. Every machine number is an argument.
Limitations
Assumes the array is rigid and the coupling uniform, so a fitted position is meaningful only where the residual is small; the reference shots sit at 9 to 12 percent and the rejected ones at 34 to 35. Positions are not comparable between shots, because the array is insertable and really is repositioned.
Provenance
- The
vest_impa_positionmodel: uniform channel spacing and unit coupling, reproduced faithfully bylegacy_impa_position.
fit_impa_tf_coupling
Machine-independentConvention-sensitive
source
fit_impa_tf_coupling(b_measured, i_tf, r, window, *, turns=24, tilt_bounds_deg=(-10.0, 10.0))
Fit each probe’s coupling to the toroidal field, at known radii.
| Name | Type | Unit | Description |
|---|---|---|---|
b_measured | array_like | T | Conditioned probe records as |
i_tf | array_like | A | Toroidal field coil current. |
r | array_like | m | Major radius of each probe. |
window | TfCalibrationWindow | - | The interval to regress over. |
turns | int, optional | - | Coil turns. |
tilt_bounds_deg | tuple of float, optional | deg | Bounds on the probe tilt. |
| Returns | |||
| — | ImpaCouplingFit | - | Per-channel coupling and offset with their residual statistics. |
Convention
Regresses the measured field on the modelled toroidal field at the known
radius, giving the coupling as slope and the offset as intercept. This is the
half of the degeneracy that a known radius resolves; see
fit_impa_geometry for the other half. Only the magnitude of the
coupling carries meaning, since its sign follows the calibration polarity.
Defaults · Applicability · Limitations · Provenance
Defaults
turns = 24 is machine-specific. The tilt bounds are a legacy compatibility
value from a model that assumed a near-vertical probe, and they saturate on an
array that faces the toroidal field, which is the reference condition here.
Applicability
Machine-independent.
Limitations
Needs the radii, which on this array are usually themselves fitted, so the two must not be circular. The tilt bounds saturating is a signal that the model does not fit the array, not a result to use.
Provenance
- The measurement model in this module’s conventions.
grade_impa_quality
Machine-independentConvention-sensitive
source
grade_impa_quality(time, raw, b_measured, b_z, channel_valid, window, geometry, coupling, *, expected_channels=8, max_normalized_rmse=0.15, r_bounds=(0.1, 0.9), pitch_tolerance=0.01, window_reasons=(), orientation='toroidal', alpha_tolerance=0.15, crosstalk=None, min_crosstalk_r_squared=0.8)
Grade whether an array’s measurements can be trusted, and say why not.
| Name | Type | Unit | Description |
|---|---|---|---|
time | array_like | s | Sample times. |
raw | array_like | V | Raw probe records. |
b_measured | array_like | T | Conditioned probe records. |
b_z | array_like | T | Compensated vertical field. |
channel_valid | array_like | - | Which channels to consider. |
window | TfCalibrationWindow | - | The calibration interval that was used. |
geometry | ImpaGeometryFit | - | The fitted geometry. |
coupling | ImpaCouplingFit | - | The fitted coupling. |
expected_channels | int, optional | - | How many channels the array should have. |
max_normalized_rmse | float, optional | - | Largest geometry residual still acceptable. |
r_bounds | tuple of float, optional | m | Radial bounds the fit should sit inside. |
pitch_tolerance | float, optional | m | Largest departure of fitted from as-built spacing. |
window_reasons | sequence of str, optional | - | Reasons carried from the window selection. |
orientation | str, optional | - | Which field the array is taken to face. |
alpha_tolerance | float, optional | - | Largest departure of the coupling from unity. |
crosstalk | ImpaCrosstalkFit, optional | - | The crosstalk fit, when one was made. |
min_crosstalk_r_squared | float, optional | - | Smallest acceptable crosstalk goodness of fit. |
| Returns | |||
| — | ImpaQuality | - | A verdict of valid, warning or invalid, with the reasons behind it. |
Convention
The verdict is the worst of the checks, not an average, so one invalid check makes the result invalid however many pass. Reasons accumulate rather than short-circuiting, so a caller sees everything wrong at once.
Renamed from validate_impa under issue #337: this layer transforms and
infers, and grading sits uneasily here even so. The grading itself moves to
the validation layer under issue #339.
Processing steps · Defaults · Applicability · Limitations · Provenance
Processing steps
- Check the channels are present and the time axis usable.
- Check each channel’s own signal health, including railing.
- Check the calibration window, then the geometry, then the coupling.
- Check the compensated signal and the vertical sensors.
- Combine by taking the worst verdict.
Defaults
The residual, spacing, coupling and goodness-of-fit thresholds are
hard-coded, and two of them disagree with the values vest.yaml carries,
which is tracked in #625. The channel count and the radial bounds are
machine-specific.
Applicability
Machine-independent. Every threshold arrives as an argument.
Limitations
Grades the fits it is handed; it cannot tell a well-fitted wrong model from a right one. A shot whose array faces the toroidal field can pass the geometry checks and still have no usable vertical measurement.
Provenance
- Issues #337 and #339 for the naming and the eventual move;
vest.yamlimpa.qualityfor the configured thresholds.
impa_calibrate_signals
Machine-independentConvention-sensitive
source
impa_calibrate_signals(raw, *, gain, cutoff_hz, sample_rate, baseline='first_sample', baseline_samples=2500)
Show source vaft/process/impa.py, lines 404–471
def impa_calibrate_signals(
raw: np.ndarray,
*,
gain: float,
cutoff_hz: float,
sample_rate: float,
baseline: str = "first_sample",
baseline_samples: int = 2_500,
) -> np.ndarray:
"""Filter, scale and baseline raw probe records into field units.
Parameters
----------
raw : array_like
Raw digitizer records as ``(n_channels, n_samples)`` [V].
gain : float
Hall calibration factor [T/V].
cutoff_hz : float
Conditioning low-pass cut-off [Hz].
sample_rate : float
Sample rate [Hz].
baseline : str, optional
Which baseline to remove [-].
baseline_samples : int, optional
Leading samples used when the baseline is a mean [-].
Returns
-------
np.ndarray
Conditioned records in field units [T].
Processing steps
----------------
1. Low-pass each channel.
2. Multiply by the calibration factor.
3. Remove the baseline.
Convention
----------
**The stage order is the donor's**, low pass then gain then baseline, and it
is not interchangeable: removing a baseline before filtering leaves the
filter's transient riding on a different level.
The sign of the calibration factor is the caller's, and the fits downstream
are deliberately sign-agnostic; see the module's conventions and #624.
Defaults
--------
``baseline_samples = 2500`` is an acquisition-era value, the leading interval
that precedes the discharge at the array's own sample rate. It is a sample
count, so it means a different duration at a different rate.
Applicability
-------------
Machine-independent.
Limitations
-----------
Assumes the leading window is field-free. Inherits the record-length caveat
of :func:`impa_lowpass`.
Provenance
----------
.. [1] ``VEST_IMPAProcessing.m``, whose stage order this follows.
"""
raw = np.atleast_2d(np.asarray(raw, dtype=float))
filtered = impa_lowpass(raw, cutoff_hz, sample_rate) * float(gain)
return _apply_baseline(filtered, baseline, baseline_samples)Filter, scale and baseline raw probe records into field units.
| Name | Type | Unit | Description |
|---|---|---|---|
raw | array_like | V | Raw digitizer records as |
gain | float | T/V | Hall calibration factor. |
cutoff_hz | float | Hz | Conditioning low-pass cut-off. |
sample_rate | float | Hz | Sample rate. |
baseline | str, optional | - | Which baseline to remove. |
baseline_samples | int, optional | - | Leading samples used when the baseline is a mean. |
| Returns | |||
| — | np.ndarray | T | Conditioned records in field units. |
Convention
The stage order is the donor’s, low pass then gain then baseline, and it is not interchangeable: removing a baseline before filtering leaves the filter’s transient riding on a different level.
The sign of the calibration factor is the caller’s, and the fits downstream are deliberately sign-agnostic; see the module’s conventions and #624.
Processing steps · Defaults · Applicability · Limitations · Provenance
Processing steps
- Low-pass each channel.
- Multiply by the calibration factor.
- Remove the baseline.
Defaults
baseline_samples = 2500 is an acquisition-era value, the leading interval
that precedes the discharge at the array’s own sample rate. It is a sample
count, so it means a different duration at a different rate.
Applicability
Machine-independent.
Limitations
Assumes the leading window is field-free. Inherits the record-length caveat
of impa_lowpass.
Provenance
VEST_IMPAProcessing.m, whose stage order this follows.
impa_lowpass
Machine-independentConvention-sensitive
source
impa_lowpass(values, cutoff_hz, sample_rate)
Show source vaft/process/impa.py, lines 341–392
def impa_lowpass(values: np.ndarray, cutoff_hz: float, sample_rate: float) -> np.ndarray:
"""Zero-phase low pass reproducing the legacy filter design.
Parameters
----------
values : array_like
Waveform or stack of them; the sample axis is the last [any].
cutoff_hz : float
Cut-off frequency [Hz].
sample_rate : float
Sample rate [Hz].
Returns
-------
np.ndarray
The filtered waveform, same shape [any].
Convention
----------
**Zero phase where it can be.** The forward-backward filter moves no feature
in time, which matters because the array's channels are compared against each
other and against the coil current. A record too short for the padding that
needs falls back to a single forward pass, which is causal and therefore
delays every feature; the convention silently changes with record length, and
only tiny synthetic records are short enough for it.
Defaults
--------
The tap count is a legacy compatibility value: the donor design is a
Hamming-window filter whose order follows from the sample rate, giving the
same 26 taps this uses.
Applicability
-------------
Machine-independent.
Limitations
-----------
The fallback above is the one case where the phase convention is not what the
summary says.
Provenance
----------
.. [1] The legacy ``vest_filter`` design, whose window, order and
forward-backward application this reproduces.
"""
values = np.asarray(values, dtype=float)
taps = signal.firwin(_FIR_TAPS, cutoff_hz, pass_zero="lowpass", fs=sample_rate)
# The shared length rule; this check used to stop three samples short (#893).
if values.shape[-1] >= _filtfilt_min_length(taps.size):
return signal.filtfilt(taps, 1, values, axis=-1)
return signal.lfilter(taps, 1, values, axis=-1)Zero-phase low pass reproducing the legacy filter design.
| Name | Type | Unit | Description |
|---|---|---|---|
values | array_like | any | Waveform or stack of them; the sample axis is the last. |
cutoff_hz | float | Hz | Cut-off frequency. |
sample_rate | float | Hz | Sample rate. |
| Returns | |||
| — | np.ndarray | any | The filtered waveform, same shape. |
Convention
Zero phase where it can be. The forward-backward filter moves no feature in time, which matters because the array’s channels are compared against each other and against the coil current. A record too short for the padding that needs falls back to a single forward pass, which is causal and therefore delays every feature; the convention silently changes with record length, and only tiny synthetic records are short enough for it.
Defaults · Applicability · Limitations · Provenance
Defaults
The tap count is a legacy compatibility value: the donor design is a Hamming-window filter whose order follows from the sample rate, giving the same 26 taps this uses.
Applicability
Machine-independent.
Limitations
The fallback above is the one case where the phase convention is not what the summary says.
Provenance
- The legacy
vest_filterdesign, whose window, order and forward-backward application this reproduces.
legacy_impa_compensation
VEST-specificConvention-sensitive
source
legacy_impa_compensation(time, raw, tf_raw, r, *, target_time=0.29, sample_rate=25000.0, cutoff_hz=250.0, gain=-0.13333333333333333, tf_gain=30000.0, turns=24, tilt_bounds_deg=(-10.0, 10.0))
Faithful port of the legacy compensation script, at one time sample.
Kept for comparison against the donor, not as the maintained path; the
current chain is fit_impa_tf_coupling with remove_tf_pickup.
| Name | Type | Unit | Description |
|---|---|---|---|
time | array_like | s | Sample times. |
raw | array_like | V | Raw probe records as |
tf_raw | array_like | V | Raw toroidal-field coil trace. |
r | array_like | m | Major radius of each probe. |
target_time | float, optional | s | The single sample the fit is evaluated at. |
sample_rate | float, optional | Hz | Sample rate. |
cutoff_hz | float, optional | Hz | Conditioning low-pass cut-off. |
gain | float, optional | T/V | Hall calibration factor. |
tf_gain | float, optional | A/V | Raw-to-amperes factor for the coil trace. |
turns | int, optional | - | Coil turns. |
tilt_bounds_deg | tuple of float, optional | deg | Bounds on the probe tilt. |
| Returns | |||
| — | ImpaCouplingFit | - | The per-channel coupling and the compensated field at that sample. |
Convention
The donor’s order, which differs from the position script’s: here the low pass comes before the gain, and both traces are offset-corrected. The sign pairing is also the donor’s, a negative gain with a positive coil factor, the mirror of the other script. Both are reproduced rather than harmonized.
Processing steps · Defaults · Applicability · Limitations · Provenance
Processing steps
- Low-pass each probe, apply the gain, subtract the first sample.
- Low-pass the coil trace and subtract its first sample.
- Take the sample nearest the target time.
- Solve a bounded tilt per channel, build the pickup, and divide it out.
Defaults
Every default is a legacy compatibility value from the donor script, including its evaluation time, which differs from the position script’s.
Applicability
VEST-specific. A port of a VEST script carrying that machine’s coil factor, sample rate and calibration as defaults, reproducing one historical routine rather than a general method.
Limitations
One time sample only. The donor also processed a reference shot through the same path; that branch is deliberately absent here, so this is the single-shot half of the original. The tilt model assumes a near-vertical probe and saturates on an array that faces the toroidal field.
Provenance
VEST_IMPAProcessing.m, ported faithfully including its stage order and its sign pairing; the omitted reference-shot branch is noted above.
legacy_impa_position
VEST-specificConvention-sensitive
source
legacy_impa_position(time, raw, tf_raw, *, target_time=0.3, sample_rate=25000.0, cutoff_hz=2500.0, gain=0.13333333333333333, tf_gain=-30000.0, turns=24, pitch=0.05, r0_initial=0.4, r_bounds=(0.1, 0.9), baseline_samples=2500)
Faithful port of the legacy position script, at one time sample.
Kept so the current chain can be compared against what the donor actually
did, not so it can be used in preference; fit_impa_geometry is the
maintained path.
| Name | Type | Unit | Description |
|---|---|---|---|
time | array_like | s | Sample times. |
raw | array_like | V | Raw probe records as |
tf_raw | array_like | V | Raw toroidal-field coil trace. |
target_time | float, optional | s | The single sample the fit is evaluated at. |
sample_rate | float, optional | Hz | Sample rate. |
cutoff_hz | float, optional | Hz | Conditioning low-pass cut-off. |
gain | float, optional | T/V | Hall calibration factor. |
tf_gain | float, optional | A/V | Raw-to-amperes factor for the coil trace. |
turns | int, optional | - | Coil turns. |
pitch | float, optional | m | As-built channel spacing. |
r0_initial | float, optional | m | Starting guess for the innermost radius. |
r_bounds | tuple of float, optional | m | Bounds on that radius. |
baseline_samples | int, optional | - | Leading samples forming the baseline. |
| Returns | |||
| — | ImpaGeometryFit | - | The fitted radii and spacing at that one sample. |
Convention
The donor’s order, kept deliberately, including the asymmetry that the coil trace is not offset-corrected while the probes are. The sign pairing is the donor’s too, a positive gain with a negative coil factor, which differs from both the datasheet and the other legacy script; see the module’s conventions.
Processing steps · Defaults · Applicability · Limitations · Provenance
Processing steps
- Subtract each probe’s first sample, apply the gain, low-pass, then subtract the mean of the leading samples.
- Condition the coil trace with gain and low pass, without removing any offset.
- Take the sample nearest the target time.
- Solve the bounded least squares for the innermost radius.
Defaults
Every default here is a legacy compatibility value reproducing the donor script: its single evaluation time, its sample rate, its cut-off, its two gains and its baseline length.
Applicability
VEST-specific. A port of a VEST script, carrying that machine’s coil factor, sample rate and array spacing as its defaults; it reproduces one historical routine rather than describing a general method.
Limitations
One time sample, not a time series, and no residual quality reported. It assumes unit coupling, which the reference shots show is nearly true and the rejected shots show is not.
Provenance
vest_impa_position.m, ported faithfully including its stage order and its sign pairing.
process_impa
Machine-independentConvention-sensitive
source
process_impa(time, raw, i_tf, *, config=None, criteria=None, ip=None, pf_currents=None, channel_valid=None, r=None, z=0.0, pitch=0.05, r_bounds=(0.1, 0.9), r0_initial=0.4, max_normalized_rmse=0.15, reference=None, b_z_raw=None, bz_channel_valid=None, fit_pitch=False, max_crosstalk_angle_deg=30.0, min_crosstalk_r_squared=0.8, bz_gain=None, bz_radial_offset=0.01)
Run the whole array chain for one shot, from raw records to a graded result.
| Name | Type | Unit | Description |
|---|---|---|---|
time | array_like | s | Sample times. |
raw | array_like | V | Raw probe records as |
i_tf | array_like | A | Toroidal field coil current. |
config | ImpaProcessingConfig, optional | - | Conditioning settings. |
criteria | TfWindowCriteria, optional | - | Window-selection thresholds. |
ip | array_like, optional | A | Plasma current. |
pf_currents | array_like, optional | A | Poloidal field coil currents. |
channel_valid | array_like, optional | - | Which probe channels to use. |
r | array_like, optional | m | Configured radii, which take precedence when supplied. |
z | float, optional | m | Height of the array. |
pitch | float, optional | m | As-built channel spacing. |
r_bounds | tuple of float, optional | m | Bounds on the fitted radius. |
r0_initial | float, optional | m | Starting guess for it. |
max_normalized_rmse | float, optional | - | Largest acceptable geometry residual. |
reference | Mapping, optional | - | A reference shot supplying the calibration instead of this shot’s own. |
b_z_raw | array_like, optional | V | Raw vertical-sensor records. |
bz_channel_valid | array_like, optional | - | Which vertical sensors to use. |
fit_pitch | bool, optional | - | Whether to fit the spacing too. |
max_crosstalk_angle_deg | float, optional | deg | Largest misalignment treated as physical. |
min_crosstalk_r_squared | float, optional | - | Smallest acceptable crosstalk goodness of fit. |
bz_gain | float, optional | T/V | Volts-to-tesla gain for the vertical sensors. |
bz_radial_offset | float, optional | m | Radial offset of the vertical sensors from their Hall neighbours. |
| Returns | |||
| — | ImpaResult | - | The conditioned fields, the geometry and coupling, the compensated vertical field, the quality verdict, and a provenance record. |
Convention
Geometry precedence is deliberate and ordered. Self-calibration from the shot’s own window is the primary source, not a fallback, because the array is insertable and its position is a per-shot quantity. A configured radius wins only where an era was surveyed or left fixed.
The vertical sensors are not co-located with the Hall channel of the same index; the offset is a hardware fact supplied by the caller.
Processing steps · Defaults · Applicability · Limitations · Provenance
Processing steps
- Condition the raw records into field units.
- Mask the invalid channels.
- Find the interval driven by the toroidal field alone.
- Resolve the geometry by precedence: a reference shot, then a configured radius, then a fit on this shot’s own window, then the nominal uncalibrated positions.
- Resolve the coupling, from the reference if there is one, else by fitting.
- Remove the toroidal pickup, branching on the array’s orientation.
- Optionally fit and remove the vertical sensors’ crosstalk.
- Grade the result and record what was used.
Defaults
The spacing, bounds, starting guess and channel count are machine-specific
VEST values. The residual threshold and the radial offset disagree with what
vest.yaml carries, which is tracked in #625; the VEST pipeline passes the
configured values, so the disagreement bites only a direct caller.
Applicability
Machine-independent. Every machine number is an argument, and the VEST pipeline supplies them from configuration.
Limitations
Inherits every assumption of the steps it orchestrates, above all that the selected window is genuinely driven by the toroidal field alone. A shot whose array faces that field yields a compensated vertical field that is not a measurement, which the grading flags rather than the chain refusing.
Provenance
- The stages this orchestrates, each documented on its own function;
vest.yamlimpafor the configuration the VEST pipeline passes in.
remove_bz_crosstalk
Machine-independentConvention-sensitive
source
remove_bz_crosstalk(b_z_raw, b_toroidal, crosstalk)
Show source vaft/process/impa.py, lines 1157–1210
def remove_bz_crosstalk(
b_z_raw: np.ndarray,
b_toroidal: np.ndarray,
crosstalk: ImpaCrosstalkFit,
) -> np.ndarray:
"""Subtract a vertical sensor's toroidal crosstalk.
Parameters
----------
b_z_raw : array_like
Raw vertical-sensor records, in the sensor's native units [V].
b_toroidal : array_like
The toroidal field at each sensor [T].
crosstalk : ImpaCrosstalkFit
The fitted per-sensor slope and offset [-].
Returns
-------
np.ndarray
The records with the crosstalk removed, still in native units [V].
Convention
----------
**The output stays in volts.** The wiring datasheet leaves the vertical
sensors' volts-to-tesla gain unspecified, so nothing here converts them; the
fitted slope is therefore volts per tesla rather than a dimensionless
projection.
Applicability
-------------
Machine-independent.
Limitations
-----------
Removes only the linear crosstalk the fit describes. A sensor whose response
to the toroidal field is not linear keeps its residual.
Provenance
----------
.. [1] :func:`fit_impa_crosstalk`, which supplies the coefficients, and the
wiring datasheet that leaves the vertical gain unspecified.
"""
b_z_raw = np.atleast_2d(np.asarray(b_z_raw, dtype=float))
b_toroidal = np.atleast_2d(np.asarray(b_toroidal, dtype=float))
channels = min(b_z_raw.shape[0], b_toroidal.shape[0])
corrected = np.full_like(b_z_raw, np.nan)
for channel in range(channels):
slope = crosstalk.slope_v_per_t[channel]
if not np.isfinite(slope):
continue
corrected[channel] = (
b_z_raw[channel] - slope * b_toroidal[channel] - crosstalk.offset[channel]
)
return correctedSubtract a vertical sensor’s toroidal crosstalk.
| Name | Type | Unit | Description |
|---|---|---|---|
b_z_raw | array_like | V | Raw vertical-sensor records, in the sensor’s native units. |
b_toroidal | array_like | T | The toroidal field at each sensor. |
crosstalk | ImpaCrosstalkFit | - | The fitted per-sensor slope and offset. |
| Returns | |||
| — | np.ndarray | V | The records with the crosstalk removed, still in native units. |
Convention
The output stays in volts. The wiring datasheet leaves the vertical sensors’ volts-to-tesla gain unspecified, so nothing here converts them; the fitted slope is therefore volts per tesla rather than a dimensionless projection.
Applicability · Limitations · Provenance
Applicability
Machine-independent.
Limitations
Removes only the linear crosstalk the fit describes. A sensor whose response to the toroidal field is not linear keeps its residual.
Provenance
fit_impa_crosstalk, which supplies the coefficients, and the wiring datasheet that leaves the vertical gain unspecified.
remove_tf_pickup
Machine-independentConvention-sensitive
source
remove_tf_pickup(b_measured, tf_pickup, alpha)
Show source vaft/process/impa.py, lines 1213–1261
def remove_tf_pickup(b_measured: np.ndarray, tf_pickup: np.ndarray, alpha: np.ndarray) -> np.ndarray:
"""Recover the vertical field by removing a probe's toroidal pickup.
Parameters
----------
b_measured : array_like
What the probe measured [T].
tf_pickup : array_like
The toroidal field at that probe [T].
alpha : array_like
The probe's coupling to the toroidal field [-].
Returns
-------
np.ndarray
The compensated vertical field, NaN where the probe is toroidally
aligned [T].
Convention
----------
Inverts the measurement model: subtract the coupled toroidal part, then
divide by the remaining poloidal sensitivity. A probe with unit coupling
faces the toroidal field and has **no** sensitivity left for the vertical
one, so the result is NaN rather than a division blowing up. That is not an
edge case on this array: the reference shots put the coupling at 1.01 to
1.045, which is exactly that condition.
Applicability
-------------
Machine-independent.
Limitations
-----------
The compensated field is only as good as the coupling it was given, and the
division amplifies its error as the coupling approaches one. Trust the
result only where the array is genuinely near-vertical.
Provenance
----------
.. [1] The measurement model in this module's conventions, of which this is
the inversion.
"""
b_measured = np.atleast_2d(np.asarray(b_measured, dtype=float))
tf_pickup = np.atleast_2d(np.asarray(tf_pickup, dtype=float))
alpha = np.asarray(alpha, dtype=float)
with np.errstate(invalid="ignore", divide="ignore"):
projection = np.sqrt(1.0 - np.clip(alpha, -1.0, 1.0) ** 2)
projection = np.where(projection > 1e-3, projection, np.nan)
return (b_measured - tf_pickup) / projection[:, None]Recover the vertical field by removing a probe’s toroidal pickup.
| Name | Type | Unit | Description |
|---|---|---|---|
b_measured | array_like | T | What the probe measured. |
tf_pickup | array_like | T | The toroidal field at that probe. |
alpha | array_like | - | The probe’s coupling to the toroidal field. |
| Returns | |||
| — | np.ndarray | T | The compensated vertical field, NaN where the probe is toroidally aligned. |
Convention
Inverts the measurement model: subtract the coupled toroidal part, then divide by the remaining poloidal sensitivity. A probe with unit coupling faces the toroidal field and has no sensitivity left for the vertical one, so the result is NaN rather than a division blowing up. That is not an edge case on this array: the reference shots put the coupling at 1.01 to 1.045, which is exactly that condition.
Applicability · Limitations · Provenance
Applicability
Machine-independent.
Limitations
The compensated field is only as good as the coupling it was given, and the division amplifies its error as the coupling approaches one. Trust the result only where the array is genuinely near-vertical.
Provenance
- The measurement model in this module’s conventions, of which this is the inversion.
toroidal_field
Machine-independentConvention-sensitive
source
toroidal_field(r, i_tf, turns=24)
Show source vaft/process/impa.py, lines 474–520
def toroidal_field(r: np.ndarray | float, i_tf: np.ndarray | float, turns: int = 24) -> np.ndarray:
"""Vacuum toroidal field at a radius, from the coil current.
Parameters
----------
r : array_like
Major radius, strictly positive [m].
i_tf : array_like
Toroidal field coil current [A].
turns : int, optional
Coil turns [-].
Returns
-------
np.ndarray
The vacuum toroidal field [T].
Convention
----------
``mu0 * N * I / (2 * pi * R)``, the vacuum field of an ideal toroidal
solenoid, so it carries the sign of the current as given. It is the field the
array is calibrated against, not a measurement.
Defaults
--------
``turns = 24`` is machine-specific, the VEST toroidal field coil's turn count.
A caller on another machine passes its own.
Applicability
-------------
Machine-independent. Only the default turn count is a VEST number.
Limitations
-----------
Vacuum field only: it ignores the plasma's own diamagnetic or paramagnetic
contribution, which is the assumption that makes a coil-driven interval usable
for calibration in the first place.
Provenance
----------
.. [1] The ideal toroidal solenoid field; the same relation
:mod:`vaft.machine_mapping.tf` uses for the coil current.
"""
r_array = np.asarray(r, dtype=float)
if np.any(r_array <= 0):
raise ValueError("IMPA probe radii must be positive")
return MU0 * int(turns) * np.asarray(i_tf, dtype=float) / (2.0 * math.pi * r_array)Vacuum toroidal field at a radius, from the coil current.
| Name | Type | Unit | Description |
|---|---|---|---|
r | array_like | m | Major radius, strictly positive. |
i_tf | array_like | A | Toroidal field coil current. |
turns | int, optional | - | Coil turns. |
| Returns | |||
| — | np.ndarray | T | The vacuum toroidal field. |
Convention
mu0 * N * I / (2 * pi * R), the vacuum field of an ideal toroidal
solenoid, so it carries the sign of the current as given. It is the field the
array is calibrated against, not a measurement.
Defaults · Applicability · Limitations · Provenance
Defaults
turns = 24 is machine-specific, the VEST toroidal field coil’s turn count.
A caller on another machine passes its own.
Applicability
Machine-independent. Only the default turn count is a VEST number.
Limitations
Vacuum field only: it ignores the plasma’s own diamagnetic or paramagnetic contribution, which is the assumption that makes a coil-driven interval usable for calibration in the first place.
Provenance
- The ideal toroidal solenoid field; the same relation
vaft.machine_mapping.tfuses for the coil current.
validate_impa
Deprecated
source
validate_impa(*args, **kwargs)
Show source vaft/process/impa.py, lines 1796–1805
def validate_impa(*args: Any, **kwargs: Any) -> ImpaQuality:
"""Deprecated compatibility wrapper for :func:`grade_impa_quality`."""
warnings.warn(
"vaft.process.validate_impa() is deprecated; use grade_impa_quality(). "
"vaft.process does not reach verdicts (issues #253, #337); the grading "
"itself moves to vaft.validation.impa under #339.",
DeprecationWarning,
stacklevel=2,
)
return grade_impa_quality(*args, **kwargs)Deprecated compatibility wrapper for grade_impa_quality.