Langkau ke kandungan utama
Projek ini dalam fasa beta. Jumpa pepijat? Buat isu GitHub. Ada soalan atau idea? Tanya dalam Discussions — kami suka dengar maklum balas anda!
Bagaimana kualiti terjemahan pada halaman ini?

Resonans magnetik nuklear dengan Qiskit

Untuk modul Qiskit in Classrooms ini, pelajar mesti mempunyai persekitaran Python yang berfungsi dengan pakej berikut dipasang:

  • qiskit v2.1 atau lebih baharu
  • qiskit-ibm-runtime v0.40.1 atau lebih baharu
  • qiskit-aer v0.17 atau lebih baharu
  • scipy dan matplotlib (untuk penyuaian dan pemplotan)
  • pylatexenc (untuk memaparkan gambar rajah circuit)

Untuk menyediakan dan memasang pakej di atas, lihat panduan Install Qiskit. Untuk menjalankan job pada komputer kuantum sebenar, pelajar mesti menyediakan akaun dengan IBM Quantum® dengan mengikuti langkah dalam panduan Set up your IBM Cloud® account.

Modul ini telah diuji dan menggunakan kira-kira 5 minit masa QPU. Ini ialah anggaran, dan penggunaan sebenar anda mungkin berbeza.

Pengenalan​

Apabila ahli kimia menjalankan eksperimen NMR, mereka meletakkan sampel spin nuklear dalam medan magnet yang kuat, menggunakan denyutan frekuensi radio (RF), dan mengukur isyarat yang kembali. Teknik ini berasaskan beberapa idea daripada mekanik kuantum bagi zarah spin-1/2 dalam medan magnet. Spin itu mempunyai dua aras tenaga yang dipisahkan oleh tenaga yang sepadan dengan frekuensi Larmor yang tertentu. Denyutan resonans pada frekuensi itu mengalihkan spin ke satah melintang, di mana ia berpusing dan mengaruh isyarat yang kemudian pudar dengan dua masa tertentu, T1T_1 dan T2T_2.

Qubit superkonduktor ialah versi kejuruteraan bagi objek yang sama: sistem kuantum dua aras yang boleh dikawal. Keadaan ∣0⟩|0\rangle dan ∣1⟩|1\rangle adalah analog spin-atas dan spin-bawah, gate yang kita gunakan untuk memutarkannya adalah analog denyutan RF, dan ia kehilangan koheren dengan T1T_1 dan T2T_2 tersendiri. Ini bukan sekadar perbandingan longgar; sesetengah pemproses kuantum eksperimen terawal pada penghujung 1990-an dan awal 2000-an menggunakan NMR.

Dalam modul ini anda akan menggunakan komputer kuantum sebenar untuk menjalankan eksperimen pencirian yang sama seperti yang dilakukan oleh ahli spektroskopi NMR (atau jurutera kuantum yang menentukur perkakasan):

  • Rabi / nutasi — memacu spin dan melihatnya berputar. Beginilah cara anda menentukur putaran π\pi atau π/2\pi/2.

  • T1T_1 — relaksasi spin-kekisi, pereputan spin teruja kembali ke keseimbangan.

  • T2T_2 — relaksasi spin-spin (nyahfasa), diukur dengan eksperimen Ramsey dan difokus semula dengan gema Hahn.

  • Spektroskopi NMR (anjakan kimia dan gandingan JJ) — mensimulasikan molekul kecil pada beberapa qubit dan membaca spektrum multipletnya untuk memulihkan kesambungan melalui peraturan n+1n+1.

Bagi setiap konsep, kita mula-mula memberikan teori minimum, kemudian melaksanakan eksperimen dalam Qiskit mengikut aliran kerja Qiskit patterns empat langkah.

Teori​

Zarah spin-1/2 dalam medan magnet​

Nukleus spin-1/2 mempunyai momen magnet μ=γℏI\boldsymbol{\mu} = \gamma \hbar \mathbf{I}, dengan γ\gamma ialah nisbah giromagnet. Dalam medan statik B0B_0 sepanjang zz, dua keadaan spin berpecah dari segi tenaga (kesan Zeeman):

E±=∓12γℏB0,ΔE=γℏB0=ℏω0.E_{\pm} = \mp \tfrac{1}{2}\gamma \hbar B_0, \qquad \Delta E = \gamma \hbar B_0 = \hbar \omega_0 .

Jurang tenaga mentakrifkan frekuensi Larmor (resonans) ω0=γB0\omega_0 = \gamma B_0. Momen magnet berpusing mengelilingi B0B_0 pada frekuensi yang sama ini.

Untuk memutarkan spin kita menggunakan medan RF berayun pada (atau berhampiran) ω0\omega_0. Dalam bingkai yang berputar pada frekuensi pemacu (bingkai berputar), pemacu resonans memutarkan vektor Bloch mengelilingi paksi dalam satah xx-yy. Sejauh mana ia berputar (sudut selak) ditentukan oleh kekuatan dan tempoh denyutan. Dua pilihan paling penting: denyutan 90∘90^\circ mengalihkan spin +1/2+1/2 ke satah melintang, dan denyutan 180∘180^\circ memutarkannya sepenuhnya ke −1/2-1/2.

Menterjemah antara jargon NMR dan pengkomputeran kuantum​

Qubit ialah sistem dua aras, secara matematik serupa dengan spin-1/2 dalam medan magnet — jadi walaupun kita berjalan pada pemproses kuantum dan bukan nukleus, fizik yang mendasari NMR adalah fizik yang sama. Hanya perbendaharaan katanya berbeza. Jadual ini membantu anda berbual dengan ahli kimia fizik dan pakar pengkomputeran kuantum.

NMR / spin-1/2Pemproses kuantum (qubit)
Spin-atas / spin-bawah∣0⟩\ket{0} / ∣1⟩\ket{1}
Jurang Zeeman ΔE=ℏω0\Delta E = \hbar\omega_0Tenaga peralihan qubit ℏω01\hbar\omega_{01}
Frekuensi Larmor ω0\omega_0Frekuensi qubit ω01\omega_{01}
Denyutan RF resonans (sudut selak θ\theta)Gate putaran qubit tunggal RX(θ)R_X(\theta)
Denyutan 90∘90^\circ / 180∘180^\circRX(π/2)R_X(\pi/2) / RX(π)R_X(\pi)
Relaksasi spin-kekisi T1T_1Masa relaksasi tenaga qubit T1T_1
Relaksasi spin-spin T2T_2Masa nyahfasa qubit T2T_2
NutasiAyunan Rabi
Pereputan induksi bebas (FID), gema HahnJujukan Ramsey, gema

Segala yang berikut ialah latihan mengukur lajur sebelah kanan dan membacanya sebagai lajur sebelah kiri.

Sediakan persekitaran Qiskit​

Kita mengikut aliran kerja Qiskit patterns sepanjang masa:

  1. Petakan masalah kepada circuit kuantum.

  2. Optimumkan circuit untuk pelaksanaan (transpile kepada backend).

  3. Laksanakan menggunakan primitif IBM Quantum.

  4. Pasca-proses dan analisis.

Mula-mula kita memuatkan perkhidmatan runtime dan memilih backend sebenar yang paling kurang sibuk. Jika anda belum menyimpan kelayakan anda, lihat halaman dokumentasi tentang cara menyimpan kelayakan log masuk anda.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"matplotlib": "matplotlib", "numpy": "numpy", "qiskit": "qiskit", "qiskit_aer": "qiskit-aer", "qiskit_ibm_runtime": "qiskit-ibm-runtime", "scipy": "scipy"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
# Load the IBM Quantum Compute Service and select the least-busy real backend
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler, Batch

# After setup, this picks up your saved credentials automatically:
service = QiskitRuntimeService()

backend = service.least_busy(operational=True, simulator=False, min_num_qubits=156)
print(f"Selected backend: {backend.name}")
Selected backend: ibm_kingston

Gunakan sel di bawah untuk bertukar antara perkakasan sebenar dan simulator setempat bagi keseluruhan notebook. Menjalankan pada perkakasan ialah tujuan modul ini, tetapi jika terdapat masalah kesambungan atau penggunaan, simulator boleh menjadi sandaran. Tetapkan USE_HARDWARE = True untuk menjalankan pada QPU yang dipilih di atas.

