Resonansi magnetik nuklir dengan Qiskit
Untuk modul Qiskit in Classrooms ini, siswa harus punya lingkungan Python yang berfungsi dengan paket-paket berikut terpasang:
qiskitv2.1 atau lebih baruqiskit-ibm-runtimev0.40.1 atau lebih baruqiskit-aerv0.17 atau lebih baruscipydanmatplotlib(untuk fitting dan plotting)pylatexenc(untuk merender diagram circuit)
Untuk menyiapkan dan memasang paket-paket di atas, lihat panduan Install Qiskit. Untuk menjalankan job di komputer kuantum sungguhan, siswa harus membuat akun IBM Quantum® dengan mengikuti langkah-langkah di panduan Set up your IBM Cloud® account.
Modul ini sudah diuji dan memakai sekitar 5 menit waktu QPU. Ini hanya perkiraan, dan penggunaan sebenarnya mungkin berbeda.
Pendahuluan
Ketika seorang kimiawan menjalankan eksperimen NMR, mereka menaruh sampel spin nuklir dalam medan magnet kuat, menerapkan pulsa radio-frequency (RF), lalu mengukur sinyal yang kembali. Teknik ini bertumpu pada beberapa ide dari mekanika kuantum partikel spin-1/2 dalam medan magnet. Spin punya dua level energi yang dipisahkan oleh energi yang sesuai dengan frekuensi Larmor tertentu. Pulsa resonan pada frekuensi itu membuat spin miring ke bidang transversal, di mana ia berpresesi dan menginduksi sinyal yang kemudian meluruh dengan dua waktu karakteristik, dan .
Qubit superkonduktor adalah versi rekayasa dari objek yang sama: sistem kuantum dua level yang bisa dikendalikan. State dan -nya adalah analog dari spin-up dan spin-down, gate yang kita terapkan untuk memutarnya adalah analog dari pulsa RF, dan ia kehilangan koherensi dengan dan -nya sendiri. Ini bukan sekadar perbandingan longgar; beberapa prosesor kuantum eksperimental paling awal pada akhir 1990-an dan awal 2000-an memakai NMR.
Di modul ini kamu akan memakai komputer kuantum sungguhan untuk menjalankan eksperimen karakterisasi yang sama dengan yang dilakukan seorang spektroskopis NMR (atau insinyur kuantum yang mengkalibrasi hardware):
-
Rabi / nutasi — menggerakkan spin dan mengamatinya berputar. Beginilah cara mengkalibrasi rotasi atau .
-
— relaksasi spin-kisi, peluruhan spin tereksitasi kembali ke kesetimbangan.
-
— relaksasi spin-spin (dephasing), diukur dengan eksperimen Ramsey dan difokus ulang dengan Hahn echo.
-
Spektroskopi NMR (pergeseran kimia dan kopling ) — mensimulasikan molekul kecil pada beberapa qubit dan membaca spektrum multipletnya untuk mendapatkan kembali konektivitas melalui aturan .
Untuk setiap konsep, pertama-tama kita berikan teori minimalnya, lalu mengimplementasikan eksperimennya di Qiskit mengikuti alur kerja empat langkah Qiskit patterns.
Teori
Partikel spin-1/2 dalam medan magnet
Inti atom spin-1/2 punya momen magnetik , dengan adalah rasio giromagnetik. Dalam medan statis sepanjang , kedua state spin terpecah dalam energi (efek Zeeman):
Celah energi ini mendefinisikan frekuensi Larmor (resonansi) . Momen magnetik berpresesi mengelilingi pada frekuensi yang sama ini.
Untuk memutar spin, kita menerapkan medan RF berosilasi pada (atau dekat) . Dalam kerangka yang berputar pada frekuensi drive (rotating frame), drive resonan memutar vektor Bloch mengelilingi sumbu di bidang -. Seberapa jauh ia berputar (flip angle) ditentukan oleh kekuatan dan durasi pulsa. Dua pilihan yang paling penting: pulsa memiringkan spin ke bidang transversal, dan pulsa memutarnya penuh ke .
Menerjemahkan antara jargon NMR dan komputasi kuantum
Qubit adalah sistem dua level, secara matematis identik dengan spin-1/2 dalam medan magnet — jadi meskipun kita berjalan di prosesor kuantum dan bukan di inti atom, fisikanya adalah fisika yang sama yang mendasari NMR. Hanya kosakatanya yang berbeda. Tabel ini membantumu berkomunikasi dengan kimiawan fisika maupun spesialis komputasi kuantum.
| NMR / spin-1/2 | Prosesor kuantum (qubit) |
|---|---|
| Spin-up / spin-down | / |
| Celah Zeeman | Energi transisi qubit |
| Frekuensi Larmor | Frekuensi qubit |
| Pulsa RF resonan (flip angle ) | Gate rotasi single-qubit |
| Pulsa / | / |
| Relaksasi spin-kisi | Waktu relaksasi energi qubit |
| Relaksasi spin-spin | Waktu dephasing qubit |
| Nutasi | Osilasi Rabi |
| Free induction decay (FID), Hahn echo | Urutan Ramsey, echo |
Semua yang ada di bawah ini adalah latihan mengukur kolom kanan dan membacanya sebagai kolom kiri.
Siapkan lingkungan Qiskit
Kita mengikuti alur kerja Qiskit patterns sepanjang modul:
-
Petakan masalah ke circuit kuantum.
-
Optimalkan circuit untuk eksekusi (transpile ke backend).
-
Eksekusi memakai primitif IBM Quantum.
-
Post-process dan analisis.
Pertama kita muat layanan runtime dan pilih backend sungguhan yang paling sepi antreannya. Kalau kamu belum menyimpan kredensial, lihat halaman dokumentasi tentang cara menyimpan kredensial login.
# 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
Pakai cell di bawah untuk beralih antara hardware sungguhan dan simulator lokal untuk seluruh notebook. Menjalankan di hardware adalah inti modul ini, tetapi kalau ada masalah konektivitas atau penggunaan, simulator bisa jadi cadangan. Setel USE_HARDWARE = True untuk menjalankan di 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: osilasi Rabi (nutasi)
Teori
Gerakkan spin pada resonansi dan vektor Blochnya berputar stabil dari kutub ke kutub — ia bernutasi. Jika kita menerapkan rotasi dengan flip angle mengelilingi sumbu- pada qubit yang mulai dari , probabilitas menemukannya di adalah:
Inilah kurva Rabi. Maksimum pertamanya adalah pulsa (inversi penuh, pulsa ); pulsa adalah seperempat putaran (pulsa yang memiringkan spin ke bidang transversal). Dalam NMR, kurva ini adalah cara kamu mengkalibrasi pulsa.
Eksperimen Rabi yang sebenarnya menyapu amplitudo atau durasi drive terhadap waktu. Itu membutuhkan kontrol tingkat pulsa, yang dihapus di Qiskit v2.0. Di sini kita justru menyapu sudut rotasi dari gate . Kurvanya dan identifikasi / identik; satu-satunya perbedaan adalah kita memilih sudut secara langsung, bukan mengkalibrasi panjang pulsa. Pada hardware dengan fractional gate, untuk sembarang berjalan secara native.
Tampilan bola Bloch
Animasi di bawah menunjukkan nutasi: drive resonan memutar vektor Bloch secara stabil mengelilingi sumbu-, membawanya dari turun ke arah dan kembali lagi. Inilah gerakan yang diukur oleh kurva Rabi.
Petakan masalah ke circuit
Kita membangun satu circuit berparameter, diikuti pengukuran, dan nanti mengevaluasinya pada banyak sudut sekaligus.
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")
Optimalkan untuk eksekusi
Transpile ke circuit Instruction Set Architecture (ISA) untuk backend yang dipilih.
rabi_isa = pm_q.run(rabi)
Eksekusi
Kita menyapu dari sampai (dua siklus Rabi penuh). Dengan memberikan array nilai parameter sebagai satu Primitive Unified Bloc (PUB), semuanya dijalankan 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()
Post-process dan analisis
Ekstrak pada setiap sudut dan bandingkan dengan .
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()

