Skip to content
Home/Blog/Measuring T1 and T2 on Real Hardware with Qiskit Experiments
QiskitHardwareBest Practices

Measuring T1 and T2 on Real Hardware with Qiskit Experiments

A practical walkthrough of the T1, T2Ramsey, and T2Hahn experiment classes in Qiskit Experiments 0.14: how to build the delay-sweep circuits, run them, and read the fitted coherence times out of the results.

FreeQuantumComputing
·· 8 min read

Our piece on T1 and T2 covers what the two numbers mean: T1 as energy relaxation, T2 as the loss of phase information. This post covers the other half, how you measure them, using Qiskit Experiments (version 0.14 as of this writing), the library that automates the delay sweeps and curve fitting instead of you writing that machinery by hand.

pip install qiskit-experiments

Why you need a noisy backend

An ideal, noiseless simulator never decoheres, so running these experiments against a plain AerSimulator() gives you a flat line and nothing to fit. You need either real hardware or a simulator seeded with a realistic noise model. The easiest path for testing the workflow is AerSimulator.from_backend() on a fake backend snapshot, which carries over that device's real calibration data, including its T1 and T2:

from qiskit_ibm_runtime.fake_provider import FakePerth
from qiskit_aer import AerSimulator

backend = AerSimulator.from_backend(FakePerth())

Measuring T1: the delay sweep

T1 works by preparing |1⟩, waiting a variable delay, then measuring how much population has decayed back to |0⟩:

import numpy as np
from qiskit_experiments.library import T1

delays = np.arange(0, 300e-6, 10e-6)  # 0 to 300 microseconds
exp = T1(physical_qubits=(0,), delays=delays)

exp_data = exp.run(backend=backend).block_for_results()
exp_data.analysis_results(dataframe=True)

The physical_qubits argument targets a specific qubit on the device rather than an abstract circuit qubit. The result table's T1 row gives the fitted decay constant with its uncertainty, in seconds. exp_data.figure(0) returns the decay curve as a plotted figure if you want to see the exponential fit visually rather than only the fitted number.

Measuring T2: Ramsey fringes

T2Ramsey measures dephasing by preparing a superposition, waiting a delay, then applying a second pulse with a deliberate small detuning (osc_freq) so the result oscillates as the delay increases. The envelope of that oscillation, not the oscillation itself, decays with T2:

from qiskit_experiments.library import T2Ramsey

delays = list(np.arange(1e-6, 50e-6, 2e-6))
exp = T2Ramsey((0,), delays, osc_freq=1e5)
exp.set_transpile_options(scheduling_method="asap")

exp_data = exp.run(backend=backend, shots=2000).block_for_results()
exp_data.analysis_results(dataframe=True)

The results table reports both a T2star value (T2Ramsey measures what's conventionally written T2*, coherence time without any refocusing) and the fitted Frequency, which should land close to the osc_freq you set if the detuning was applied correctly.

Measuring T2 with an echo: T2Hahn

T2* is sensitive to slow, low-frequency noise (like drift in a control field) that a Hahn echo sequence cancels out by inserting a refocusing pulse partway through the delay. T2Hahn measures the longer coherence time that survives once that slow noise is cancelled:

from qiskit_experiments.library import T2Hahn

delays = [round(float(d) * 1e-6, 6) for d in range(0, 51, 5)]
exp = T2Hahn(physical_qubits=(0,), delays=delays, num_echoes=1)

exp_data = exp.run(backend=backend, shots=2000).block_for_results()
exp_data.analysis_results(dataframe=True)

num_echoes controls how many refocusing pulses get inserted into the delay. More echoes cancel more noise but add more gate error from the extra pulses themselves, so the reported T2Hahn value is one point on a real trade-off, not a single ground-truth number.

Why T2* and T2Hahn disagree

If you run both experiments on the same qubit, expect T2Hahn to report a longer coherence time than T2Ramsey's T2*. That gap isn't a measurement error. T2* is sensitive to noise sources an echo sequence cancels, so the two experiments are measuring genuinely different things: T2* is closer to what an uncorrected circuit experiences, while T2Hahn shows what's recoverable if your pulse sequence includes refocusing. A third experiment class, Tphi, isolates pure dephasing from the T1-driven contribution using the T1 and T2 values together, following the relationship 1/T2 = 1/(2·T1) + 1/Tφ covered in our T1 vs T2 explainer.

Reading results without guessing at column names

Every experiment above returns its fit through the same interface:

df = exp_data.analysis_results(dataframe=True)
print(df[["name", "value", "quality"]])

The quality column flags whether the fit converged cleanly (good) or not, worth checking before trusting a number, especially on real hardware where a poorly chosen delay range produces a curve with too few points in the decay region to fit reliably.

Try this next

  • Run T1 at increasing delay ranges and watch the fit quality degrade once your delays extend well past several multiples of the true T1, where almost every shot has already decayed and there's no curve left to fit.
  • Compare T2Ramsey and T2Hahn results on the same fake-backend qubit and check whether the gap matches what the device's calibration data reports for Tphi.
  • Read the Qiskit Experiments manuals for the full characterization library: fine-amplitude and fine-frequency experiments, readout error mitigation, and randomized benchmarking, which our companion post covers.