import numpy as np
from itertools import combinations
from qiskit_aer import AerSimulator
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import EstimatorV2 as Estimator

USE_HARDWARE = True # <-- set True to run on the QPU selected above
USE_BATCH = False # Safer for a class with pauses; set True for an uninterrupted run

if USE_HARDWARE:
run_backend = backend # the real QPU selected above
else:
# Local testing mode: an Aer simulator that mimics the selected device -- its noise model,
# coupling map, and qubit count -- while layout choices still use real calibration data.
run_backend = AerSimulator.from_backend(backend)

# --- Choose connected qubits with low readout error. --------------------------------------
def readout_error(q):
props = backend.target["measure"].get((q,))
return props.error if props is not None and props.error is not None else 1.0

coupling_map = backend.coupling_map or backend.target.build_coupling_map()
edges = {tuple(sorted(edge)) for edge in coupling_map.get_edges() if edge[0] != edge[1]}

# AX needs one connected pair.
AX_LAYOUT = list(min(edges, key=lambda edge: sum(readout_error(q) for q in edge)))

# AX2 needs one qubit connected to two neighbours; the first entry is the central A qubit.
neighbors = {q: set() for q in range(backend.num_qubits)}
for q0, q1 in edges:
neighbors[q0].add(q1)
neighbors[q1].add(q0)
ax2_layouts = (
[a, x1, x2]
for a, adjacent in neighbors.items()
for x1, x2 in combinations(adjacent, 2)
)
AX2_LAYOUT = min(ax2_layouts, key=lambda layout: sum(readout_error(q) for q in layout))

# Use a long-lived qubit for the single-qubit experiments.
def best_qubit(backend):
return max(
range(backend.num_qubits), key=lambda q: backend.qubit_properties(q).t2 or 0.0
)

QUBIT = best_qubit(backend)
qp = backend.qubit_properties(QUBIT)
print(
f"Using qubit {QUBIT} for single-qubit experiments: "
f"T1 = {qp.t1 * 1e6:.0f} us, T2 = {qp.t2 * 1e6:.0f} us"
)
print(f"Using physical qubits {AX_LAYOUT} for AX")
print(f"Using physical qubits {AX2_LAYOUT} for AX2 (A first, then the two X spins)")

pm_q = generate_preset_pass_manager(
optimization_level=1, backend=run_backend, initial_layout=[QUBIT]
)
pm_ax = generate_preset_pass_manager(
optimization_level=1, backend=run_backend, initial_layout=AX_LAYOUT
)
pm_ax2 = generate_preset_pass_manager(
optimization_level=1, backend=run_backend, initial_layout=AX2_LAYOUT
)

# Job mode is the default because a classroom pause can deactivate a Batch. On the Open plan,
# a Batch has a 10-minute maximum lifetime and deactivates after 1 minute with no queued job.
batch = Batch(backend=run_backend) if USE_BATCH else None
execution_mode = batch if batch is not None else run_backend
sampler = Sampler(mode=execution_mode)
estimator = Estimator(mode=execution_mode)
estimator.options.resilience_level = 0 # raw expectation values, no error mitigation
estimator.options.default_shots = 1000

mode_name = "Batch" if USE_BATCH else "individual jobs"
device_name = "hardware" if USE_HARDWARE else "local simulator (runtime local mode)"
print(f"Ready. Running on {device_name} using {mode_name}.")

Eksperimen: ayunan Rabi (nutasi)​

Teori​

Pacu spin pada resonans dan vektor Blochnya berputar dengan stabil dari kutub ke kutub — ia bernutasi. Jika kita menggunakan putaran dengan sudut selak θ\theta mengelilingi paksi-xx pada qubit yang bermula dalam ∣0⟩|0\rangle, kebarangkalian mendapatinya dalam ∣1⟩|1\rangle ialah:

P1(θ)=sin⁡2 ⁣(θ2)=12(1−cos⁡θ).P_1(\theta) = \sin^2\!\left(\tfrac{\theta}{2}\right) = \tfrac{1}{2}\bigl(1 - \cos\theta\bigr).

Ini ialah lengkung Rabi. Maksimum pertamanya ialah denyutan π\pi (penyongsangan penuh, denyutan 180∘180^\circ); denyutan π/2\pi/2 ialah suku pusingan (denyutan 90∘90^\circ yang mengalihkan spin ke satah melintang). Dalam NMR, lengkung ini ialah cara anda menentukur denyutan anda.

Kaveat eksperimen

Eksperimen Rabi literal menyapu amplitud atau tempoh pemacu dalam masa. Itu memerlukan kawalan aras denyutan, yang telah dialih keluar dalam Qiskit v2.0. Di sini kita sebaliknya menyapu sudut putaran θ\theta bagi gate RX(θ)R_X(\theta). Lengkung dan pengenalpastian π\pi/π/2\pi/2 adalah serupa; satu-satunya perbezaan ialah kita memilih sudut secara langsung dan bukan menentukur tempoh denyutan. Pada perkakasan dengan gate pecahan, RX(θ)R_X(\theta) untuk θ\theta sewenang-wenangnya dijalankan secara natif.

Pandangan sfera Bloch​

Animasi di bawah menunjukkan nutasi: pemacu resonans memutarkan vektor Bloch dengan stabil mengelilingi paksi-xx, membawanya dari ∣0⟩|0\rangle ke arah ∣1⟩|1\rangle dan kembali. Inilah gerakan yang diukur oleh lengkung Rabi.

Petakan masalah kepada circuit​

Kita membina satu circuit berparameter, RX(θ)R_X(\theta) diikuti pengukuran, dan kemudian menilainya pada banyak sudut serentak.

from qiskit import QuantumCircuit
from qiskit.circuit import Parameter

theta = Parameter("theta")
rabi = QuantumCircuit(1, 1)
rabi.rx(theta, 0)
rabi.measure(0, 0)
rabi.draw("mpl")

Output of the previous code cell

Optimumkan untuk pelaksanaan​

Transpile kepada circuit Instruction Set Architecture (ISA) untuk backend yang dipilih.

rabi_isa = pm_q.run(rabi)

Laksanakan​

Kita menyapu θ\theta dari 00 hingga 4π4\pi (dua kitaran Rabi penuh). Menghantar tatasusunan nilai parameter sebagai satu Primitive Unified Bloc (PUB) menjalankan semuanya dalam satu job.

angles = np.linspace(0, 4 * np.pi, 41)
job = sampler.run([(rabi_isa, angles.reshape(-1, 1))], shots=1000)
rabi_result = job.result()

Pasca-proses dan analisis​

Ekstrak P1P_1 pada setiap sudut dan bandingkan dengan sin⁡2(θ/2)\sin^2(\theta/2).

import matplotlib.pyplot as plt

ba = rabi_result[0].data.c # BitArray, one entry per angle
shots = ba.num_shots
p1 = np.array([ba.get_counts(i).get("1", 0) / shots for i in range(len(angles))])

plt.figure(figsize=(7, 4))
plt.plot(angles, p1, "o", label="measured")
plt.plot(angles, np.sin(angles / 2) ** 2, "-", label=r"$\sin^2(\theta/2)$")
for k, name in [(np.pi / 2, r"$\pi/2$ (90°)"), (np.pi, r"$\pi$ (180°)")]:
plt.axvline(k, color="gray", ls="--", lw=1)
plt.text(k, 1.02, name, ha="center", fontsize=9)
plt.xlabel(r"flip angle $\theta$ (rad)")
plt.ylabel(r"$P_1$")
plt.title("Rabi / nutation curve")
plt.legend()
plt.tight_layout()
plt.show()

Output of the previous code cell

Semak kefahaman anda​

Pada lengkung yang anda ukur, P1P_1 mula-mula mencapai maksimumnya pada denyutan π\pi (θ=π\theta = \pi). Sekarang andaikan sebuah peranti tersalah tentu ukur, supaya sudut nominal θ\theta pada paksi-x sebenarnya menghasilkan putaran 1.05 θ1.05\,\theta.

(a) Pada sudut nominal berapakah maksimum pertama P1P_1 kini muncul? (b) Adakah menggunakan satu denyutan π\pi cara yang sensitif untuk mengesan ralat 5% ini?

Jawapan