Uji pemahamanmu
Pada kurva yang kamu ukur, pertama kali mencapai maksimum pada pulsa (). Sekarang misalkan sebuah perangkat salah kalibrasi, sehingga sudut nominal pada sumbu-x sebenarnya menghasilkan rotasi sebesar .
(a) Pada sudut nominal berapa maksimum pertama sekarang muncul? (b) Apakah satu pulsa saja cara yang sensitif untuk mendeteksi error 5% ini?
Jawaban
(a) Maksimum muncul ketika rotasi sebenarnya sama dengan , yaitu pada sudut nominal — puncak sedikit bergeser ke kiri.
(b) Tidak. Pulsa nominal menghasilkan rotasi sebenarnya sebesar , sehingga alih-alih — perubahan yang terlalu kecil untuk terlihat di tengah noise pengukuran. Inilah sebabnya, untuk mengkalibrasi dengan presisi, para ahli spektroskopi NMR memperkuat galatnya dengan menerapkan rotasi berkali-kali (misalnya metode , atau rangkaian pulsa panjang), sehingga galat kecil per pulsa menumpuk menjadi deviasi besar yang bisa diukur. Kita akan kembali ke ide ini di soal tantangan.
Eksperimen: (relaksasi spin-kisi)
Teori
Kalau dibiarkan, spin yang tereksitasi akan melepaskan energi ke sekitarnya ("kisi") dan berelaksasi kembali ke kesetimbangan termal. Populasi keadaan tereksitasi meluruh secara eksponensial dengan waktu relaksasi spin-kisi :
Bagi seorang kimiawan, menentukan jeda daur ulang yang harus ditunggu di antara pemindaian untuk NMR kuantitatif, dan juga menggambarkan gerak berputar molekul serta dinamikanya. Pada qubit, ini adalah waktu relaksasi energi, dan merupakan salah satu dari dua angka utama untuk memodelkan efek dekoherensi di komputer kuantum.
Eksperimennya. Siapkan dengan gate (pulsa ), tunggu jeda variabel , lalu ukur. Fraksi yang masih berada di menggambarkan peluruhannya.
Tampilan bola Bloch
Relaksasi mengembalikan keadaan tereksitasi ke kesetimbangan, sehingga vektor Bloch meluncur dari kembali ke sepanjang sumbu .
Bangun dan transpile pemindaian jeda
Durasi jeda harus berupa nilai konkret (dijadwalkan dalam waktu hardware), jadi kita membuat satu circuit untuk setiap jeda.
# 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
Eksekusi
t1_job = sampler.run([(c,) for c in t1_isa], shots=1000)
t1_res = t1_job.result()
Analisis — fit eksponensial
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")
Measured T1 = 225.3 microseconds
Waktu yang tepat berbeda dari satu eksperimen ke eksperimen lain dan dari satu backend ke backend lain, tapi hasilnya seharusnya sekitar beberapa ratus mikrodetik.
Cek pemahamanmu
Di NMR kuantitatif, kamu diminta menunggu sekitar di antara pemindaian. Dengan hukum peluruhan, berapa fraksi magnetisasi kesetimbangan yang sudah pulih setelah ?
Jawaban
Setelah , sisa deviasi dari kesetimbangan adalah , artinya sekitar 99.3% sudah pulih.
Eksperimen: ,
Teori
mengukur hilangnya energi. mengukur hilangnya koherensi fase di bidang transversal. Kita bisa mengamatinya dengan eksperimen Ramsey: pulsa memutar semua spin ke ekuator, semuanya menunjuk ke arah yang sama. Mereka berpresesi Larmor, tapi masing-masing berpresesi pada frekuensi yang sedikit berbeda, sehingga menyebar di sepanjang ekuator dan sinyal transversal netto meluruh, dengan waktu peluruhan karakteristik .
Catatan untuk pembaca kuantum: Gambaran penyebaran ini menunjukkan satu cara kehilangan koherensi: sebaran fase pasti yang saling merata-ratakan. Perlu diketahui bahwa ini bukan satu-satunya mekanisme. Koherensi juga bisa hilang karena fase menjadi terjerat dengan lingkungan, sehingga fase itu bukan lagi nilai pasti yang dimiliki sistem. Kamu tidak bisa membedakan kedua mekanisme hanya dengan melihat peluruhan sinyal, jadi gambaran penyebaran ini adalah intuisi yang bagus. Hati-hati jangan membacanya sebagai cerita yang lengkap atau harfiah.
Dua efek yang membuat spin kehilangan fase:
- Dekoherensi ireversibel (atau secara efektif ireversibel) yang muncul dari kopling tak terkendali dengan derajat kebebasan lain, dicirikan oleh sejati. Di NMR, ini umumnya berasal dari gerak molekul yang memodulasi kopling antar spin. Di komputasi kuantum, ini sesuai dengan kopling tak diinginkan antara qubit dan lingkungan.
- Offset frekuensi statis atau yang berubah perlahan dan reversibel, seperti inhomogenitas medan, variasi frekuensi antar qubit, dan galat kalibrasi. Digabung dengan sejati, ini menghasilkan waktu peluruhan semu yang lebih pendek yang teramati dalam eksperimen Ramsey.
Lalu bagaimana kita mendapatkan sejati kalau eksperimen Ramsey hanya memberi tahu ? Eksperimen kedua, yang disebut gema Hahn, membatalkan semua noise tipe kedua untuk menemukan sejati. Awalnya sama dengan eksperimen Ramsey, dengan pulsa , lalu spin menyebar seperti sebelumnya. Setelah beberapa waktu , pulsa diterapkan. Pulsa ini membalik akumulasi fase yang disebabkan offset frekuensi statis, sehingga spin terfokus kembali setelah jeda kedua dengan durasi yang sama, .
dan sama-sama angka penting, baik dalam konteks kimia maupun komputasi kuantum. Dalam kimia, menentukan lebar garis untuk eksperimen NMR standar (kamu akan melihat artinya di bagian berikutnya). bisa memberi tahu banyak hal tentang molekul, seperti gerak berputar molekul, dan perubahan bisa menandakan bahwa molekul terikat pada sesuatu yang lebih besar. Dalam komputasi kuantum, kita umumnya ingin dan sepanjang mungkin, supaya ada lebih banyak waktu untuk menjalankan eksperimen sebelum dekoherensi menguasai sistem. Satu keluarga teknik berbasis gema Hahn memperpanjang waktu ini dengan membatalkan noise reversibel, sehingga circuit idealnya hanya dibatasi oleh sejati, bukan . Ini disebut "dynamical decoupling."
Implementasi
Saat kita mengimplementasikan eksperimen Ramsey dan gema Hahn pada qubit, pembacaannya sedikit berbeda dari kasus NMR. Di NMR, kamu bisa langsung mengamati medan berosilasi yang diinduksi oleh spin yang berpresesi pada frekuensi Larmor di bidang transversal. Tapi dengan qubit, kita hanya bisa mengukur proyeksinya sepanjang sumbu , yaitu apakah atau . Karena itu, untuk kedua eksperimen, kita menutup dengan pulsa tambahan lalu pengukuran. Pulsa ini menerjemahkan informasi fase qubit menjadi populasi.
Di bawah ini kita menjalankan tiap eksperimen untuk menentukan dan .
Ramsey (): Dua pulsa dengan waktu jeda
Pulsa pertama memiringkan vektor Bloch ke ekuator, dan pulsa berikutnya menerjemahkan fase vektor Bloch menjadi populasi. Karena fase berubah terhadap waktu saat vektor Bloch berpresesi, kita melihat pola sinusoidal pada populasi sebagai fungsi waktu presesi . Saat qubit kehilangan koherensi fase, amplitudo kurva sinus ini seharusnya meluruh.
Beberapa kehalusan lagi untuk pembaca kuantum: Dalam eksperimen komputasi kuantum, osilasi yang kita lihat sebenarnya bukan pada frekuensi Larmor, yang berada di rentang GHz dan terlalu cepat untuk kita resolusikan. Eksperimen kuantum beroperasi dalam kerangka berputar: kerangka yang berputar bersama qubit pada (hampir) frekuensi Larmor, sehingga presesi cepat tidak terlihat dan vektor Bloch tampak nyaris diam. Untuk melihat fringe, kita sengaja mengatur kerangka berputar sedikit menyimpang dari frekuensi Larmor. Vektor Bloch lalu tampak berpresesi pada detuning kecil itu, dan kita mendapat sinyal berosilasi pada frekuensi detuning. Di bawah, kita tidak menetapkan detuning pada satu nilai; kita memilihnya sehingga sekitar selusin fringe mengisi jendela pengukuran (yang ukurannya disesuaikan dengan waktu koherensi qubit), sehingga osilasi mudah disampel tanpa aliasing. Satu kerumitan lagi: di Qiskit kita tidak punya kontrol tingkat pulsa yang diperlukan untuk mengubah frekuensi pulsa (yang menentukan frekuensi kerangka berputar). Sebagai gantinya, kita menambahkan detuning efektif secara manual, dengan menggunakannya untuk mengatur fase pulsa Ramsey kedua. Agak dibuat-buat, tapi hasilnya sama dan peluruhan yang kita amati tetap yang asli.
Tampilan bola Bloch
Pulsa memiringkan spin ke ekuator; masing-masing lalu berpresesi dengan laju yang sedikit berbeda dan mereka menyebar, sehingga vektor netto (merah) mengecil saat kehilangan fase — peluruhan ini adalah .
# 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)
Gema Hahn (): Tambahkan pulsa pemfokus ulang di tengah
Tampilan bola Bloch
Gema Hahn: spin menyebar seperti sebelumnya, lalu pulsa membalikkannya, sehingga presesi lanjutan mereka memfokuskan ulang mereka kembali bersama (vektor merah tumbuh lagi), memulihkan koherensi yang hilang akibat dephasing statis.
# 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
Analisis: Fit dan bandingkan kedua peluruhan
# 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")

