OPX simulator¶
The simulator is capable of prediciting the actual output timing of the OPX for a given QUA program.
The simulator supports input to measurement commands via the loopback interface.
The simulator returns two type of objects:
simulated analog wavefoms and simulated digital waveforms, which is a dictionary that contains the names, timing values, frequencies and phases of all waveforms that were played during a program. These can be retreived based on DAC ports or quantum elements.
Note
The samples of the waveforms are the raw envelope values, before modulation by the carrier, scaling with the
amp()
function, frame rotation and mixer correction. To obtain the actual values that are output to the DAC, seeget_simulated_samples()
method ofQmJob
.The actual analog samples that were played to the DAC, using the
get_simulated_samples()
method ofQmJob
.
Usage¶
By calling the simulate()
function of a QuantumMachine
(see Quantum Machine API).
This function should receive a SimulationConfig
object, whose API is specified in the following section.
An example for the a call to simulate
can be found in its API documentation.
LoopbackInterface¶
It is possible to simulate a connection from an output of an OPX to one of the two inputs. This is done by using the LoopbackInterface
which is passed to the simulate
method of the QM object. For example, the following code generates a virtual connection from output 1 to input 2. A list of two such tuples can be passed to the LoopbackInterface (as there are two inputs to the OPX).
QM.simulate(prog,SimulationConfig(duration, LoopbackInterface([("con1",1,"con1",2)]))
LoopbackInterface
can also simulate signal propagation delay and noise using the noisePower
and latency
keywords.
noisePower
adds gaussian noise with zero mean and a variance (in units [V^2]) set by this parameter.
latency
adds a signal propagation delay in [ns] set by this parameter
The following adds noise with variance 1 V^2 and 100 ns latency. All (up to 2) tuples in the loopback interface will have the same noise figure and same latency.
QM.simulate(prog,SimulationConfig(duration, LoopbackInterface([("con1",1,"con1",2)],noisePower=1,latency=100))
Raw ADC interface¶
It is possible to explicitly specify the signal passed into the OPX in the simulation. This is quite similar to the LoopbackInterface described above and supports the same options.
For example, the code snippet below playes a 1 microsecond signal to input 1 of the device called “con1”.
signal=np.linspace(0,0.2,1000).tolist()
QM.simulate(prog,SimulationConfig(duration, RawInterface([("con1",1,signal)],noisePower=1,latency=100))
API¶
-
class
SimulationConfig
(duration=0, include_analog_waveforms=False, include_digital_waveforms=False, simulation_interface=None, controller_connections=[])¶ create a configuration object to pass to
QuantumMachine.simulate
- Parameters
duration (int) – The duration to run the simulation for, in clock cycles
include_analog_waveforms (bool) – Should we collect simulated analog waveform names
include_digital_waveforms (bool) – Should we collect simulated digital waveform names
simulation_interface (SimulatorInterface) –
interface to simulator. Currently supported interfaces:
None
- zero inputsLoopbackInterface
- Loopback output to input (see API)controller_connections (List[ControllerConnection]) – A list of connections between the controllers in the config
-
class
LoopbackInterface
(connections, latency=24, noisePower=0.0)¶ create a loopback interface for simulation
- Parameters
connections (list) –
list of tuples with loopback connections. Each tuple can be:
Physical connection between ports:
(fromController: str, fromPort: int, toController: str, toPort: int)
Virtual connection between quantum elements:
(fromQE: str, toQE: str, toQEInput: int)
example:
>>> job = qm.simulate(prog2, SimulationConfig( >>> duration=20000, >>> # loopback from output 1 to input 1: >>> simulation_interface=LoopbackInterface([("con1", 1, "con1", 1)])
Examples¶
from qm.QuantumMachinesManager import QuantumMachinesManager
from qm import SimulationConfig
from qm import LoopbackInterface
from qm.qua import *
from examples._config import config
import matplotlib.pyplot as plt
qmm = QuantumMachinesManager(host='127.0.0.1')
qm = qmm.open_qm(config)
##
# ## Example 1 - No inputs
with program() as prog1:
a = declare(fixed)
b = declare(fixed, value=0.2)
c = declare(fixed, value=0.4)
play("measurement", "qe1")
play("marker", "qeDig")
with for_(a, 0.2, a < 0.9, a + 0.1):
play("measurement" * amp(a), "qe1")
assign(c, c + b*1.5)
save(c, "c")
# simulate program
job = qm.simulate(prog1, SimulationConfig(
duration=1000, # duration of simulation in units of 4ns
include_analog_waveforms=True, # include analog waveform names
include_digital_waveforms=True # include digital waveform names
))
# get DAC and digital samples
samples = job.get_simulated_samples()
# plot all ports:
samples.con1.plot()
# another way, plot analog output 1 and digital output 9:
# plt.figure()
# plt.plot(samples.con1.analog["1"])
# plt.plot(samples.con1.digital["9"])
# plt.legend(("analog 1", "digital 9"))
# plt.xlabel("Time [ns]")
# plt.ylabel("Signal [V]")
# print waveform names and times
print(job.simulated_analog_waveforms())
print(job.simulated_digital_waveforms())
# get results
res = job.get_results()
c = res.variable_results.c.values
print(c)
##
# ## Example 2 - Loopback inputs
with program() as prog2:
I = declare(fixed)
Q = declare(fixed)
f = declare(int)
a = declare(fixed)
with for_(a, 0.1, a < 0.4, a + 0.1):
with for_(f, 50e6, f < 92e6, f + 1e6):
update_frequency("qe1", f)
measure("measurement"*amp(a), "qe1", "adc", demod.full('integW1', I), demod.full('integW2', Q))
save(I, "I")
save(Q, "Q")
# simulate program
job = qm.simulate(prog2, SimulationConfig(
duration=40000,
simulation_interface=LoopbackInterface([("con1", 1, "con1", 1)]) # loopback from output 1 to input 1
))
# get results
res = job.get_results()
adc = res.raw_results.input1.values
ts = res.raw_results.input1.ts_nsec
I = res.variable_results.I.values
Q = res.variable_results.Q.values
plt.figure()
plt.plot(ts, adc)
plt.xlabel("Time [ns]")
plt.ylabel("ADC")
plt.figure()
plt.plot(I, Q, '.')
plt.xlabel("I")
plt.xlabel("Q")
##
# ## Example 3:
with program() as prog3:
d = declare(int)
with for_(d, 10, d <= 100, d + 10):
play("measurement", "qe1")
play("measurement", "qe2", duration=d)
wait(50, "qe1")
# simulate program
job = qm.simulate(prog3, SimulationConfig(
duration=1700, # duration of simulation in units of 4ns
))
# get DAC and digital samples
samples = job.get_simulated_samples()
# plot analog ports 1 and 3:
samples.con1.plot(analog_ports={'1', '3'}, digital_ports={})
# another way:
# plt.figure()
# plt.plot(samples.con1.analog["1"], "-")
# plt.plot(samples.con1.analog["3"], "--")
# plt.legend(("analog 1", "analog 3"))
# plt.xlabel("Time [ns]")
# plt.ylabel("Signal [V]")