(a) Maksimum muncul apabila putaran sebenar sama dengan π\pi, iaitu pada sudut nominal θ=π/1.05≈0.95π\theta = \pi/1.05 \approx 0.95\pi — anjakan kecil puncak ke kiri.

(b) Tidak. Denyut π\pi nominal menghasilkan putaran sebenar 1.05π1.05\pi, memberikan P1=sin⁡2(1.05π/2)≈0.994P_1 = \sin^2(1.05\pi/2) \approx 0.994 dan bukannya 11 — perubahan yang terlalu kecil untuk dilihat berbanding hingar pengukuran. Inilah sebabnya, untuk menentukur dengan tepat, ahli spektroskopi NMR menguatkan ralat dengan menggunakan putaran itu berkali-kali (contohnya kaedah 360∘360^\circ, atau rentetan denyut yang panjang), supaya ralat kecil bagi setiap denyut terkumpul menjadi sisihan besar yang boleh diukur. Kita kembali kepada idea ini dalam masalah cabaran.

Eksperimen: T1T_1 (relaksasi spin-kekisi)​

Teori​

Jika dibiarkan, spin teruja melepaskan tenaga kepada persekitarannya ("kekisi") dan berehat kembali ke arah keseimbangan terma. Populasi keadaan teruja mereput secara eksponen dengan masa relaksasi spin-kekisi T1T_1:

P1(τ)=e−τ/T1.P_1(\tau) = e^{-\tau/T_1}.

Bagi ahli kimia, T1T_1 menentukan kelewatan kitar semula yang perlu anda tunggu antara imbasan untuk NMR kuantitatif, dan ia melaporkan tentang jungkir-balik molekul serta dinamik. Pada qubit, ia ialah masa relaksasi tenaga, dan merupakan salah satu daripada dua nombor utama yang digunakan untuk memodelkan kesan dekoheren dalam komputer kuantum.

Eksperimen. Sediakan ∣1⟩|1\rangle dengan get XX (denyut π\pi), tunggu kelewatan berubah τ\tau, kemudian ukur. Pecahan yang masih berada dalam ∣1⟩|1\rangle menjejak pereputan itu.

Pandangan sfera Bloch​

Relaksasi T1T_1 mengembalikan keadaan teruja kepada keseimbangan, jadi vektor Bloch menyusur dari ∣1⟩|1\rangle kembali ke ∣0⟩|0\rangle sepanjang paksi zz.

Bina dan transpil imbasan kelewatan​

Tempoh kelewatan mestilah nilai konkrit (ia dijadualkan dalam masa perkakasan), jadi kita membina satu litar bagi setiap kelewatan.

# Scale the T1 delay sweep to the qubit's reported coherence, and snap each delay to an integer
# number of samples (dt) so there are no "duration rounded" warnings (as in the Ramsey/echo cells).
T1_us = (backend.qubit_properties(QUBIT).t1 or 100e-6) * 1e6 # reported T1 (us)
delays_us = np.linspace(0, 5 * T1_us, 20) # 0 .. ~5 T1 captures the full decay
print(f"T1 sweep: 0..{5*T1_us:.0f} us in {len(delays_us)} points")

dt = backend.dt
t1_circuits = []
for tau in delays_us:
n_dt = int(round(tau * 1e-6 / dt)) # integer samples -> no rounding warning
qc = QuantumCircuit(1, 1)
qc.x(0) # pi pulse: prepare |1>
qc.delay(n_dt, 0, unit="dt") # wait tau
qc.measure(0, 0)
t1_circuits.append(qc)

t1_isa = pm_q.run(t1_circuits)
T1 sweep: 0..1393 us in 20 points

Laksana​

t1_job = sampler.run([(c,) for c in t1_isa], shots=1000)
t1_res = t1_job.result()

Analisis — padankan eksponen​

from scipy.optimize import curve_fit

p1_t1 = np.array(
[r.data.c.get_counts().get("1", 0) / r.data.c.num_shots for r in t1_res]
)

def decay(t, A, T1, B):
return A * np.exp(-t / T1) + B

p0 = [1.0, 100.0, 0.0]
popt, _ = curve_fit(decay, delays_us, p1_t1, p0=p0, maxfev=10000)
T1_fit = popt[1]

plt.figure(figsize=(7, 4))
plt.plot(delays_us, p1_t1, "o", label="measured")
tt = np.linspace(0, delays_us.max(), 200)
plt.plot(tt, decay(tt, *popt), "-", label=rf"fit: $T_1$ = {T1_fit:.1f} µs")
plt.xlabel("delay τ (µs)")
plt.ylabel(r"$P_1$")
plt.title("$T_1$ relaxation")
plt.legend()
plt.tight_layout()
plt.show()
print(f"Measured T1 = {T1_fit:.1f} microseconds")

Output of the previous code cell

Measured T1 = 225.3 microseconds

Masa T1T_1 yang tepat berbeza antara eksperimen dan antara backend, tetapi anda sepatutnya melihat keputusan sekitar beberapa ratus mikrosaat.

Semak kefahaman anda​

Dalam NMR kuantitatif, anda diberitahu supaya menunggu kira-kira 5 T15\,T_1 antara imbasan. Menggunakan hukum pereputan, apakah pecahan magnetisasi keseimbangan yang telah pulih selepas 5 T15\,T_1?

Jawapan

Selepas 5 T15\,T_1, sisihan yang tinggal daripada keseimbangan ialah e−5≈0.0067e^{-5}\approx 0.0067, iaitu kira-kira 99.3% telah pulih.

Eksperimen: T2T_2, T2∗T_2^*​

Teori​

T1T_1 mengukur kehilangan tenaga. T2T_2 mengukur kehilangan koheren fasa dalam satah melintang. Kita boleh memerhatikannya dengan eksperimen Ramsey: denyut π/2\pi/2 memutar semua spin ke bawah sehingga khatulistiwa, semuanya menuju arah yang sama. Ia berpresesi Larmor, tetapi setiap satu berpresesi pada frekuensi yang sedikit berbeza, jadi ia terkembang di sepanjang khatulistiwa dan isyarat melintang bersih mereput, dengan masa pereputan ciri T2∗T_2^*.

Catatan sampingan untuk pembaca kuantum: Gambaran terkembang ini menunjukkan satu cara kehilangan koheren: serakan fasa tertentu yang saling memurnikan. Perlu diketahui bahawa ini bukan satu-satunya mekanisme. Koheren juga boleh hilang kerana fasa menjadi terkait (entangled) dengan persekitaran, jadi ia bukan lagi nilai tertentu yang dipegang oleh sistem sama sekali. Anda tidak dapat membezakan kedua-dua mekanisme itu hanya dengan memerhatikan pereputan isyarat, jadi gambaran terkembang ini ialah intuisi yang baik. Berhati-hatilah supaya tidak menganggapnya sebagai cerita yang lengkap atau literal.

Dua kesan menyebabkan spin hilang fasa:

  • Dekoheren tak boleh balik (atau secara berkesan tak boleh balik) yang timbul daripada gandingan tidak terkawal dengan darjah kebebasan lain, dicirikan oleh T2T_2 sebenar. Dalam NMR, ini umumnya datang daripada gerakan molekul yang memodulasi gandingan antara spin. Dalam pengkomputeran kuantum, ia sepadan dengan gandingan tidak diingini antara qubit dan persekitaran.
  • Ofset frekuensi statik atau berubah perlahan yang boleh balik, seperti ketakhomogenan medan, variasi frekuensi antara qubit, dan ralat penentukuran. Digabungkan dengan T2T_2 sebenar, ini menghasilkan masa pereputan ketara yang lebih pendek T2∗T_2^* yang diperhatikan dalam eksperimen Ramsey.

Jadi bagaimanakah kita memulihkan T2T_2 sebenar jika eksperimen Ramsey hanya memberitahu kita tentang T2∗T_2^*? Eksperimen kedua, yang dipanggil gema Hahn, membatalkan semua hingar jenis kedua untuk mendapatkan T2T_2 sebenar. Ia bermula sama seperti eksperimen Ramsey, dengan denyut π/2\pi/2, kemudian spin terkembang seperti sebelumnya. Selepas beberapa masa τ\tau, denyut π\pi dikenakan. Denyut itu membalikkan pengumpulan fasa yang disebabkan oleh ofset frekuensi statik, jadi spin memfokus semula selepas kelewatan kedua yang sama tempohnya, τ\tau.