T2* (Ramsey) = 171.2 µs ; T2 (echo) = 326.0 µs
Di sini kita melihat osilasi Ramsey dan sinyal gema Hahn meluruh, seperti yang diharapkan. Skala waktu masing-masing peluruhan ini adalah dan .
Cek pemahamanmu
Biasanya kamu akan mendapati . Jelaskan alasannya dalam satu kalimat, dan sebutkan efek fisik apa yang dihilangkan oleh pulsa pada gema Hahn, serta apa yang tidak bisa dihilangkannya.
Jawaban
mencakup dephasing ireversibel dan sebaran statis reversibel, sehingga meluruh lebih cepat; pulsa pada gema memfokuskan ulang dephasing statis dan reversibel (inhomogenitas medan / offset frekuensi tetap), menyisakan hanya dephasing spin-spin ireversibel, yaitu sejati. Gema tidak bisa membatalkan fluktuasi yang berubah di antara kedua paruh urutan.
Spektroskopi NMR sebuah molekul: Pergeseran kimia dan kopling
Dari satu spin ke sebuah molekul
Eksperimen sejauh ini mengkarakterisasi satu spin yang terisolasi. NMR kimia sungguhan membaca sebuah molekul (banyak spin berkopling sekaligus) dan menggunakan spektrum yang dihasilkan untuk menyimpulkan fitur struktur molekul. Ini bisa memberi tahu kita tentang dua efek:
-
Pergeseran kimia. Setiap inti yang berbeda secara kimia berpresesi pada frekuensi yang sedikit berbeda, karena elektron di sekitarnya menyaring medan yang diterapkan dengan jumlah yang berbeda. Jadi posisi puncak mengidentifikasi lingkungan kimia (misalnya proton CH versus proton aromatik).
-
Kopling skalar . Interaksi melalui ikatan antara dua spin yang memecah setiap puncak menjadi multiplet. Inti dengan tetangga ekuivalen terpecah menjadi garis dengan intensitas binomial, yaitu aturan . Pola pemecahan mengungkap konektivitas (inti mana yang berikatan), dan jaraknya adalah konstanta kopling .
Eksperimennya
Untuk memodelkan ini di komputer kuantum kita, kita perlu mengimplementasikan Hamiltonian spin pada qubit. Dalam limit kopling lemah dan medan tinggi (selisih pergeseran kimia kopling), bagian dan dari kopling saling merata-ratakan, menyisakan hanya . Jadi Hamiltonian-nya adalah (satuan frekuensi sudut, ):
Setiap inti adalah satu qubit: pergeseran kimia adalah rotasi satu-qubit, dan kopling adalah interaksi dua-qubit.
Eksperimen berjalan sebagai berikut. Pulsa memiringkan setiap spin ke bidang transversal, dan spin berpresesi serta berkopling selama waktu . Kita merekam magnetisasi transversal kompleks yang dijumlahkan atas semua spin. Seperti pada eksperimen Ramsey di atas, magnetisasi transversal ini menggambarkan sinusoid yang meluruh sebagai fungsi waktu presesi . Saat kita mengambil transformasi Fourier dari sinyal, kita mendapat spektrum dengan puncak pada pergeseran kimia yang terpecah oleh kopling skalar .
Kita mensimulasikan evolusi molekul dengan memetakan waktu ke sudut rotasi: yang lebih besar berarti rotasi dan yang lebih besar, bukan circuit yang lebih panjang atau lebih dalam. Jadi meskipun keadaan yang disimulasikan memang maju seiring (itulah yang membuat free induction decay (FID) berosilasi), qubit fisik tidak pernah menganggur lebih lama dan tidak ada dekoherensi yang bergantung pada . Karena itu FID hasil simulasi tidak pernah meluruh dengan sendirinya. Untuk FID ideal yang sangat panjang tak hingga, garis spektrum akan sangat tajam tak hingga; jendela sampling terbatas kita justru memberi mereka resolusi terbatas dan bisa menimbulkan kebocoran spektral. Garis NMR sungguhan memiliki lebar terbatas yang ditentukan oleh . Kita menambahkannya kembali dengan mengalikan FID dengan jendela sebelum transformasi Fourier. Ini disebut apodisasi pelebaran garis, yang diterapkan para ahli spektroskopi saat pemrosesan untuk menentukan lebar garis (menukar resolusi dengan rasio sinyal-terhadap-noise). (Sel opsional di Appendix modul ini menunjukkan alternatif Trotterized, di mana peluruhan justru berasal dari dekoherensi nyata yang tumbuh seiring kedalaman circuit.)
Sistem AX
Mari mulai dengan sistem AX, yaitu molekul yang terdiri dari dua spin berkopling yang berbeda secara kimia. Label A dan X menunjukkan dua lingkungan spin yang berbeda secara kimia. Hurufnya sembarang, tapi fakta bahwa keduanya berjauhan dalam alfabet menggambarkan perbedaan kimia mereka.
Petakan dan optimalkan
Kita menulis satu fungsi yang, dengan offset pergeseran kimia dan kopling , mengembalikan circuit persiapan keadaan yang terparameterisasi. Pulsa memiringkan spin ke ekuator, lalu rotasi mensimulasikan evolusi keadaan di bawah suku pergeseran kimia dan kopling . Setiap adalah offset presesi kecil dalam Hz relatif terhadap referensi yang dipilih, atau carrier kerangka berputar. Di sini kita menetapkannya secara manual; pada molekul sungguhan, pelindungan elektron mengubah medan magnet lokal dan menggeser resonansi tiap inti relatif terhadap referensi itu. Ini dimodelkan oleh gate satu-qubit, satu per spin, dan setiap menentukan di mana puncak spin itu berada dalam spektrum. Gate dua-qubit menerapkan kopling , yang memecah setiap puncak menjadi multiplet dan menentukan jarak antar 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")
Eksekusi dan pasca-pemrosesan
Kita mengevaluasi circuit pada grid waktu evolusi, dan Estimator mengembalikan dan di setiap titik. Kita menggabungkannya menjadi FID kompleks , menerapkan jendela 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)}),
)

