LCR/Impedance and RPS/RUS Analyses
This section covers two advanced module families found in the Analysis workspace: the capacitance–voltage and impedance-based LCR/Impedance family, and the resonant piezoelectric/ultrasound-based RPS/RUS family. Both families extract semiconductor, thin-film, photovoltaic and elastic device parameters from the measurement files you upload, completely, with an uncertainty budget and in a reproducible manner.
- LCR / Impedance family (A1–A8): Extracts semiconductor/thin-film/photovoltaic device parameters (carrier density, built-in voltage, trap energies, interface trap density, recombination lifetime) from capacitance–voltage (C–V), capacitance–frequency (C–f), impedance spectroscopy (Z–f) and temperature-resolved admittance (TAS) data.
- RPS / RUS family (29–35): Extracts resonance frequency, quality factor, acoustic attenuation, relative piezoelectric response, nonlinearity ratio, relative elastic modulus and the full elastic tensor (Cij) from resonant piezoelectric spectroscopy (RPS) and resonant ultrasound spectroscopy (RUS) data.
Both families are computed in the application's Qt-free core engines (app/analysis_kit/engines/lcr and .../rps); the numbers are produced from a single source and the visual layer never recomputes. Uncertainties are propagated from the fit covariance within the GUM (JCGM 100:2008) framework.
bias_v, cp_f, freq_hz, z_re_ohm, harmonic, r_v, t_set_k), it is computed directly without manual column mapping.
This section describes two analysis families that take the raw measurement files (CSV) you recorded in the lab and extract meaningful numbers about the material and device from them. Just as a doctor looks at an X-ray film and says "the bone is this dense," the software looks at your curves and reads physical quantities such as carrier density, trap energy or elastic modulus.
- Why it's done: Raw curves (capacitance, impedance, resonance peaks) cannot be interpreted on their own; analysis converts them into comparable physical parameters.
- What it teaches / measures: Each module produces a specific quantity (e.g. carrier density, lifetime, elastic constants) and gives its uncertainty (± error) alongside it.
- Where it's used: Semiconductor/solar cell research, thin-film quality control, materials characterization and failure analysis.
Common Concepts
Data columns and unit notation
The LCR/RPS example files carry the unit in square brackets in their CSV headers; the loader strips the trailing [unit] suffix and binds the column by name. Typical headers:
| Mode | CSV column header (example) | Description |
|---|---|---|
| C–V | bias_v [V], cp_f [F], rp_ohm [ohm], g_s [S], z_re_ohm [ohm], z_im_ohm [ohm] | Fixed frequency, swept DC bias |
| C–f | freq_hz [Hz], cp_f [F], g_s [S], rp_ohm [ohm], z_re_ohm [ohm], z_im_ohm [ohm] | Fixed bias, log-swept frequency |
| Z–f | freq_hz [Hz], z_re_ohm [ohm], z_im_ohm [ohm], z_mag_ohm [ohm], z_phase_deg [deg], bias_v [V] | Impedance spectroscopy |
| TAS | temperature_k [K], freq_hz [Hz], cp_f [F], g_s [S] | One C–f sweep stacked at each temperature |
| RPS | harmonic, freq_hz [Hz], x_v [V], y_v [V], r_v [V], t_set_k [K] | Lock-in harmonic/phase output |
area_cm2, temperature_k, eps_r, must be supplied either from the relevant column in the file or from the module parameter panel. The example files map these values via parameter defaults.Physical constants (CODATA 2019, SI)
| Constant | Symbol | Value |
|---|---|---|
| Elementary charge | q | 1.602176634 × 10⁻¹⁹ C |
| Boltzmann constant | kB | 1.380649 × 10⁻²³ J/K |
| Boltzmann (eV) | kB | 8.617333262 × 10⁻⁵ eV/K |
| Vacuum permittivity | ε₀ | 8.8541878128 × 10⁻¹² F/m |
Uncertainty and goodness-of-fit metrics
- All standard uncertainties are k = 1 (expanded uncertainty is not separately reported; project convention).
- For linear fits the uncertainty is computed from the
numpy.polyfitcovariance matrix; for nonlinear fits (scipy.optimize.least_squares) from the Jacobian with a-posteriori s² scaling. r2(coefficient of determination) is reported for every fit; each module also returns ananalysis_resolvedflag (Falsewhen it cannot be resolved).
analysis_resolved = False) and return a warning note; there is no output crash.LCR / Impedance Family (A1–A8)
LCR and impedance measurements apply a small oscillating (AC) signal to the device and measure its capacitance and resistance response. Like knocking on a wall and inferring from the echo whether there is a cavity behind it, the state of the junction region, the defects and the carriers is read from the electrical response at different frequencies and voltages.
- Why it's done: To understand, without damaging the device (non-destructively), the doping density, depletion region and defect/trap levels inside it.
- What it teaches / measures: Carrier density, built-in voltage, trap energies, interface trap density and carrier lifetime.
- Where it's used: Solar cell and diode development, MOS interface quality control, material trap/defect diagnostics.
The LCR module family has been validated with synthetic examples generated from ground-truth presets for different semiconductor/PV device types. The preset table below summarizes the physical basis of the example files:
| Preset | Type | A (cm²) | Neff (cm⁻³) | Vbi (V) | εr | Rs (Ω) | Rrec (Ω) | Cμ (F) | Traps (E [eV], ΔC [F]) |
|---|---|---|---|---|---|---|---|---|---|
c_si | c-Si | 0.09 | 1×10¹⁶ | 0.70 | 11.7 | 5 | 5×10³ | 2×10⁻⁹ | (0.15, 0.3 nF) |
cigs | CIGS | 0.09 | 5×10¹⁵ | 0.80 | 13.6 | 15 | 1×10⁴ | 3×10⁻⁹ | (0.10, 0.8 nF), (0.28, 0.5 nF) |
perovskite | Perovskite | 0.09 | 1×10¹⁷ | 1.00 | 24.0 | 20 | 8×10³ | 5×10⁻⁸ | (0.35, 2 nF), (0.55, 1.5 nF) |
iii_v | III-V | 0.09 | 1×10¹⁸ | 1.20 | 12.9 | 8 | 2×10⁴ | 1×10⁻⁹ | — |
opv | OPV | 0.09 | 1×10¹⁶ | 0.60 | 3.5 | 50 | 1.5×10⁴ | 8×10⁻⁹ | (0.20, 0.4 nF) |
The trap characteristic (emission) frequency is computed with a consistent prefactor form across all LCR modules:
Here ν₀ is the attempt frequency (default 1×10¹² s⁻¹K⁻²). This relation is used both in example generation and in TAS Arrhenius extraction.
A1 — Mott–Schottky (C–V) · lcr_mott_schottky
By looking at how the device's capacitance changes as the voltage is varied, this module tells you how much the semiconductor is "doped" (carrier density) and the junction's built-in voltage. Just as the capacitance of a capacitor drops as its plates are moved apart, voltage widens the depletion region, and the slope of this change gives us the density.
- Why it's done: It answers the question "how many free carriers per unit volume are there in this material?"
- What it teaches / measures: Effective carrier density Neff, built-in voltage Vbi and the depletion width at 0 V.
- Where it's used: Diode/solar cell doping level verification and process control.
Purpose: Extracts carrier density Neff and built-in voltage Vbi from depletion-region C–V data.
Physics and method. In an abrupt junction the depletion capacitance is Cdep = ε·A/W with W = √(2ε(Vbi−V)/(qN)), so the 1/C² quantity is linear in bias:
The engine applies a linear fit (slope m, intercept b) to the 1/C²–V curve:
- Neff = −2 / (q · εr · ε₀ · A² · m) → [m⁻³], then ×10⁻⁶ to [cm⁻³]
- Vbi = −b/m (x-intercept)
- Wd(0 V) = εr·ε₀·A / C(0 V) → [m], then ×10⁹ to [nm]
Input columns: bias_v, cp_f. (At least 5 points, all C > 0, finite bias.)
Parameters:
| Parameter | Unit | Description | Default |
|---|---|---|---|
eps_r | — | Relative permittivity εr | 11.7 |
area_cm2 | cm² | Device area | 0.09 |
Outputs:
| Key | Unit | Description |
|---|---|---|
n_eff_cm3 | cm⁻³ | Effective carrier density (from slope) |
v_bi_v | V | Built-in voltage (x-intercept) |
w_d_at_0v_nm | nm | Depletion width at 0 V |
ms_slope | 1/(F²·V) | 1/C²–V slope (< 0 for n-type depletion) |
eps_r_used | — | εr used |
r2 | — | Linear fit goodness |
Uncertainty (GUM): u(N)/N = u(m)/|m|; u²(Vbi) = ub²/m² + b²·um²/m⁴ − 2·b·cov(m,b)/m³.
Example file: examples/analysis/21_lcr_mott_schottky.csv — c-Si abrupt junction, f = 10 kHz, bias −1.0…0.5 V (40 points). Expected: Neff ≈ 1×10¹⁶ cm⁻³ (±2%), Vbi ≈ 0.70 V (±20 mV), Wd(0 V) ≈ 301 nm, r² ≥ 0.98.