T2∗T_2^* dan T2T_2 kedua-duanya nombor penting untuk diketahui dalam tetapan kimia dan tetapan pengkomputeran kuantum. Dalam tetapan kimia, T2∗T_2^* menentukan lebar garis bagi eksperimen NMR piawai (anda akan melihat maksudnya dalam bahagian kemudian). T2T_2 boleh memberitahu banyak perkara tentang molekul, seperti jungkir-balik molekul, dan perubahan dalam T2T_2 boleh menandakan bahawa molekul telah terikat pada sesuatu yang lebih besar. Dalam tetapan pengkomputeran kuantum, kita umumnya mahu T2T_2 dan T2∗T_2^* sepanjang yang mungkin, supaya kita mempunyai lebih banyak masa untuk menjalankan eksperimen sebelum dekoheren menguasai sistem. Satu keluarga teknik berasaskan gema Hahn melanjutkan masa ini dengan membatalkan hingar boleh balik, supaya litar secara ideal dihadkan oleh T2T_2 sebenar, bukan T2∗T_2^*. Ini dipanggil "penyahgandingan dinamik."

Pelaksanaan​

Apabila kita melaksanakan eksperimen Ramsey dan gema Hahn pada qubit, bacaan sedikit berbeza daripada kes NMR. Dalam NMR, anda boleh memerhatikan terus medan berayun yang teraruh oleh spin yang berpresesi pada frekuensi Larmor dalam satah melintang. Tetapi dengan qubit, kita hanya dapat mengukur unjurannya sepanjang paksi ZZ, iaitu sama ada ia ∣0⟩\vert 0 \rangle atau ∣1⟩\vert 1 \rangle. Oleh itu, bagi kedua-dua eksperimen, kita menamatkan dengan denyut π/2\pi/2 tambahan diikuti pengukuran. Denyut π/2\pi/2 ini menukar maklumat fasa qubit menjadi populasi.

Di bawah, kita menjalankan setiap eksperimen untuk menentukan T2∗T_2^* dan T2T_2.

Ramsey (T2∗T_2^{*}): Dua denyut π/2\pi/2 dengan masa kelewatan τ\tau​

Denyut π/2\pi/2 pertama mencondongkan vektor Bloch ke khatulistiwa, dan yang seterusnya menukar fasa vektor Bloch menjadi populasi. Oleh kerana fasa berubah mengikut masa apabila vektor Bloch berpresesi, kita melihat corak sinusoid dalam populasi sebagai fungsi masa presesi τ\tau. Apabila qubit kehilangan koheren fasa, kita sepatutnya melihat amplitud lengkung sinus ini mereput.

Beberapa kehalusan lagi untuk pembaca kuantum: Dalam eksperimen pengkomputeran kuantum, ayunan yang kita lihat sebenarnya bukan pada frekuensi Larmor, yang berada dalam julat GHz dan terlalu pantas untuk kita bezakan. Eksperimen kuantum beroperasi dalam bingkai berputar: bingkai yang berputar bersama qubit pada (hampir) frekuensi Larmor, jadi presesi pantas itu tidak kelihatan dan vektor Bloch kelihatan hampir pegun. Untuk melihat pinggir, kita sengaja menetapkan bingkai berputar kita sedikit menyimpang daripada frekuensi Larmor. Vektor Bloch kemudian kelihatan berpresesi pada sisihan kecil itu, dan kita mendapat isyarat berayun pada frekuensi sisihan. Di bawah, kita tidak menetapkan sisihan pada satu nilai; kita memilihnya supaya kira-kira sedozen pinggir merangkumi tetingkap pengukuran (yang saiznya kita sesuaikan dengan masa koheren qubit), yang memastikan ayunan mudah disampel tanpa aliasing. Satu lagi kerumitan: dalam Qiskit kita tidak mempunyai kawalan aras denyut yang diperlukan untuk menukar frekuensi denyut (yang menetapkan frekuensi bingkai berputar). Sebaliknya, kita menambah sisihan berkesan secara manual, menggunakannya untuk menetapkan fasa denyut Ramsey kedua. Ia agak dibuat-buat, tetapi hasilnya sama dan pereputan yang kita perhatikan masih T2∗T_2^* yang tulen.

Pandangan sfera Bloch​

Denyut π/2\pi/2 mencondongkan spin ke khatulistiwa; setiap satu kemudian berpresesi pada kadar yang sedikit berbeza dan ia terkembang, jadi vektor bersih (merah) mengecil apabila ia hilang fasa — pereputan ini ialah T2∗T_2^*.

# Adaptive Ramsey: scale the window to the reported coherence and choose the detuning so a fixed
# number of fringes span it. This decouples the point count from the window -- a long window stays
# cheap and cannot alias (we keep 8 samples per fringe).
T2_us = (backend.qubit_properties(QUBIT).t2 or 100e-6) * 1e6 # reported (echo) T2 (us)
ramsey_span = 0.5 * T2_us # window = half the reported T2
n_fringes = 12 # fringes across the window
f_detune = n_fringes / (
ramsey_span * 1e-6
) # adaptive detuning (Hz) -> low, so a long window is cheap
samp_per_fringe = 8
n_ramsey = n_fringes * samp_per_fringe + 1 # ~97 points, fixed regardless of T2
ramsey_delays_us = np.linspace(0, ramsey_span, n_ramsey)
print(
f"Ramsey sweep: 0..{ramsey_span:.0f} us in {n_ramsey} points "
f"(detuning {f_detune/1e3:.1f} kHz, {samp_per_fringe} samples/fringe)"
)

dt = backend.dt # seconds per sample
delays_dt = [int(round(t * 1e-6 / dt)) for t in ramsey_delays_us] # integer samples
actual_delays_us = np.array(delays_dt) * dt * 1e6 # true (snapped) delays for fitting

ramsey_circ = []
for n_dt, tau_us in zip(delays_dt, actual_delays_us):
qc = QuantumCircuit(1, 1)
qc.rx(np.pi / 2, 0)
qc.delay(n_dt, 0, unit="dt") # integer duration -> no rounding warning
qc.rz(
2 * np.pi * f_detune * tau_us * 1e-6, 0
) # detuning phase (uses the true delay)
qc.rx(np.pi / 2, 0)
qc.measure(0, 0)
ramsey_circ.append(qc)

ramsey_isa = pm_q.run(ramsey_circ)
ramsey_res = sampler.run([(c,) for c in ramsey_isa], shots=1000).result()
p1_ramsey = np.array(
[r.data.c.get_counts().get("1", 0) / r.data.c.num_shots for r in ramsey_res]
)