Expected AX lines (Hz): [-7.0, -5.0, 5.0, 7.0]
Ekstensi: Sistem AX dan aturan
Sekarang tambahkan tetangga ekuivalen kedua. Dalam sistem AX, satu spin A berkopling, dengan yang sama, ke dua spin X ekuivalen. (Ingat, X hanyalah label untuk dua spin ekuivalen itu; tidak ada hubungannya dengan operator Pauli . Setiap kopling di bawah tetap .) Spin A lalu melihat empat konfigurasi tetangga ; dua yang campuran berimpit, jadi A terpecah menjadi triplet 1:2:1 ( garis). Setiap spin X hanya melihat A dan tetap berupa doublet. Spin ekuivalen tidak saling memecah, jadi kita tidak menyertakan kopling X–X.
Molekul nyata dengan pola ini adalah 1,1,2-trikloroetana (ClCH–CHCl). Saat menargetkan spin hidrogen (bentuk NMR yang paling umum), proton hidrogen tunggal di CH berperan sebagai A, dan dua proton CH yang ekuivalen adalah dua spin X. Sekarang tinggal hitung tetangga: proton CH punya dua tetangga (pasangan CH), jadi sinyalnya terpecah menjadi triplet 1:2:1 (); setiap proton CH hanya punya satu tetangga (CH), jadi sinyal CH adalah doublet 1:1 (). Perhatikan bahwa gugus dengan proton lebih sedikit (CH) menampilkan garis lebih banyak; jumlah garis mencerminkan berapa banyak tetangga yang dimiliki suatu sinyal, bukan berapa banyak proton yang berbagi sinyal itu.
Di bawah ini, kita mensimulasikan sistem AX 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)],
)
Cek pemahamanmu
Baca tiap pertanyaan, pikirkan jawabanmu, lalu klik segitiga untuk menampilkan solusinya.
Pada spektrum AX, kedua doublet dipisahkan (pusat ke pusat) sejauh 12 Hz, dan dua garis dalam tiap doublet berjarak 2 Hz. Angka mana yang merupakan selisih pergeseran kimia dan mana yang konstanta kopling ? Kalau kamu pindah ke spektrometer dengan medan magnet dua kali lipat, mana yang akan berubah?
Jawaban
Pemisahan pusat ke pusat 12 Hz adalah selisih pergeseran kimia (); jarak garis 2 Hz adalah konstanta kopling . Pergeseran kimia berasal dari pelindungan , jadi skalanya mengikuti medan. Pada medan dua kali lipat, pemisahan menjadi dua kali lipat, 24 Hz. Kopling adalah properti molekul melalui ikatan dan tidak bergantung pada medan, jadi tetap 2 Hz. Para kimiawan membedakan pergeseran dari kopling dengan melihat bagaimana pemecahan berskala terhadap medan.
Dengan aturan , prediksikan multiplet A kalau spin X ekuivalen ketiga ditambahkan (sistem AX), dan jelaskan mengapa dua spin X ekuivalen di AX tidak saling memecah.
Jawaban
Dengan tetangga ekuivalen, A menjadi kuartet 1:3:3:1. Spin ekuivalen tidak saling memecah karena kopling mereka menggeser tingkat energi yang relevan dengan jumlah yang sama, sehingga selisih antar tingkat itu — frekuensi yang kita lihat — tidak berubah.
Kesimpulan
Kita telah menggunakan komputer kuantum sungguhan untuk menjelajahi bagaimana spin inti berpresesi dan mengalami dekoherensi dalam eksperimen NMR, dan bagaimana menafsirkan spektrum yang dihasilkan. Ada baiknya kita mundur sejenak untuk meninjau mengapa ini bisa dilakukan, dan mengapa ini lebih dari sekadar keingintahuan.
Qubit dan inti spin-1/2 secara matematis adalah objek yang sama: sistem kuantum dua tingkat yang hidup di bola Bloch, diputar oleh pulsa resonan, berpresesi mengitari sebuah sumbu, dan kehilangan koherensi ke lingkungannya. Seluruh kosakata modul ini (frekuensi Larmor, kerangka berputar, , , dan , fringe Ramsey, gema Hahn) sama-sama milik NMR dan komputasi kuantum. Apa yang disebut kimiawan pergeseran kimia, disebut insinyur kuantum rotasi satu-qubit; apa yang disebut kimiawan kopling , disebut insinyur kuantum interaksi . Kedua bidang ini telah menggambarkan fisika yang sama dengan kata-kata berbeda.
Hubungan itu bersifat historis, bukan sekadar konseptual: NMR adalah salah satu platform pertama yang menjalankan algoritma kuantum sungguhan. Pada 2001, sebuah molekul dalam larutan telah mengeksekusi algoritma Shor untuk memfaktorkan 15, dengan setiap spin inti berfungsi sebagai qubit. NMR juga menyumbangkan banyak perangkat kontrol ke komputasi kuantum. Gema spin, rangkaian pulsa CPMG, pulsa komposit, dan dynamical decoupling semuanya ditemukan oleh para ahli spektroskopi puluhan tahun sebelum qubit membutuhkannya untuk melawan dekoherensi. Ada simetri yang memuaskan dalam apa yang baru saja kita lakukan: bidang yang melahirkan komputer kuantum awal kini menjadi sesuatu yang bisa disimulasikan oleh komputer kuantum.
Ulasan dan pertanyaan
Konsep penting
-
Qubit adalah sistem dua tingkat rekayasa yang ekuivalen dengan spin-1/2; , frekuensi, gate, , dan -nya adalah analog langsung dari besaran NMR.
-
Pulsa resonan memutar vektor Bloch; sudut balik menentukan rotasi, dan kurva Rabi/nutasi mengidentifikasi rotasi dan .
-
adalah relaksasi energi (spin-kisi); adalah relaksasi fase (spin-spin); juga mencakup dephasing statis reversibel yang difokuskan ulang oleh gema Hahn.
-
Molekul adalah himpunan spin berkopling: pergeseran kimia menentukan posisi tiap puncak, dan kopling memecah puncak menjadi multiplet mengikuti aturan , yang bersama-sama mengodekan lingkungan kimia dan konektivitas.
Benar / salah
-
B/S Frekuensi Larmor adalah celah energi antara dua keadaan spin dibagi .
-
B/S Pulsa () membalik sepenuhnya spin kesetimbangan.
-
B/S umumnya lebih panjang daripada .
-
B/S Gema Hahn memfokuskan ulang dephasing spin-spin ireversibel.
-
B/S Pada sistem AX, inti A tampak sebagai triplet 1:2:1.
-
B/S Konstanta kopling menjadi dua kali lipat saat kamu menggandakan medan magnet spektrometer.
-
B/S Dihapusnya Qiskit Pulse membuat pengukuran pada hardware saat ini menjadi mustahil.
Jawaban singkat
-
Jelaskan dalam dua kalimat mengapa satu pulsa adalah cara yang buruk untuk mendeteksi galat sudut balik , dan bagaimana merangkai pulsa mengatasinya.
-
Sebuah sampel menunjukkan garis NMR yang lebar. Dalam hal , apa artinya itu, dan besaran qubit apa yang menjadi analognya?
-
Berikan analog qubit untuk masing-masing: (a) jeda daur ulang, (b) pulsa , (c) pergeseran kimia.
-
Dengan aturan , jelaskan mengapa gugus etil (CHCH–) menampilkan triplet 1:2:1 dan kuartet 1:3:3:1, dan identifikasi gugus mana yang menghasilkan multiplet mana.
Soal tantangan
-
Rangkaian Carr-Purcell. Modifikasi gema Hahn untuk menyisipkan pulsa berjarak sama (rangkaian gaya CPMG) dan ukur sebagai fungsi . Diskusikan mengapa lebih banyak pulsa pemfokus ulang bisa memperpanjang semu.
-
Amplifikasi galat pulsa. Bangun circuit yang menerapkan sebanyak kali pada dan plot terhadap untuk sudut yang sengaja diatur salah . Tunjukkan bagaimana galat menjadi terlihat saat bertambah. Petunjuk: letakkan barrier setelah setiap rotasi; kalau tidak, transpiler mungkin menggabungkan rotasi berulang menjadi satu gate ekuivalen.
-
Gugus etil. Dengan
fid_circuit, bangun spektrum proton fragmen etil (CH–CH): lima qubit, dengan tiga proton CH berbagi satu pergeseran kimia dan dua proton CH berbagi yang lain, dan setiap pasangan CH–CH berkopling dengan yang sama (tanpa kopling dalam gugus ekuivalen). Prediksikan polanya dengan aturan , lalu simulasikan; kamu seharusnya mendapatkan kuartet 1:3:3:1 (CH) dan triplet 1:2:1 (CH).
Appendix (opsional): Evolusi Trotterized — biarkan dekoherensi menentukan lebar garis
Di bagian spektroskopi NMR sebuah molekul, evolusi diterapkan dalam satu lapisan yang kedalamannya tidak bertambah seiring , sehingga FID tidak meluruh dengan sendirinya dan kita menetapkan lebar garis dengan jendela apodisasi . Sel opsional ini mengambil pendekatan sebaliknya. Ia memecah evolusi menjadi langkah Trotter dan menaruh barrier setelah tiap langkah (sehingga transpiler tidak bisa menggabungkannya kembali menjadi satu lapisan). Titik waktu memakai langkah, jadi kedalaman circuit bertambah seiring waktu.
Karena setiap suku dalam saling komut, ini eksak: pada simulator tanpa noise, hasilnya sama-sama puncak tajam. Tapi pada backend model noise atau hardware sungguhan, galat gate yang terakumulasi membuat FID meluruh dengan sendirinya, dan peluruhan itulah yang menentukan lebar garis. Ini adalah ide lebar garis dari bagian eksperimen , , yang kini muncul dari dekoherensi nyata alih-alih jendela pemrosesan. Kita menjalankan sistem AX (dua doublet) dan sistem AX (triplet 1:2:1 plus doublet) dengan cara ini.
Dua catatan praktis untuk dipertimbangkan. Pertama, biayanya adalah kedalaman: circuit AX terdalam memakai gate dua-qubit dan versi AX sekitar dua kali lipatnya, jadi keduanya jauh lebih bernoise dan lebih mahal daripada versi eksak. Kedua, setiap sistem spin tetap dikirim sebagai satu job, dan setiap titik waktu memakai ulang layout qubit fisik yang sama yang dipilih di bagian spektroskopi. Jika USE_BATCH=True, job-job ini juga memakai Batch opsional untuk seluruh notebook.
# 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()