# Qiskit: set_frequency workaround in PulseSimulator

I am trying to run exercise 4 from the recent IBM Quantum Challenge using a PulseSimulator since the device used in the challenge is not available for public use. A snippet of what I am trying to run is the following:

from qiskit import pulse, IBMQ, assemble
from qiskit.pulse import Play, Schedule, DriveChannel, Gaussian, AcquireChannel
from qiskit.providers.aer import PulseSimulator
from qiskit.tools.monitor import job_monitor
import numpy as np

# Constants and units

job_params = {
'meas_level': 1,
'meas_return': 'avg',
'shots': 512
}

spec_range = 0.300 # GHz
num_spec01_freqs = 71
GHz = 1.0e9 # Gigahertz

# Helper functions

def get_exc_chans(gv):
return [AcquireChannel(i) for i in range(gv['backend_config'].n_qubits)]

def get_spec01_freqs(center_freqs, qubit):
center_freq = round(center_freqs[qubit], -8) # 2 significant digits
return np.linspace(center_freq/GHz - spec_range/2,
center_freq/GHz + spec_range/2, num_spec01_freqs)

# Set up backend and config

backend_name = 'ibmq_armonk'
backend_real = provider.get_backend(backend_name)
backend = PulseSimulator.from_backend(backend_real)

qubit = 0

backend_config = backend.configuration()
exc_chans = get_exc_chans(globals())
dt = backend_config.dt

backend_defaults = backend.defaults()
center_frequency = backend_defaults.qubit_freq_est
inst_sched_map = backend_defaults.instruction_schedule_map

# |0⟩ -> |1⟩  pulse

# Retrieve calibrated measurement pulse from backend
meas = inst_sched_map.get('measure', qubits=[qubit])

# The same spec pulse for both 01 and 12 spec
drive_amp = 0.25
drive_duration = inst_sched_map.get('x', qubits=[qubit]).duration

# Calibrated backend pulse use advanced DRAG pulse to reduce leakage to the |2> state.
# Here we will use simple Gaussian pulse
drive_sigma = drive_duration // 4 # DRAG pulses typically 4*sigma long.
spec_pulse = Gaussian(duration=drive_duration, amp=drive_amp,
sigma=drive_sigma, name=f"Spec drive amplitude = {drive_amp}")

# Construct an np array of the frequencies for our experiment
spec_freqs_GHz = get_spec01_freqs(center_frequency, qubit)

# Create the base schedule
spec01_scheds = []
for freq in spec_freqs_GHz:
with pulse.build(name="Spec Pulse at %.3f GHz" % freq) as spec01_sched:
with pulse.align_sequential():
# Pay close attention to this part to solve the problem at the end
pulse.set_frequency(freq*GHz, DriveChannel(qubit))
pulse.play(spec_pulse, DriveChannel(qubit))
pulse.call(meas)

spec01_scheds.append(spec01_sched)

qobj = assemble(spec01_scheds, backend=backend, **job_params)
spec01_job = backend.run(qobj)
job_monitor(spec01_job)


However, everytime I run this I get the following (not very helpful) error message:

Job Status: job incurred error


I opened an issue about this in the Qiskit Aer GitHub repository (issue #1264) and got a response. They told me that "the set/shift frequency instructions are not supported by the pulse simulator". And they suggested the following workaround:

A way to bypass this issue as a user is to manually add an oscillation to the pulse envelopes. E.g. if the channel's LO frequency is $$w$$, but you want to set it to $$v$$ for a given pulse (or pulses), convert the pulse to an explicit WaveForm specified in terms of a sample list, then multiply the sample array $$exp(i(v-w)t)$$, where $$t$$ is the array of associated times. I may be missing some book keeping here but some version of this should work.

As simple as this sounds, I don't quite understand how to do this. Can anyone explain to me, with code, how to do this? Or point me to somewhere where this is done?

So, if you just want to create Pulse to go from ground state $$|0\rangle$$ to first excited state $$|1\rangle$$ for can do it with simulator by using a fake Armonk and following the tutorial : https://qiskit.org/textbook/ch-quantum-hardware/calibrating-qubits-pulse.html and https://qiskit.org/textbook/ch-quantum-hardware/accessing_higher_energy_states.html

but if you want to get the 2nd energy state $$|2\rangle$$ with a simulator you need to construct your own oscillator by using the dim_oscillator, the oscillator allow you to create noise in your system. The lib doc : https://qiskit.org/documentation/stubs/qiskit.providers.aer.pulse.duffing_system_model.html and here the textbook entry : https://qiskit.org/textbook/ch-quantum-hardware/hamiltonian-tomography.html

The think to know is the $$|2\rangle$$ is a singular property of transmon qubit and so can't be simulate with perfect qubit in other way than having noise or a physical like system.

Here some other tutorial explaining how to do get energies states from custom model https://qiskit.org/documentation/tutorials/circuits_advanced/10_pulse_simulator_backend_model.html?highlight=oscillator and https://qiskit.org/documentation/tutorials/circuits_advanced/09_pulse_simulator_duffing_model.html

I'm absolutly not an expert at all so maybe this way isn't the best way to get to do it.

As simple as this sounds, I don't quite understand how to do this.

Oh and yes I didn't find it easy at all neither