A2 — C–V Doping Profile · lcr_cv_profiling
While A1 gives a single average density, A2 extracts how the doping density varies with depth into the device. Like sounding the bottom of a lake point by point with a plumb line to build a depth map, each voltage corresponds to a depth, and the local density is computed there.
- Why it's done: To see whether the doping is uniform or varies with depth.
- What it teaches / measures: The depth-resolved N(W) profile, the average density and the depth range covered by the profile.
- Where it's used: Doping uniformity quality control and layered-structure analysis.
Purpose: Extracts a depth-resolved (non-uniform) doping profile N(W) from differential C–V.
Physics and method. The differential profiling method:
The dC/dV derivative is taken first with a Savitzky–Golay (poly = 2) smoothing, then with irregular-spacing-aware numpy.gradient (smoothing window smooth_window). As bias increases W shrinks; as depletion recedes W grows. Only finite, positive points with |dC/dV| > 0 are included in the profile.
Input columns: bias_v, cp_f.
Parameters:
| Parameter | Unit | Description | Default |
|---|---|---|---|
eps_r | — | Relative permittivity | 11.7 |
area_cm2 | cm² | Device area | 0.09 |
smooth_window | — | Savitzky–Golay window (odd number) | 5 |
Outputs: n_mean_cm3 (cm⁻³, profile average), n_points_profile (number of valid points), w_min_nm, w_max_nm (nm; the depth range of the profile). Uncertainty: u(N̄) = s/√n (the standard error of the mean of the profile points).
Example file: examples/analysis/22_lcr_cv_profiling.csv — c-Si uniform N(W) ≈ 1×10¹⁶ cm⁻³, bias −1.0…0.4 V (60 points), smooth_window = 5. Expected: the N̄ profile is flat and ~1×10¹⁶ cm⁻³ (2×10¹⁵…5×10¹⁶ band), ≥ 3 valid profile points.

