SpinEcho, CPMG and INEPT
Three classic pulse sequences, written in the library from Pulse, Delay and JCouple. Each expands to plain rotations, so the pulse programme on the NMR Analysis tab shows every delay with its length and every pulse with its phase.
SpinEcho(tau, offset, wires...)
The Hahn echo: 90°x, delay τ, 180°y, delay τ. The phase 2π·offset·τ gained in the first delay is reflected by the 180° pulse and cancelled by the second delay, so the final state does not depend on the offset. Defaults: τ = 5 ms, offset 0, wire 0.
function SpinEcho(float tau=0.005, float offset=0.0, int ... = 0) {
w = arg[2..argmax]
Pulse(90.0, "x", w)
Delay((float)tau, (float)offset, w)
Pulse(180.0, "y", w)
Delay((float)tau, (float)offset, w)
}
Try SpinEcho(0.002, 250, 0) and SpinEcho(0.002, 0, 0): the RZ angles differ, the state vector does not. Only what evolves symmetrically about the 180° pulse survives; a scalar coupling does, a shift does not.
CPMG(n, tau, offset, wires...)
Carr, Purcell, Meiboom and Gill: 90°x, then n times the block delay τ, 180°y, delay τ. Echoes form at 2τ, 4τ and so on. The 180° pulses are about y, perpendicular to the excitation axis, so pulse errors cancel on even echoes. On a spectrometer the echo train measures T2; in the circuit the state after the last block equals the state after the excitation pulse (for an even n) whatever the offset.
CPMG() // 4 echoes, τ = 1 ms, on resonance CPMG(8, 0.0005, 120) // 8 echoes, 0.5 ms, 120 Hz offset CPMG(2, 0.002, 0, 0..2) // two echoes on three spins
n is an integer and must be at least 1; the block runs inside a LOOP, so the circuit shows a loop marker around it.
INEPT(J, source, target)
Insensitive Nuclei Enhanced by Polarisation Transfer. The source spin is excited with 90°x, the pair evolves for 1/(2J) into the antiphase state, and 90°y on the source with 90°x on the target turns antiphase source magnetisation into antiphase target magnetisation. On hardware the gain is γsource/γtarget, about 4 for ¹H to ¹³C.
function INEPT(float J=215.0, int ... = 0..1) {
w = arg[1..argmax]
tj = 1 / (2 * J)
Pulse(90.0, "x", w[0])
JCouple((float)tj, (float)J, w[0], w[1])
Pulse(90.0, "y", w[0])
Pulse(90.0, "x", w[1])
}
Run INEPT() on the chloroform sample and switch the channel on the tab to ¹³C: the carbon shows the transferred signal as an antiphase doublet. Refocused INEPT, which brings the doublet back in phase, is one more JCouple(1/(4J), J, 0, 1) after two 90° pulses; HSQC runs the transfer forward and back with an evolution period in between.
A CNOT from pulses
The library does not need a CNOT routine because CX already exists, but it is worth seeing what the tab draws for one. A CNOT on an NMR computer is 90°y on the target, 1/(2J) of coupling with the shifts refocused, 90°−y on the target, plus z rotations that are absorbed into later pulse phases. Put CX [0,1] on the chloroform sample and open the pulse programme: the two delays of 1.17 ms with the simultaneous 180° pulses between them are the refocused coupling period.