Shaped Pulse OptimizationΒΆ

For single pulse optimization, we can use rf_optimizer. Turn to multi_rf_optimizer for cooperative pulses optimization.


The procedure can be divided into three stages: spin system set up, pulse optimizer initialization and optimization.

local sys = spin_system(config)    -- 1. spin system set up.
local oc = rf_optimizer(sys)       -- 2. pulse optimizer initialization.
local opt_pulse = oc:optimize{}    -- 3. pulse optimization.

The parameter structure for optimize is summarized as follow:

Parameter Mandatory/Optional Content
width M Pulse duration in ms.
step M Discrete pulse steps.
init_pattern O Inital waveform pattern, described by a string, default is "rand_spline". see pattern in the parameter structure of shapedRF for details.
max_init_amp O Maximum amplitude in Hz, useful for scaling inital pulse shape.
init_state O Inital state of spin system, described by a string, e.g. "I1z+I2z".
targ_state O Target state of spin system, described by a string, e.g. "I1x+I2y".
targ_op O Target unitary propagator of spin system, described by a string, e.g. "I1xI2x+I1yI2y+I1zI2z" will define an isotropic mixing propagator exp{-i*pi*(I1xI2x+I1yI2y+I1zI2z)}.
limit_channel O Specify the desired channel considered for the optimization. E.g. limit_channel ="1H".
limit_axis O Specify the desired component of the involved channels. E.g. limit_axis = "x", valid parameters are "x" or "y".
algorithm O Specify the optimization algorithm, default is "LBFGS".
max_eval O Specify the maximum iteration steps for the optimization.
xtol_rel O Specify a fractional tolerance on the pulse shape parameters.

Note

  • init_state and targ_state are required for state transfer.
  • targ_op is required for unitary transformation.

The optimized pulse is essentially a shapedRF, thus all related operations in shapedRF are available for the optimal pulse.

We also provides a projection function inside rf_optimizer to observe the evolution trajectory components of the interested state.

oc:projection{}

The parameter structure for projection is summarized as follow:

Parameter Mandatory/Optional Content
rf M The optimized pulse object.
init_state M Inital state of spin system, described by a string, e.g. "I1z+I2z".
observ_states M List of observed states, described by a Lua table, e.g. {"I1z", "I1x", "I1y"}. Note if you wish to observe all basis states of the spin system, just assign an empty table {}.

  • State transfer

    The follow example script for an off-resonance 90 degree pulse optimization is self-explanatory.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    --[[ Copyright 2019 The Spin-Scenario Authors. All Rights Reserved.
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
        http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
    ==============================================================================-]]
    
    -- example: single pulse optimization for single proton.
    output_terminal{type = "eps", font = "Arial,18"} -- available font includes qt, png, eps and tex.
    
    B0{"500 MHz"}
    -- set up spin system.
    local config = {
        spin = "1H",
        zeeman = "1 scalar 5 kHz"
    }
    local sys = spin_system(config)
    
    local oc = rf_optimizer(sys)
    local rf90 = oc:optimize{width = 5.12, step = 512, init_pattern = "rand", init_state = "I1z", targ_state = "I1x"}
    
    rf90:set_name("off resonance optimized pulse")
    plot(rf90)
    
    oc:projection{init_state = "I1z", rf = rf90, observ_states = {"I1z", "I1x", "I1y"} }
    
    rf90:switch("ux/uy")
    specgram(rf90, { wlen = 128, overlap = 0.95, nfft = 10240, style = "amp", f0=0, f1=15})
    

    1spin_opt_pulse 1spin_opt_pulse_traj1

  • Unitary transformation

    The follow example script demonstrates optimizing isotropic mixing pulse (tp=1.5/J) for heteronuclear spin system.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    --[[ Copyright 2019 The Spin-Scenario Authors. All Rights Reserved.
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
        http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
    ==============================================================================-]]
    output_terminal{type = "qt", font = "Arial,12"} -- available font includes qt, png, eps and tex.
    
    -- example: pulse optimization for two heteronuclear spin system.
    B0{"500 MHz"}
    -- set up spin system.
    local config = {
        spin = "1H 13C",
        jcoupling = "1 2 scalar 140 Hz"
    }
    local sys = spin_system(config)
    
    local oc = rf_optimizer(sys)
    local opt_pulse = oc:optimize {
        width = 7.14*1.5,
        step = 357,
        init_pattern = "rand",
        targ_op = "1*(I1xI2x+I1yI2y+I1zI2z)",
        tol_f = 1e-12,
        max_init_amp = 0.55,
        max_eval = 200
    }
    
    opt_pulse:switch('ux/uy')
    plot(opt_pulse)
    
    oc:projection{ init_state = "I1x", rf = opt_pulse, observ_states = {}} 
    oc:projection{ init_state = "I1y", rf = opt_pulse, observ_states = {}} 
    oc:projection{ init_state = "I1x+I1y", rf = opt_pulse, observ_states = {}} 
    

    2spin_mix_pulse_1H 2spin_mix_pulse_13C 2spin_mix_pulse_traj