A3 — Impedance (Nyquist) Fit · lcr_impedance_fit
This module fits the impedance measured versus frequency to an equivalent electrical circuit (resistors + capacitor) and finds the values of the circuit elements. Like guessing the circuit inside an unknown box by feeding a signal to its terminals and watching the response, the semicircular (Nyquist) shape of the curve tells us the internal resistances and the capacitance.
- Why it's done: To quantify the loss/recombination processes in the device separately.
- What it teaches / measures: Series resistance Rs, recombination resistance Rrec, chemical capacitance Cμ and carrier lifetime τn.
- Where it's used: Solar cell/perovskite device loss analysis and model validation.
Purpose: Applies a complex NLLS fit of an equivalent circuit (Randles type) to the Z–f spectrum; extracts Rs, Rrec, Cμ and carrier lifetime τn.
Physics and method. Single-arc Randles circuit:
The circuit is fitted with complex NLLS (modulus weighting 1/|Z|, least_squares TRF, lower bound 0). When the circuit is set to auto it is determined from the device type:
| Device type | Default circuit |
|---|---|
| c_si, iii_v, cigs | rs_rrec_cmu |
| perovskite | rs_rtr_cgeo_rrec_cmu |
| opv | rs_rrec_cpe |
Supported circuit models:
| Circuit ID | Model | Parameters |
|---|---|---|
rs_rrec_cmu | Rs–(Rrec‖Cμ) | r_s, r_rec, c_mu |
rs_rrec_cpe | Rs–(Rrec‖CPE) | r_s, r_rec, cpe_q, cpe_n |
rs_rtr_cgeo_rrec_cmu | Rs–(Rtr‖Cgeo)–(Rrec‖Cμ) | r_s, r_tr, c_geo, r_rec, c_mu |
rs_rrec_cmu_warburg | Rs–(Rrec‖Cμ)–W | r_s, r_rec, c_mu, warburg_sigma |
Input columns: z_re_ohm, z_im_ohm, freq_hz (at least 5 points).
Parameters:
| Parameter | Description | Default |
|---|---|---|
circuit | Equivalent circuit (auto / 4 models) | auto |
Outputs: r_s_ohm (Ω), r_rec_ohm (Ω), c_mu_f (F), tau_n_s (s), chi2, r2, circuit_used (the circuit used). Uncertainty (GUM): u²(τ) = Cμ²·u²(Rrec) + Rrec²·u²(Cμ) + 2·Rrec·Cμ·cov(Rrec,Cμ).
Example file: examples/analysis/23_lcr_impedance_fit.csv — c-Si single-arc, Rs = 5 Ω, Rrec = 5 kΩ, Cμ = 2 nF, 10 Hz–1 MHz (80 points). Expected: Rs ≈ 5 Ω (±5%), Rrec ≈ 5 kΩ (±5%), τn ≈ 10 µs (±5%), apex f₀ ≈ 15.9 kHz, circuit_used = rs_rrec_cmu, r² > 0.95.
circuit_used scalar in the output reports which model the auto selection resolved to. Unless you want to fix the circuit manually, auto selects the most appropriate model based on the device type.
A4 — C–f Trap Spectrum · lcr_cf_traps
Defects (traps) in the material capture and release carriers at a certain rate; this rate corresponds to a characteristic frequency. As the frequency is swept a "step" appears in the capacitance; the module finds the exact frequency of this step. Like turning the dial on a radio until you catch a station, we find the trap's "tuning frequency" by sweeping.
- Why it's done: To detect the presence of a trap and the emission frequency that characterizes it.
- What it teaches / measures: The threshold emission frequency f₀, the capacitance step height ΔC and the number of detected steps.
- Where it's used: Defect screening, material purity and process-induced trap monitoring.
Purpose: Detects the trap steps (Debye relaxation) in the C–f spectrum to find the characteristic (threshold) emission frequency f₀.
Physics and method. For a single Debye trap, C(ω) = ΔC / (1 + (ω/ωi)²). The −dC/d(ln ω) quantity of this profile peaks at ω = ωi:
The derivative is taken with Savitzky–Golay smoothing; the peak position is determined by parabolic peak refinement (sub-sample precision). The number of steps is counted with scipy.signal.find_peaks (threshold = 20% of the maximum peak).
Input columns: freq_hz, cp_f (at least 6 points, all f > 0).
Parameters: smooth_window (default 7).
Outputs: f0_hz (Hz, threshold emission frequency), delta_c_f (F, capacitance step height = max − min), n_steps (number of detected steps).
Example file: examples/analysis/24_lcr_cf_traps.csv — c-Si single trap E = 0.15 eV, T = 80 K, ν₀ = 1×10¹². Expected: f₀ ≈ 724 kHz (±5%), n_steps = 1, ΔC ≈ 0.3 nF. (2π·f₀ agrees with the emission frequency ωi = 2ν₀T²exp(−E/kT) to within 5%.)