ramsey_circ[len(ramsey_circ) // 2].draw("mpl") # draw a sample circuit (mid-sweep)
Ramsey sweep: 0..248 us in 97 points (detuning 48.4 kHz, 8 samples/fringe)

Output of the previous code cell

Gema Hahn (T2T_2): Tambah denyut π\pi pemfokus semula di tengah​

Pandangan sfera Bloch​

Gema Hahn: spin terkembang seperti sebelumnya, kemudian denyut π\pi membalikkannya, jadi presesi berterusan mereka memfokus semula mereka bersama (vektor merah tumbuh semula), memulihkan koheren yang hilang akibat kehilangan fasa statik.

# Scale the echo sweep to the reported (echo) T2. The echo signal is monotonic (no fringes),
# so only the range matters here; 0 .. ~2.5 T2 shows the full decay for a clean fit.
T2_us = (backend.qubit_properties(QUBIT).t2 or 100e-6) * 1e6
echo_delays_us = np.linspace(0, 2.5 * T2_us, 24) # total free-evolution time
print(f"Echo sweep: 0..{2.5*T2_us:.0f} us in {len(echo_delays_us)} points")

dt = backend.dt
half_dt = [
int(round(t / 2 * 1e-6 / dt)) for t in echo_delays_us
] # samples per half-delay
actual_echo_us = np.array(half_dt) * 2 * dt * 1e6 # true total delay for fitting

echo_circ = []
for n_half in half_dt:
qc = QuantumCircuit(1, 1)
qc.rx(np.pi / 2, 0)
qc.delay(n_half, 0, unit="dt") # half the free-evolution, integer samples
qc.rx(np.pi, 0) # refocusing pi pulse
qc.delay(n_half, 0, unit="dt")
qc.rx(-np.pi / 2, 0)
qc.measure(0, 0)
echo_circ.append(qc)

echo_isa = pm_q.run(echo_circ)
echo_res = sampler.run([(c,) for c in echo_isa], shots=1000).result()
p1_echo = np.array(
[r.data.c.get_counts().get("1", 0) / r.data.c.num_shots for r in echo_res]
)

echo_circ[len(echo_circ) // 2].draw("mpl") # draw a sample circuit
Echo sweep: 0..1240 us in 24 points

Output of the previous code cell

Analisis: Padankan dan bandingkan kedua-dua pereputan​

# Initial guesses / bounds derived from the reported coherence so the fits track the scaled axes.
T2_us = (backend.qubit_properties(QUBIT).t2 or 100e-6) * 1e6

# Ramsey: decaying oscillation -> extract T2*
def ramsey_fn(t, A, T2s, f, phi, B):
return A * np.exp(-t / T2s) * np.cos(2 * np.pi * f * t + phi) + B

rp0 = [0.4, T2_us / 2, f_detune * 1e-6, 0.0, 0.5] # T2* guess ~ half the echo T2
rbounds = (
[0, 0.1, 0, -np.pi, 0],
[1, 2 * T2_us, 5, np.pi, 1],
) # keep the fit from collapsing to ~0
rpopt, _ = curve_fit(
ramsey_fn, ramsey_delays_us, p1_ramsey, p0=rp0, bounds=rbounds, maxfev=20000
)
T2_star = abs(rpopt[1])

# Echo: simple exponential envelope -> extract T2
def env(t, A, T2, B):
return A * np.exp(-t / T2) + B

epopt, _ = curve_fit(env, echo_delays_us, p1_echo, p0=[0.5, T2_us, 0.0], maxfev=10000)
T2 = abs(epopt[1])

fig, ax = plt.subplots(1, 2, figsize=(12, 4))
ax[0].plot(ramsey_delays_us, p1_ramsey, "o")
tt = np.linspace(0, ramsey_delays_us.max(), 400)
ax[0].plot(tt, ramsey_fn(tt, *rpopt), "-")
ax[0].set_title(rf"Ramsey: $T_2^*$ = {T2_star:.1f} µs")
ax[0].set_xlabel("τ (µs)")
ax[0].set_ylabel(r"$P_1$")
ax[1].plot(echo_delays_us, p1_echo, "o")
tt2 = np.linspace(0, echo_delays_us.max(), 400)
ax[1].plot(tt2, env(tt2, *epopt), "-")
ax[1].set_title(rf"Hahn echo: $T_2$ = {T2:.1f} µs")
ax[1].set_xlabel("τ (µs)")
plt.tight_layout()
plt.show()
print(f"T2* (Ramsey) = {T2_star:.1f} µs ; T2 (echo) = {T2:.1f} µs")

Output of the previous code cell

T2* (Ramsey) = 171.2 µs ; T2 (echo) = 326.0 µs

Di sini kita melihat ayunan Ramsey dan pereputan isyarat gema Hahn, seperti yang dijangkakan. Skala masa yang berkaitan bagi setiap pereputan ini ialah T2∗T_2^* dan T2T_2, masing-masing.

Semak kefahaman anda​

Anda lazimnya akan mendapati T2≳T2∗T_2 \gtrsim T_2^{*}. Jelaskan sebabnya dalam satu ayat, dan nyatakan kesan fizikal apa yang dialihkan oleh denyut π\pi gema Hahn, serta apa yang tidak dapat dialihkannya.

Jawapan

T2∗T_2^{*} merangkumi kedua-dua kehilangan fasa tak boleh balik dan serakan statik boleh balik, jadi ia mereput lebih pantas; denyut π\pi gema memfokus semula kehilangan fasa statik dan boleh balik (ketakhomogenan medan / ofset frekuensi tetap), meninggalkan hanya kehilangan fasa spin-spin tak boleh balik, iaitu T2T_2 sebenar. Gema tidak dapat membatalkan turun naik yang berubah antara dua separuh jujukan.

Spektroskopi NMR sesebuah molekul: Anjakan kimia dan gandingan JJ​

Daripada satu spin kepada molekul​

Eksperimen setakat ini mencirikan satu spin tunggal yang terpencil. NMR kimia sebenar membaca sebuah molekul (banyak spin berganding serentak) dan menggunakan spektrum yang terhasil untuk menyimpulkan ciri struktur molekul. Ini boleh memberitahu kita tentang dua kesan:

  • Anjakan kimia. Setiap nukleus yang berbeza secara kimia berpresesi pada frekuensi νi\nu_i yang sedikit berbeza, kerana elektron setempatnya melindungi medan yang dikenakan dengan jumlah yang berbeza. Kedudukan puncak oleh itu mengenal pasti persekitaran kimia (proton CH3_3 berbanding proton aromatik, sebagai contoh).

  • Gandingan skalar JJ. Interaksi melalui ikatan antara dua spin memecahkan setiap puncak menjadi multiplet. Nukleus dengan nn jiran setara dipecahkan kepada n+1n+1 garis dengan keamatan binomial, iaitu peraturan n+1n+1. Corak pemecahan mendedahkan kesambungan (nukleus mana yang terikat), dan jarak antaranya ialah pemalar gandingan JJ.

Eksperimen​

Untuk memodelkan ini dalam komputer kuantum kita, kita perlu melaksanakan Hamiltonian spin pada qubit. Dalam had gandingan lemah, medan tinggi (perbezaan anjakan kimia ≫\gg gandingan), bahagian XXXX dan YYYY gandingan itu purata keluar, meninggalkan hanya ZZZZ. Jadi Hamiltonian ialah (unit frekuensi sudut, ℏ=1\hbar=1):

H=∑iπ νi Zi⏟chemical shift  +  ∑i<jπ2 Jij ZiZj⏟J-coupling.H = \underbrace{\sum_i \pi\,\nu_i\, Z_i}_{\text{chemical shift}} \;+\; \underbrace{\sum_{i<j} \tfrac{\pi}{2}\,J_{ij}\, Z_iZ_j}_{J\text{-coupling}}.

Setiap nukleus ialah satu qubit: anjakan kimia ialah putaran ZZ satu qubit, dan gandingan ialah interaksi ZZZZ dua qubit.

Eksperimen berjalan seperti berikut. Denyut π/2\pi/2 mencondongkan setiap spin ke dalam satah melintang, dan spin berpresesi serta berganding selama masa tt. Kita merekod magnetisasi melintang kompleks s(t)=⟨X⟩+i⟨Y⟩s(t) = \langle X\rangle + i\langle Y\rangle yang dijumlahkan ke atas semua spin. Seperti dalam eksperimen Ramsey di atas, magnetisasi melintang ini menjejak sinusoid mereput sebagai fungsi masa presesi tt. Apabila kita mengambil transformasi Fourier isyarat itu, kita mendapat spektrum dengan puncak pada anjakan kimia νi\nu_i yang dipecahkan oleh gandingan skalar JijJ_{ij}.

nota

Kita mensimulasikan evolusi molekul dengan memetakan masa tt kepada sudut putaran: tt yang lebih besar bermakna putaran ZZ dan ZZZZ yang lebih besar, bukan litar yang lebih panjang atau lebih dalam. Jadi walaupun keadaan yang disimulasikan memang maju bersama tt (itulah yang menyebabkan pereputan induksi bebas (FID) berayun), qubit fizikal tidak pernah melahu lebih lama dan tiada dekoheren yang bergantung pada tt. FID yang disimulasikan oleh itu tidak pernah mereput dengan sendirinya. Bagi FID ideal yang sangat panjang tanpa had, garis spektrum akan menjadi sangat tajam; tetingkap pensampelan terhingga kita sebaliknya memberikan resolusi terhingga dan boleh menimbulkan kebocoran spektrum. Garis NMR sebenar mempunyai lebar terhingga yang ditentukan oleh T2∗T_2^*. Kita menambahnya semula dengan mendarab FID dengan tetingkap e−t/T2∗e^{-t/T_2^{*}} sebelum transformasi Fourier. Ini dipanggil apodisasi pelebaran garis, yang digunakan oleh ahli spektroskopi semasa pemprosesan untuk menetapkan lebar garis (menukar resolusi dengan nisbah isyarat-kepada-hingar). (Sel pilihan dalam Lampiran modul ini menunjukkan alternatif Trotter, di mana pereputan sebaliknya datang daripada dekoheren sebenar yang bertambah dengan kedalaman litar.)

Sistem AX​

Mari kita mulakan dengan sistem AX, molekul yang terdiri daripada dua spin berganding yang berbeza secara kimia. Label A dan X menandakan dua persekitaran spin yang berbeza secara kimia. Huruf-huruf itu sewenang-wenangnya, tetapi hakikat bahawa ia berjauhan dalam abjad menggambarkan ketidaksamaan kimia mereka.

Petakan dan optimumkan​

Kita menulis satu fungsi yang, diberi ofset anjakan kimia νi\nu_i dan gandingan JijJ_{ij}, mengembalikan litar penyediaan keadaan berparameter. Denyut π/2\pi/2 mencondongkan spin ke khatulistiwa, kemudian putaran ZZ mensimulasikan evolusi keadaan di bawah sebutan anjakan kimia dan gandingan JJ. Setiap νi\nu_i ialah ofset presesi kecil dalam Hz relatif kepada rujukan yang dipilih, atau pembawa bingkai berputar. Di sini kita menetapkannya secara manual; dalam molekul sebenar, perlindungan elektron mengubah medan magnet setempat dan menganjak resonans setiap nukleus relatif kepada rujukan itu. Ini dimodelkan oleh get RZR_Z satu qubit, satu bagi setiap spin, dan setiap νi\nu_i menentukan di mana puncak spin itu terletak dalam spektrum. Get ZZZZ dua qubit mengenakan gandingan JijJ_{ij}, yang memecahkan setiap puncak menjadi multiplet dan menetapkan jarak antara garisnya.

from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.quantum_info import SparsePauliOp

t = Parameter(
"t"
) # evolution time (arbitrary units; the frequencies below are in matching units)

def fid_circuit(offsets, couplings):
"""State-preparation circuit for a set of spins: a pi/2 pulse, then evolution under the
chemical-shift + J-coupling Hamiltonian for time t. No measurement -- the Estimator reads
<X> and <Y> directly.

offsets : list of chemical-shift frequencies nu_i, one per qubit
couplings : dict {(i, j): J_ij}
"""
n = len(offsets)
qc = QuantumCircuit(n)
qc.ry(np.pi / 2, range(n)) # pi/2 pulse: tip every spin into the transverse plane
for i, nu in enumerate(offsets):
qc.rz(2 * np.pi * nu * t, i) # chemical-shift precession -> line at nu_i
for (i, j), J in couplings.items():
qc.rzz(np.pi * J * t, i, j) # J-coupling -> splitting of size J
return qc

def transverse_obs(n):
"""Total transverse observables (sum over spins): (sum_i X_i, sum_i Y_i)."""
ox = SparsePauliOp.from_sparse_list(
[("X", [i], 1.0) for i in range(n)], num_qubits=n
)
oy = SparsePauliOp.from_sparse_list(
[("Y", [i], 1.0) for i in range(n)], num_qubits=n
)
return ox, oy

# AX system: two distinct chemical shifts, one coupling
ax_offsets = [6.0, -6.0] # chemical shifts nu_1, nu_2 (Hz)
ax_couplings = {(0, 1): 2.0} # J_12 = 2 Hz

ax_isa = pm_ax.run(fid_circuit(ax_offsets, ax_couplings))
fid_circuit(ax_offsets, ax_couplings).draw("mpl")

Laksana dan pasca-proses​

Kita menilai litar itu pada grid masa evolusi, dan Estimator mengembalikan ⟨X⟩\langle X\rangle dan ⟨Y⟩\langle Y\rangle pada setiap satu. Kita menggabungkannya menjadi FID kompleks ⟨X⟩+i⟨Y⟩\langle X\rangle + i\langle Y\rangle, mengenakan tetingkap apodisasi, dan mentransformasi Fourier hasilnya untuk mendapatkan spektrum.

# --- time grid ---
n_t = 128 # number of FID samples
dt = 1 / 32 # time step -> Nyquist frequency = 1/(2 dt) = 16 Hz
times = np.arange(n_t) * dt

# --- Step 3-4: Estimator returns <X> and <Y> directly (both quadratures in one job) ---
def run_fid(isa_circ, n, est):
"""Complex FID s(t) = sum_i <X_i> + i <Y_i> over the time grid, via the Estimator."""
ox, oy = transverse_obs(n)
ox = ox.apply_layout(isa_circ.layout) # map observables onto the transpiled qubits
oy = oy.apply_layout(isa_circ.layout)
params = times.reshape(-1, 1)
res = est.run(
[(isa_circ, ox, params), (isa_circ, oy, params)]
).result() # both quadratures, one job
return res[0].data.evs + 1j * res[1].data.evs

def spectrum(fid, T2=1.0):
sig = fid * np.exp(-times / T2) # apodization -> Lorentzian linewidth ~ 1/(pi T2)
spec = np.fft.fftshift(np.fft.fft(sig))
freq = np.fft.fftshift(np.fft.fftfreq(len(times), dt))
return freq, np.abs(spec)

fid_ax = run_fid(ax_isa, n=2, est=estimator)
freq, spec = spectrum(fid_ax, T2=1.0)

fig, ax = plt.subplots(1, 2, figsize=(12, 4))
ax[0].plot(times, fid_ax.real, label=r"Re $s(t)=\langle X\rangle$")
ax[0].plot(times, fid_ax.imag, label=r"Im $s(t)=\langle Y\rangle$")
ax[0].set_xlabel("evolution time $t$")
ax[0].set_ylabel("transverse signal")
ax[0].set_title("AX free induction decay")
ax[0].legend()
ax[1].plot(freq, spec)
for nu in ax_offsets:
for s in (-1, 1):
ax[1].axvline(nu + s * ax_couplings[(0, 1)] / 2, color="gray", ls="--", lw=1)
ax[1].set_xlim(-12, 12)
ax[1].set_xlabel(r"frequency $\nu$ (Hz)")
ax[1].set_ylabel("intensity")
ax[1].set_title("AX spectrum: two doublets, split by $J$")
plt.tight_layout()
plt.show()
print(
"Expected AX lines (Hz):",
sorted({nu + s * ax_couplings[(0, 1)] / 2 for nu in ax_offsets for s in (-1, 1)}),
)

Output of the previous code cell

Expected AX lines (Hz): [-7.0, -5.0, 5.0, 7.0]

Lanjutan: Sistem AX2_2 dan peraturan n+1n+1​

Sekarang tambah jiran setara kedua. Dalam sistem AX2_2, satu spin A berganding, dengan JJ yang sama, kepada dua spin X setara. (Ingat, X hanyalah label untuk dua spin setara itu; ia tiada kaitan dengan pengendali Pauli XX. Setiap gandingan di bawah masih ZZZZ.) Spin A kemudian melihat empat konfigurasi jiran (↑↑, ↑↓, ↓↑, ↓↓)(\uparrow\uparrow,\ \uparrow\downarrow,\ \downarrow\uparrow,\ \downarrow\downarrow); dua yang bercampur itu bertindih, jadi A dipecahkan menjadi triplet 1:2:1 (n=2⇒n+1=3n=2 \Rightarrow n+1 = 3 garis). Setiap spin X hanya melihat A dan kekal sebagai doublet. Spin setara tidak memecahkan satu sama lain, jadi kita tidak memasukkan gandingan X–X.

Molekul sebenar dengan corak ini ialah 1,1,2-trikloroetana (Cl2_2CH–CH2_2Cl). Apabila menyasarkan spin hidrogen (iaitu bentuk NMR yang paling lazim), proton hidrogen tunggal dalam CH memainkan peranan A, dan dua proton CH2_2 setara ialah dua spin X. Sekarang hanya kira jiran: proton CH mempunyai dua jiran (pasangan CH2_2), jadi isyaratnya dipecahkan menjadi triplet 1:2:1 (n=2n=2); setiap proton CH2_2 hanya mempunyai satu jiran (CH), jadi isyarat CH2_2 ialah doublet 1:1 (n=1n=1). Perhatikan bahawa kumpulan dengan proton yang lebih sedikit (CH) menunjukkan lebih banyak garis; bilangan garis mencerminkan berapa banyak jiran yang dimiliki isyarat, bukan berapa banyak proton yang berkongsinya.

1,1,2-trichloroethane: the CH proton is A, the two equivalent CH_2 protons are X

Di bawah, kita mensimulasikan sistem AX2_2 dengan tiga qubit.

# AX2: spin A (qubit 0) coupled equally to two equivalent X spins (qubits 1, 2)
ax2_offsets = [6.0, -6.0, -6.0] # A at +6 Hz; the two X both at -6 Hz
ax2_couplings = {
(0, 1): 2.0,
(0, 2): 2.0,
} # equal A-X couplings; no coupling between the X spins

ax2_isa = pm_ax2.run(fid_circuit(ax2_offsets, ax2_couplings))
fid_ax2 = run_fid(ax2_isa, n=3, est=estimator)
freq2, spec2 = spectrum(fid_ax2, T2=1.0)

fig, ax = plt.subplots(1, 2, figsize=(12, 4))
ax[0].plot(times, fid_ax2.real, label=r"Re $s(t)=\langle X\rangle$")
ax[0].plot(times, fid_ax2.imag, label=r"Im $s(t)=\langle Y\rangle$")
ax[0].set_xlabel("evolution time $t$")
ax[0].set_ylabel("transverse signal")
ax[0].set_title("AX$_2$ free induction decay")
ax[0].legend()
ax[1].plot(freq2, spec2)
ax[1].set_xlim(-12, 12)
ax[1].set_xlabel(r"frequency $\nu$ (Hz)")
ax[1].set_ylabel("intensity")
ax[1].set_title(r"AX$_2$ spectrum: A is a 1:2:1 triplet, X is a doublet")
plt.tight_layout()
plt.show()
print(
"A triplet at (Hz):",
[ax2_offsets[0] + k * ax2_couplings[(0, 1)] for k in (-1, 0, 1)],
)
print(
"X doublet at (Hz):",
[ax2_offsets[1] + s * ax2_couplings[(0, 1)] / 2 for s in (-1, 1)],
)

Semak kefahaman anda​

Baca setiap soalan, fikirkan jawapan anda, kemudian klik segi tiga untuk mendedahkan penyelesaian.

Dalam spektrum AX, kedua-dua doublet dipisahkan (pusat ke pusat) sebanyak 12 Hz, dan dua garis dalam setiap doublet berjarak 2 Hz. Nombor manakah perbezaan anjakan kimia dan yang manakah pemalar gandingan JJ? Jika anda beralih kepada spektrometer dengan medan magnet dua kali ganda, yang manakah akan berubah?

Jawapan

Pemisahan pusat ke pusat 12 Hz ialah perbezaan anjakan kimia (ν1−ν2\nu_1-\nu_2); jarak garis 2 Hz ialah pemalar gandingan JJ. Anjakan kimia datang daripada perlindungan B0B_0, jadi ia berskala dengan medan. Pada medan dua kali ganda, pemisahan menjadi dua kali ganda kepada 24 Hz. Gandingan JJ ialah sifat molekul melalui ikatan dan tidak bergantung pada medan, jadi ia kekal 2 Hz. Ahli kimia membezakan anjakan daripada gandingan dengan memerhatikan bagaimana pemecahan berskala dengan medan.

Menggunakan peraturan n+1n+1, ramalkan multiplet A jika spin X setara ketiga ditambah (sistem AX3_3), dan jelaskan mengapa dua spin X setara dalam AX2_2 tidak memecahkan satu sama lain.

Jawapan

Dengan n=3n=3 jiran setara, A menjadi kuartet 1:3:3:1. Spin setara tidak memecahkan satu sama lain kerana gandingan mereka menganjak aras tenaga yang berkaitan dengan jumlah yang sama, jadi jurang antara aras itu — frekuensi yang kita lihat — tidak berubah.

Kesimpulan​

Kita telah menggunakan komputer kuantum sebenar untuk meneroka bagaimana spin nuklear berpresesi dan mengalami dekoheren dalam eksperimen NMR, dan bagaimana mentafsir spektrum yang terhasil. Wajar untuk berundur sebentar dan menilai mengapa ini boleh dilakukan sama sekali, dan mengapa ia lebih daripada sekadar keganjilan.

Qubit dan nukleus spin-1/2 secara matematik ialah objek yang sama: sistem kuantum dua aras yang hidup pada sfera Bloch, diputar oleh denyut resonan, berpresesi pada satu paksi, dan kehilangan koheren kepada persekitarannya. Keseluruhan perbendaharaan kata modul ini (frekuensi Larmor, bingkai berputar, T1T_1, T2T_2, dan T2∗T_2^*, pinggir Ramsey, gema Hahn) menjadi milik NMR dan pengkomputeran kuantum sama rata. Apa yang ahli kimia panggil anjakan kimia, jurutera kuantum panggil putaran ZZ satu qubit; apa yang ahli kimia panggil gandingan JJ, jurutera kuantum panggil interaksi ZZZZ. Kedua-dua bidang telah menerangkan fizik yang sama dalam perkataan yang berbeza.

Kaitan itu bersifat sejarah, bukan sekadar konseptual: NMR ialah salah satu platform pertama yang menjalankan algoritma kuantum sebenar. Menjelang 2001, sebuah molekul dalam larutan telah melaksanakan algoritma Shor untuk memfaktorkan 15, dengan setiap spin nuklear berfungsi sebagai qubit. NMR juga menyumbangkan banyak kit alat kawalannya kepada pengkomputeran kuantum. Gema spin, rentetan denyut CPMG, denyut komposit, dan penyahgandingan dinamik semuanya dicipta oleh ahli spektroskopi beberapa dekad sebelum qubit memerlukannya untuk melawan dekoheren. Terdapat simetri yang memuaskan dalam apa yang baru kita lakukan: bidang yang melahirkan komputer kuantum awal kini menjadi sesuatu yang boleh disimulasikan oleh komputer kuantum.

Ulang kaji dan soalan​

Konsep kritikal​

  • Qubit ialah sistem dua aras kejuruteraan yang setara dengan spin-1/2; ∣0⟩/∣1⟩|0\rangle/|1\rangle, frekuensi, get, T1T_1, dan T2T_2 nya ialah analog langsung kuantiti NMR.

  • Denyut resonan memutar vektor Bloch; sudut kilas menentukan putaran, dan lengkung Rabi/nutasi P1=sin⁡2(θ/2)P_1=\sin^2(\theta/2) mengenal pasti putaran π\pi dan π/2\pi/2.

  • T1T_1 ialah relaksasi tenaga (spin-kekisi); T2T_2 ialah relaksasi fasa (spin-spin); T2∗T_2^{*} turut merangkumi kehilangan fasa statik boleh balik yang difokus semula oleh gema Hahn.

  • Molekul ialah set spin berganding: anjakan kimia menentukan kedudukan setiap puncak, dan gandingan JJ memecahkan puncak menjadi multiplet mengikut peraturan n+1n+1, yang bersama-sama mengekod persekitaran kimia dan kesambungan.

Betul / salah​

  1. B/S Frekuensi Larmor ialah jurang tenaga antara dua keadaan spin dibahagi dengan ℏ\hbar.

  2. B/S Denyut 90∘90^\circ (π/2\pi/2) menyongsangkan sepenuhnya spin keseimbangan.

  3. B/S T2∗T_2^{*} umumnya lebih panjang daripada T2T_2.

  4. B/S Gema Hahn memfokus semula kehilangan fasa spin-spin tak boleh balik.

  5. B/S Dalam sistem AX2_2, nukleus A kelihatan sebagai triplet 1:2:1.

  6. B/S Pemalar gandingan JJ menjadi dua kali ganda apabila anda menggandakan medan magnet spektrometer.

  7. B/S Membuang Qiskit Pulse menjadikan mustahil untuk mengukur T1T_1 pada perkakasan semasa.

Jawapan pendek​

  1. Jelaskan dalam dua ayat mengapa satu denyut π\pi ialah cara yang kurang baik untuk mengesan ralat sudut kilas 5%5\%, dan bagaimana merantai denyut membetulkannya.

  2. Sampel menunjukkan garis NMR yang lebar. Dari segi T2T_2, apakah yang diberitahu oleh ini, dan apakah kuantiti qubit yang menjadi analognya?

  3. Berikan analog qubit bagi setiap satu: (a) kelewatan kitar semula, (b) denyut 90∘90^\circ, (c) anjakan kimia.

  4. Menggunakan peraturan n+1n+1, jelaskan mengapa kumpulan etil (CH3_3CH2_2–) menunjukkan triplet 1:2:1 dan kuartet 1:3:3:1, dan kenal pasti kumpulan mana menghasilkan multiplet yang mana.

Masalah cabaran​

  1. Rentetan Carr-Purcell. Ubah suai gema Hahn untuk menyisipkan nn denyut π\pi berjarak sama (rentetan gaya CPMG) dan ukur T2T_2 sebagai fungsi nn. Bincangkan mengapa lebih banyak denyut pemfokus semula boleh memanjangkan T2T_2 ketara.

  2. Penguatan ralat denyut. Bina litar yang mengenakan RX(π)R_X(\pi) sebanyak  n\,n kali pada ∣0⟩|0\rangle dan plotkan P1P_1 lawan nn untuk sudut yang sengaja ditetapkan salah RX(1.05π)R_X(1.05\pi). Tunjukkan bagaimana ralat menjadi kelihatan apabila nn bertambah. Petunjuk: letakkan penghalang selepas setiap putaran; jika tidak, transpiler mungkin menggabungkan putaran berulang itu menjadi satu get setara.

  3. Kumpulan etil. Menggunakan fid_circuit, bina spektrum proton bagi serpihan etil (CH3_3–CH2_2): lima qubit, dengan tiga proton CH3_3 berkongsi satu anjakan kimia dan dua proton CH2_2 satu lagi, dan setiap pasangan CH3_3–CH2_2 berganding dengan JJ yang sama (tiada gandingan dalam kumpulan setara). Ramalkan coraknya dengan peraturan n+1n+1, kemudian simulasikannya; anda sepatutnya mendapat semula kuartet 1:3:3:1 (CH2_2) dan triplet 1:2:1 (CH3_3).

Lampiran (pilihan): Evolusi Trotter — biarkan dekoheren menentukan lebar garis​

Dalam bahagian Spektroskopi NMR sesebuah molekul, evolusi e−iHte^{-iHt} dikenakan dalam satu lapisan yang kedalamannya tidak bertambah dengan tt, jadi FID tidak mereput dengan sendirinya dan kita mengenakan lebar garis dengan tetingkap apodisasi e−t/T2e^{-t/T_2}. Sel pilihan ini mengambil pendekatan bertentangan. Ia memecahkan evolusi kepada pp langkah Trotter dan meletakkan penghalang selepas setiap langkah (supaya transpiler tidak boleh menggabungkannya semula menjadi satu lapisan). Titik masa kk menggunakan kk langkah, jadi kedalaman litar bertambah dengan masa.

Kerana setiap sebutan dalam HH saling kalis tukar tertib, ini adalah tepat: pada simulator tanpa hingar ia memberikan puncak tajam yang sama. Tetapi pada backend model hingar atau perkakasan sebenar, ralat get yang terkumpul menyebabkan FID mereput dengan sendirinya, dan pereputan itulah yang menentukan lebar garis. Ini ialah idea T2↔T_2\leftrightarrowlebar garis dalam bahagian eksperimen T2T_2, T2∗T_2^*, kini timbul daripada dekoheren sebenar dan bukannya tetingkap pemprosesan. Kita menjalankan kedua-dua sistem AX (dua doublet) dan sistem AX2_2 (triplet 1:2:1 serta satu doublet) dengan cara ini.

Dua nota praktikal untuk dipertimbangkan. Pertama, kosnya ialah kedalaman: litar AX terdalam menggunakan ∼ ⁣47\sim\!47 get dua qubit dan versi AX2_2 kira-kira dua kali ganda itu, jadi kedua-duanya jauh lebih bising dan lebih mahal daripada versi tepat. Kedua, setiap sistem spin masih dihantar sebagai satu job, dan setiap titik masa menggunakan semula susun atur qubit fizikal yang sama yang dipilih dalam bahagian spektroskopi. Jika USE_BATCH=True, job ini turut menggunakan Batch pilihan seluruh buku nota.

# Trotterized FID: depth grows with time, so real decoherence (not apodization) sets the linewidth.
estimator.options.default_shots = 2000 # deep circuits need more shots in this appendix
n_tr, dt_tr = (
48,
1 / 20,
) # Nyquist = 1/(2 dt) = 10 Hz (covers the AX2 triplet's 8 Hz line)
times_tr = np.arange(n_tr) * dt_tr
APODIZE_TROTTER = False # keep False so the linewidth comes from decoherence

def trotter_fid_circuit(offsets, couplings, p, step):
n = len(offsets)
qc = QuantumCircuit(n)
qc.ry(np.pi / 2, range(n)) # 90-degree pulse
for _ in range(p): # p Trotter steps, each of duration `step`
for i, nu in enumerate(offsets):
qc.rz(2 * np.pi * nu * step, i) # chemical-shift evolution for one step
for (i, j), J in couplings.items():
qc.rzz(np.pi * J * step, i, j) # J-coupling evolution for one step
qc.barrier() # <-- stops the transpiler merging the steps
return qc

def run_trotter(offsets, couplings, n, est, pass_manager):
# Time point k uses k Trotter steps (its own circuit). Submit every time point and both
# quadratures together as ONE Estimator job, using one fixed physical-qubit layout.
ox, oy = transverse_obs(n)
pubs = []
for k in range(n_tr):
isa = pass_manager.run(trotter_fid_circuit(offsets, couplings, k, dt_tr))
pubs.append((isa, ox.apply_layout(isa.layout))) # <X> at time k
pubs.append((isa, oy.apply_layout(isa.layout))) # <Y> at time k
res = est.run(pubs).result()
return np.array(
[res[2 * k].data.evs + 1j * res[2 * k + 1].data.evs for k in range(n_tr)]
)

def trotter_spectrum(fid):
sig = fid * np.exp(-times_tr / 1.0) if APODIZE_TROTTER else fid
spec = np.abs(np.fft.fftshift(np.fft.fft(sig)))
freq = np.fft.fftshift(np.fft.fftfreq(n_tr, dt_tr))
return freq, spec

fid_tr = run_trotter(
ax_offsets, ax_couplings, 2, estimator, pm_ax
) # AX -> two doublets
fid2_tr = run_trotter(
ax2_offsets, ax2_couplings, 3, estimator, pm_ax2
) # AX2 -> triplet + doublet

f_ax, s_ax = trotter_spectrum(fid_tr)
f_ax2, s_ax2 = trotter_spectrum(fid2_tr)

fig, ax = plt.subplots(1, 3, figsize=(15, 4))
ax[0].plot(times_tr, np.abs(fid_tr), "o-", label="AX")
ax[0].plot(times_tr, np.abs(fid2_tr), "s-", label="AX$_2$")
ax[0].set_xlabel("evolution time $t$")
ax[0].set_ylabel("|FID|")
ax[0].set_title("Trotter FID envelope (decays only on a noisy backend)")
ax[0].legend()
ax[1].plot(f_ax, s_ax)
ax[1].set_xlim(-12, 12)
ax[1].set_xlabel(r"frequency $\nu$ (Hz)")
ax[1].set_ylabel("intensity")
ax[1].set_title("AX: two doublets")
ax[2].plot(f_ax2, s_ax2)
ax[2].set_xlim(-12, 12)
ax[2].set_xlabel(r"frequency $\nu$ (Hz)")
ax[2].set_title("AX$_2$: 1:2:1 triplet + doublet")
plt.tight_layout()
plt.show()
print(
f"Deepest AX circuit: {n_tr-1} two-qubit gates; deepest AX2 circuit: {2*(n_tr-1)} two-qubit gates."
)
print(
"Noiseless backend: |FID| stays flat, peaks razor-sharp (set APODIZE_TROTTER=True to tame ripples)."
)
print(
"Noise-model backend / hardware: |FID| decays on its own and the peaks gain a real linewidth."
)
# Close the optional runtime Batch, if one was opened.
if batch is not None:
batch.close()