A5 — Trap DOS + Urbach (tDOS) · lcr_tdos
While A4 finds a single trap frequency, A5 converts capacitance–frequency data into a defect-density-versus-energy distribution; it also measures the band-edge "blurring" (Urbach energy) if present. Like recording an orchestra and teasing out how many instruments play at each note, it shows how many traps there are at each energy.
- Why it's done: To understand whether the defects are at a single energy or in a distribution.
- What it teaches / measures: The energy-resolved trap density NT(E), the peak energy and the Urbach energy EU (a measure of disorder).
- Where it's used: Thin-film disorder/quality assessment (e.g. CIGS, perovskite).
Purpose: Converts C(ω) data into an energy-resolved trap density NT(E) distribution using the Walter trap-DOS method; extracts the Urbach energy EU if a band tail is present.
Physics and method. The Walter transform:
dC/dω is taken with a smoothed derivative. The peak energy Epeak and the peak density are determined within NT(E). In the band-tail region below the peak energy, ln NT ≈ −E/EU is linear; the Urbach energy EU = −1/slope (meV) is computed from the slope.
Input columns: freq_hz, cp_f (at least 6 points).
Parameters:
| Parameter | Unit | Description | Default |
|---|---|---|---|
nu0 | s⁻¹K⁻² | Attempt frequency ν₀ | 1×10¹² |
v_bi_v | V | Built-in voltage | 0.7 |
w_nm | nm | Depletion width W | 100 |
temperature_k | K | Measurement temperature (must match the generation T) | 300 |
smooth_window | — | Smoothing window | 7 |
Outputs: n_t_peak_cm3_ev (cm⁻³eV⁻¹, peak DOS), e_peak_ev (eV, peak energy), e_u_mev (meV, Urbach energy — only if a clean band tail is resolved), r2 (Urbach fit goodness). Uncertainty: u(EU) = (um/m²)·1000.
Example file: examples/analysis/25_lcr_tdos.csv — CIGS, T = 55 K, Vbi = 0.8 V, W = 100 nm, ν₀ = 1×10¹², band tail EU = 20 meV + traps at 0.10/0.28 eV (emission ~661 kHz). Expected: peak DOS > 0, 0 ≤ Epeak ≤ 0.65 eV, EU > 0 if present.
temperature_k parameter must equal the temperature at which the measurement was taken; the E(ω) transform depends directly on temperature. If the wrong temperature is entered the energy axis shifts. Because CSV metadata is not carried, verify this value manually.
A6 — Admittance Dit (Conductance Method) · lcr_admittance_dit
Electronic states trapped at the interface where two materials meet (e.g. oxide/semiconductor) degrade device performance. This module counts the density of these interface defects from the peak the conductance makes versus frequency. Like counting the mortar cracks between two bricks, it tells you how "clean" the bonding surface is.
- Why it's done: To measure interface quality quantitatively and to track process improvement.
- What it teaches / measures: The interface trap density Dit and the trap time constant τit.
- Where it's used: MOS/MIS structures, gate oxide and passivation quality control.
Purpose: Extracts the interface trap density Dit and the trap time constant τit using the Nicollian–Brews conductance method.
Physics and method. The parallel conductance quantity Gp/ω:
This quantity peaks at ω = 1/τit. From the peak value:
Input columns: freq_hz, cp_f, g_s (at least 6 points).
Parameters:
| Parameter | Unit | Description | Default |
|---|---|---|---|
area_cm2 | cm² | Device area | 0.09 |
cox_f | F | Oxide capacitance (0 → max Cp is used) | 0.0 |
Outputs: d_it_cm2_ev (cm⁻²eV⁻¹), f_peak_hz (Hz, the Gp/ω peak), tau_it_s (s).
Example file: examples/analysis/26_lcr_admittance_dit.csv — c-Si single interface state (E = 0.15 eV trap, T = 80 K, emission ~724 kHz), A = 0.09 cm². Expected: Dit ∈ [1×10¹⁰, 1×10¹⁴] cm⁻²eV⁻¹, τit = 1/(2π·fpeak), fpeak within the sweep band.
cox_f parameter; otherwise the largest capacitance in the sweep is taken as Cox.
A7 — TAS Arrhenius · lcr_tas_arrhenius
A trap's emission rate depends very strongly on temperature. This module combines the characteristic frequencies measured at different temperatures to extract the trap's activation energy (its fingerprint). Like computing the "melting energy" of ice by watching how fast it melts at different temperatures, the temperature lever reveals the trap's energy.
- Why it's done: To identify a trap by its energy and compare it with the literature.
- What it teaches / measures: The trap activation energy EA and the attempt frequency ν₀.
- Where it's used: Deep-level defect identification and material reliability studies.
Purpose: Extracts the trap activation energy EA and the attempt frequency ν₀ from a temperature-resolved admittance (TAS) stack via Arrhenius analysis.
Physics and method. At each temperature the C–f inflection frequency ω₀(T) is found from the −dC/d(ln ω) peak. An Arrhenius line is then fitted:
Linear fit between ln(ω₀/T²) and 1/T: slope = −EA/kB → EA (eV); intercept → ν₀ = exp(b)/2.
Input columns: temperature_k, freq_hz, cp_f (stack; at least 12 rows, ≥ 5 frequency points at each temperature). At least 4 resolvable temperatures are required.
Parameters: smooth_window (default 7).
Outputs: e_a_ev (eV), nu0_s_k2 (s⁻¹K⁻²), n_temperatures (number of resolved temperatures), r2. Uncertainty: u(EA) = |um|·kB/q.
Example file: examples/analysis/27_lcr_tas_arrhenius.csv — c-Si single trap, 9 temperatures 55–95 K, 1 Hz–100 MHz sweep. Expected: EA ≈ 0.15 eV (±10 meV), ν₀ ≈ 1×10¹² s⁻¹K⁻², n_temperatures = 9, r² > 0.95.

A8 — Carrier Lifetime (IS) · lcr_lifetime
From the resistance and capacitance in the impedance fit, this module computes how long, on average, a carrier "lives" before recombining. Like finding the average time people stay in a room from the entry–exit rate, a long lifetime usually means a more efficient device.
- Why it's done: To measure the recombination losses that limit device efficiency.
- What it teaches / measures: The recombination carrier lifetime τn = Rrec·Cμ.
- Where it's used: Solar cell efficiency diagnostics and material quality comparison.
Purpose: Extracts the recombination carrier lifetime τn = Rrec·Cμ using the Bisquert impedance spectroscopy (IS) interpretation.
Physics and method. Reuses the same circuit fit as A3 in read-only mode (single-source principle):
The uncertainty is computed with the same GUM propagation as A3. For single-condition (single bias/illumination) data the recombination order is not extracted (recombination_order = None; an injection/bias series is needed for the order) and τn(Voc) = τn is taken.
Input columns: z_re_ohm, z_im_ohm, freq_hz.
Parameters: circuit (default auto; same options as A3).
Outputs: tau_n_s (s), tau_n_at_voc_s (s), r_rec_ohm (Ω), c_mu_f (F), recombination_order (None for single condition).
Example file: examples/analysis/28_lcr_lifetime.csv — c-Si, Rrec = 5 kΩ, Cμ = 2 nF (same Z–f data as A3). Expected: τn ≈ 10 µs (±5%), Rrec ≈ 5 kΩ, Cμ ≈ 2 nF (±10%), recombination_order = None.

RPS / RUS Family (29–35)
This family vibrates a sample (drives it into resonance) and listens to its natural "ringing" frequencies. Just as the sound a glass makes when you tap it depends on its pitch, size and material, a sample's resonances reveal its stiffness (elastic modulus), piezoelectric response and internal friction.
- Why it's done: To measure the material's mechanical/elastic and piezoelectric properties non-destructively.
- What it teaches / measures: Resonance frequency, quality factor Q, acoustic attenuation, relative d₃₃, elastic modulus and the full elastic tensor Cij.
- Where it's used: Piezoelectric/ceramic material characterization, phase-transition studies and elastic-constant determination.
The RPS/RUS family reads a lock-in measurement file (harmonic, frequency, X/Y phase, R = |V| amplitude, set temperature) to extract resonance and elastic parameters. The data is grouped by the (harmonic, t_set_k) pair; each group must have at least 5 points.
Basic Lorentzian model (amplitude):
Physical interpretations (Migliori & Sarrao, Resonant Ultrasound Spectroscopy, Wiley 1997; Carpenter et al., EPJB 2003; Salje & Carpenter, J. Phys.: Condens. Matter 2011):
- f0² ∝ ceff/ρ — the square of the resonance frequency is proportional to the effective elastic modulus.
- area ∝ d₃₃ — the 1f peak area is proportional to the linear piezoelectric response strength (relative).
- FWHM = linewidth ∝ 1/Q — a measure of anelastic loss / domain-wall motion.
asymmetry_suspect note is added; in this case f0 and area may be biased. For unbiased f0/Q the complex (X/Y) two-pole fit (module 34) is preferred.peak_near_edge / area_truncation_suspect note is added.29 — RPS Lorentzian Fit · rps_lorentzian_fit
This module fits a standard bell curve (Lorentzian) to a resonance peak to extract the peak's exact position, sharpness and magnitude. Like measuring exactly what note a guitar string rings at and how "cleanly" it does so, the narrower the peak the less energy the material loses.
- Why it's done: To obtain the basic quantities of a resonance reliably and reproducibly.
- What it teaches / measures: The resonance frequency f0, the quality factor Q, the peak area and the linewidth (FWHM).
- Where it's used: The fundamental building block of all RPS analyses; single-resonance characterization.
Purpose: A Lorentzian fit to the single dominant resonance in each (harmonic, temperature) group; extracts f0, Q, area and linewidth.
Input columns: harmonic, freq_hz, r_v, t_set_k (+ optional x_v, y_v).
Parameters: harmonic (default 1; only the groups of the selected harmonic are fitted).
Outputs (values of the first successful group):
| Key | Unit | Description |
|---|---|---|
f0_hz | Hz | Resonance frequency |
q | — | Quality factor Q = f0/FWHM |
area_v_hz | V·Hz | Peak area = π·Rpeak·HWHM |
linewidth_hz | Hz | FWHM = f0/Q |
chi2, r2 | — | Goodness-of-fit metrics |
n_groups_fit | — | Number of groups fitted |
Uncertainties are propagated with GUM: u(Q) includes the cov(f0,HWHM) term; u(area) includes the cov(Rpeak,HWHM) term; u(FWHM) = 2·u(HWHM).
Example file: examples/analysis/29_rps_lorentzian_fit.csv — f0 = 800 kHz, Q = 200, Rpeak = 1×10⁻⁴ V, single peak @ 300 K. Expected: f0 ≈ 800 kHz (±0.2%), Q ≈ 200 (±5%), FWHM ≈ 4000 Hz (±5%), area ≈ π·10⁻⁴·2000 = 0.6283 V·Hz (±10%), r² > 0.95.

30 — RPS Acoustic Attenuation · rps_attenuation
This module tracks the material's internal friction (acoustic loss) by watching how much the resonance peak broadens with temperature. Like how quickly the sound of a ringing bell dies away, a broad peak = fast decay = high loss; it produces a pronounced peak at phase transitions.
- Why it's done: To detect temperature-dependent loss mechanisms (domain-wall motion, etc.).
- What it teaches / measures: The variation of the linewidth (FWHM) with temperature, i.e. the anelastic loss Q⁻¹.
- Where it's used: Phase-transition research and attenuation/internal-friction studies.
Purpose: Tracks acoustic attenuation (anelastic loss Q⁻¹) from the variation of the linewidth (FWHM) with temperature.
Physics: Q⁻¹ ∝ FWHM = f0/Q. Mechanisms such as domain-wall motion and point-defect relaxation make the linewidth temperature dependent; it peaks at a phase transition. The module first runs 29 (on the selected harmonic) and extracts the FWHM(T) series from the group results.
Input columns: harmonic, freq_hz, r_v, t_set_k.
Parameters: harmonic (default 1).
Outputs: linewidth_hz_at_min_t (Hz), linewidth_hz_at_max_t (Hz), n_temperatures. The FWHM at each temperature is also returned as an error-barred series.
Example file: examples/analysis/30_rps_attenuation.csv — two 1f groups: 300 K (f0 = 800 kHz, Q = 200 → FWHM = 4000 Hz) and 400 K (f0 = 790 kHz, Q = 180 → FWHM ≈ 4388.9 Hz). Expected: low-T FWHM ≈ 4000 Hz, high-T FWHM ≈ 4389 Hz (both ±5%), n_temperatures = 2; loss increasing with temperature (FWHMmax > FWHMmin).

31 — RPS Relative d₃₃ · rps_d33_rel
A piezoelectric material produces vibration under voltage; the strength of this response is measured by d₃₃. The module normalizes the area of the fundamental (1f) resonance peak to a reference temperature to track how d₃₃ varies with temperature. Like comparing how "loud" a speaker plays as the temperature changes against a reference.
- Why it's done: To see whether the piezoelectric strength weakens near a phase transition.
- What it teaches / measures: The relative (normalized) piezoelectric response d33_rel(T); the trend, not the absolute value.
- Where it's used: Near-Tc behavior studies in ferroelectric/piezoelectric materials.
Purpose: Tracks the relative piezoelectric response d₃₃ from the variation of the 1f peak area with temperature.
Physics: area1f(T) ∝ effective d₃₃; d33_rel(T) = area1f(T) / area1f(Tref). Only 1f groups are used. At Tref the value is 1.000 by definition (its uncertainty is exactly 0).
Input columns: harmonic, freq_hz, r_v, t_set_k. (A 1f fit at at least 2 different temperatures is required.)
Parameters: t_ref_k (reference temperature; default is the lowest T).
Outputs: d33_rel_at_min_t, d33_rel_at_max_t, n_temperatures. Uncertainty (GUM, independent fits, cov = 0): u²(dr) = (1/arearef)²·u²(areaT) + (areaT/arearef²)²·u²(arearef).
Example file: examples/analysis/31_rps_d33_rel.csv — Tref = 300 K. 300 K area = π·10⁻⁴·2000 = 0.6283; 400 K area = π·0.9×10⁻⁴·2194.4 = 0.6203. Expected: d33_rel(300 K) = 1.000, d33_rel(400 K) ≈ 0.6203/0.6283 = 0.9873 (±5%), n_temperatures = 2.

32 — RPS Nonlinearity Ratio · rps_nonlinearity_ratio
This module compares the second-harmonic (Xf) peak with the fundamental (1f) peak; the ratio tells you how "nonlinear" the material response is. Like feeding a pure note to a speaker and looking at how much unwanted extra tone appears at the output, it separates the linear piezoelectric contribution from the electrostrictive one.
- Why it's done: To separate the linear response that arises from symmetry breaking from the nonlinear response present in every phase.
- What it teaches / measures: The Xf/1f peak-area ratio (a measure of nonlinearity) and its variation with temperature.
- Where it's used: Ferroelectric phase-transition and symmetry diagnostics.
Purpose: Separates the piezoelectric (1f) and electrostrictive (Xf) responses from the ratio of the even-harmonic (Xf) peak area to the 1f area.
Physics: nonlinearity_ratio(T) = areaXf(T) / area1f(T). 1f represents the linear piezoelectric response (requires broken inversion symmetry), Xf the nonlinear / electrostrictive response (allowed even in a centrosymmetric phase) (Carpenter et al., EPJB 2003, Eqs. 4–5).
Input columns: harmonic (1 and Xf), freq_hz, r_v, t_set_k.
Parameters: harmonic_x (the Xf harmonic multiplier; default 2). The module runs separate Lorentzian fits for 1f and Xf and matches the common temperatures.
Outputs: ratio_at_min_t, ratio_at_max_t, n_temperatures. Uncertainty (GUM, independent fits).
Example file: examples/analysis/32_rps_nonlinearity_ratio.csv — 300 K: 1f (R = 1×10⁻⁴, Q = 200) area = 0.6283; 2f (R = 0.3×10⁻⁴, f0 = 800.2 kHz, Q = 150) area = π·0.3×10⁻⁴·2667.3 = 0.2513. Expected: ratio(300 K) ≈ 0.2513/0.6283 = 0.400 (±15%), n_temperatures = 2; 2f < 1f (ratio < 1, slight nonlinearity).

33 — RPS Relative Elastic Modulus · rps_elastic_modulus
The square of the resonance frequency is proportional to the material's stiffness (elastic modulus). This module tracks the relative stiffness from the variation of f0² with temperature and reveals the "softening" at phase transitions. Like the pitch of a guitar string dropping as it loosens when heated, a drop in pitch indicates the material is softening.
- Why it's done: To detect temperature-dependent elastic softening/stiffening and phase transitions.
- What it teaches / measures: The relative elastic modulus (f0(T)/f0(Tref))² and the temperature trend.
- Where it's used: Phase-transition/critical-behavior research and thermomechanical characterization of materials.
Purpose: Tracks the relative elastic modulus from the f0²(T)/f0²(Tref) ratio; reveals the softening at a phase transition.
Physics: Since f0² ∝ ceff/ρ, modulus_rel(T) = (f0(T)/f0(Tref))². 1.000 at Tref.
Input columns: harmonic, freq_hz, r_v, t_set_k. (At least 2 temperatures.)
Parameters: t_ref_k (default is the lowest T), harmonic (default 1).
Outputs: modulus_rel_at_min_t, modulus_rel_at_max_t, n_temperatures, r2_modulus_trend (the goodness of the modulus–T linear trend). Uncertainty (GUM): u²(mr) = (2f0T/f0ref²)²·u²(f0T) + (2f0T²/f0ref³)²·u²(f0ref).
Example file: examples/analysis/33_rps_elastic_modulus.csv — two 1f groups; f0(400 K)/f0(300 K) = 790/800. Expected: modulus_rel(300 K) = 1.000, modulus_rel(400 K) = (790/800)² = 0.97516 (±1%), n_temperatures = 2; softening at high T (modulusmax-T < modulusmin-T).

34 — RPS Multi-Mode Fit (RUS) · rps_multimode_fit
A single sample rings at many different frequencies simultaneously. This module automatically finds all the resonance peaks in the sweep and applies an advanced (complex X/Y) fit to each. Like playing a chord and teasing out each note within it, it prepares the list of modes needed for the subsequent elastic-tensor solution.
- Why it's done: To build an accurate and unbiased set of resonances (modes) for the elastic tensor inversion.
- What it teaches / measures: The number of modes, the f0/Q/amplitude values of each mode, and the mean Q.
- Where it's used: The mode-detection stage of RUS measurements; the preliminary step of the tensor solution.
Purpose: Detects all the resonances in the sweep and applies a complex (X/Y) two-pole fit to each (RUS "Auto-Mark"). Gives unbiased f0, Q, amplitude and linewidth per mode; prepares the measured mode set for the subsequent tensor inversion.
Physics and method. For a single mode, a driven damped harmonic oscillator (normalized complex Lorentzian) + complex background (feedthrough):
Fitting X and Y jointly removes the feedthrough-induced Fano asymmetry. Peaks are detected with scipy.signal.find_peaks (prominence = a fraction of the R range); each peak is fitted in its own adaptive window; quality gates (r2 ≥ r2_min, q_min ≤ Q ≤ q_max, finite u(f0) ≤ 5%·f0) and mode deduplication are applied.
Input columns: harmonic, freq_hz, x_v, y_v, r_v, t_set_k (≥ 8 points per group).
Parameters:
| Parameter | Description | Default |
|---|---|---|
harmonic | Restrict to a single harmonic (None → all) | 1 |
min_prominence_frac | Min. peak prominence (fraction of R range) | 0.05 |
r2_min | Min. complex-fit r² for mode acceptance | 0.90 |
Outputs (summary of the first group): n_modes, f0_first_hz (Hz, the lowest-frequency mode), q_first, mean_q. All mode tables are stored as the mode_groups scalar for the tensor inversion.
Example file: examples/analysis/34_rps_multimode_rus.csv — cubic RPR 2.5 × 5 × 9 mm, ρ = 6000 kg/m³, C11 = 200, C12 = 110, C44 = 70 GPa, Visscher forward spectrum (order 10), 10 resonances, Q = 3000. Expected: n_modes ∈ [8, 14] (≥ 8 resolved), lowest mode f0 ≈ 119.4 kHz (±0.2%), Qfirst ∈ [2000, 4000].

35 — RUS Elastic-Tensor Inversion · rps_elastic_tensor
This module works backward from the measured resonance modes and the sample's dimensions/density to solve for all the independent elastic constants (Cij) of the material. Like back-calculating from all the tones a bell produces what metal it is made of and how stiff it is, it extracts a complete elastic identity from a single measurement.
- Why it's done: To obtain the full elastic tensor and the average moduli from a single small sample.
- What it teaches / measures: The independent Cij constants, the VRH aggregate moduli (K, G, E, ν) and the Zener anisotropy.
- Where it's used: Elastic-constant determination in materials science, crystal anisotropy and quality verification.
Purpose: Inverts the measured multi-mode resonance spectrum of a sample with known geometry for the independent elastic constants (Cij) of the selected crystal symmetry; additionally reports the Voigt–Reuss–Hill aggregate moduli (K, G, E, ν) and the Zener anisotropy. This is the flagship output capability of RUS.
Physics and method. The forward problem is the Rayleigh–Ritz / Visscher eigenvalue problem for a free–free rectangular parallelepiped (RPR) (Γa = ω²Ea; W. M. Visscher et al., JASA 90, 2154, 1991). The inverse problem applies nonlinear least squares on the relative frequency residual to the measured frequencies:
The number of independent constants depends on the symmetry:
| Symmetry | Independent constants | Count |
|---|---|---|
| Isotropic | c11, c12 | 2 |
| Cubic | c11, c12, c44 | 3 |
| Hexagonal | c11, c12, c13, c33, c44 | 5 |
| Tetragonal | c11, c12, c13, c33, c44, c66 | 6 |
| Orthorhombic | c11, c22, c33, c12, c13, c23, c44, c55, c66 | 9 |
The aggregate moduli are computed with the Voigt–Reuss–Hill average (Hill 1952), and the Zener anisotropy with A = 2·C44/(C11 − C12) (meaningful only for cubic/isotropic). Born elastic stability (the positive-definiteness of the Voigt matrix) is checked.
Input columns: harmonic, freq_hz, x_v, y_v, r_v, t_set_k (multi-mode extraction is done first with 34; ≥ as many modes as the number of independent constants are required).
Parameters:
| Parameter | Unit | Description | Default |
|---|---|---|---|
symmetry | — | Crystal symmetry (isotropic/cubic/hexagonal/tetragonal/orthorhombic) | cubic |
lx_mm, ly_mm, lz_mm | mm | Sample edge lengths | 4 / 5 / 6 |
density_kg_m3 | kg/m³ | Sample density | 6000 |
harmonic | — | Harmonic to use | 1 |
order | — | Forward-solver order | 12 |
c11_gpa…c66_gpa | GPa | Initial elastic-constant guesses | 150/75/75/150/45/45 |
n_modes_use | — | Number of lowest modes to use (0 = all) | 0 |
piezoelectric_sample | — | If 1, adds a "stiffened tensor" warning | 1 |
Outputs: c11_gpa, c12_gpa, c44_gpa (+ c13/c33/c66/c22/c23/c55 depending on symmetry), bulk_K_gpa, shear_G_gpa, young_E_gpa, poisson_nu, anisotropy_A, rms_rel_error, n_modes_fit. The uncertainties (uCij) reflect only the random frequency-fit spread; they do not include mode-assignment, truncation and geometry/density errors (a lower bound).
Example file: examples/analysis/35_rps_elastic_tensor_rus.csv — cubic, 2.5 × 5 × 9 mm, ρ = 6000, 12 modes; true C11 = 200, C12 = 110, C44 = 70 GPa; off-truth initial guess 180/120/62 GPa. Expected: C11 ≈ 200 (±5%), C12 ≈ 110 (±8%), C44 ≈ 70 (±5%), Zener A = 2·70/(200−110) = 1.556 (±10%), rms_rel_error < 1%. VRH aggregate: K ≈ 140, G ≈ 58.6, E ≈ 154.4 GPa, ν ≈ 0.316.
piezoelectric_sample = 1 this warning is added automatically. For absolute Cij use a passive/mechanically-driven sample.analysis_resolved = False and flags the values as "PROVISIONAL — must not be used"; review the initial guess, the number of modes and the solver order. Take into account the assignment_suspect (suspected mode assignment) and truncation_not_converged (insufficient order) notes.
Troubleshooting and Tips
| Symptom | Possible cause | Solution |
|---|---|---|
| Module returned "insufficient data" | Column names differ from expected / too few points | Verify the CSV headers (e.g. bias_v, cp_f, freq_hz, harmonic, r_v, t_set_k); ensure the minimum point counts |
Impedance/RPS fit failed (analysis_resolved = False) | SciPy is not installed or it did not converge | Install SciPy; review the initial guesses / circuit selection |
| f0 or EA far from expected | Measurement temperature entered incorrectly (tDOS/CF/TAS) | Measure at a temperature that brings trap emission into the device band; match temperature_k to the measurement value |
| Trap step not visible | Sweep band does not cover the emission frequency | Do a log sweep of at least ±2 decades around f₀ |
| RPS area/d₃₃ biased | Peak near the sweep edge (peak_near_edge) | Widen the sweep to include f0 ± 5·HWHM |
| Elastic tensor "unreliable" ✕ | Insufficient modes / poor initial guess / low order | Try a wider frequency sweep, a lower prominence threshold, a higher order and an initial Cij close to the truth |
r2/rms_rel_error and the relevant warning notes; these are the primary indicators of output reliability.