Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions c3/c3objs.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ def __init__(self, name, desc="", comment="", params=None):
if isinstance(par, Quantity):
self.params[pname] = par
else:
self.params[pname] = Quantity(**par)
try:
self.params[pname] = Quantity(**par)
except Exception as exception:
print(f"Error initializing {pname} with\n {par}")
raise exception

def __str__(self) -> str:
return hjson.dumps(self.asdict())
Expand Down Expand Up @@ -69,7 +73,7 @@ class Quantity:
"""

def __init__(
self, value, min_val=None, max_val=None, unit="undefined", symbol=r"\alpha"
self, value, unit="undefined", min_val=None, max_val=None, symbol=r"\alpha"
):
if "pi" in unit:
pref = np.pi
Expand Down
20 changes: 20 additions & 0 deletions c3/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,26 @@ def quick_setup(self, filepath: str) -> None:

self.pmap = ParameterMap(instructions, generator=gen, model=model)

def read_config(self, filepath: str) -> None:
"""
Load a file and parse it to create a Model object.

Parameters
----------
filepath : str
Location of the configuration file

"""
with open(filepath, "r") as cfg_file:
cfg = hjson.loads(cfg_file.read())
model = Model()
model.fromdict(cfg["model"])
generator = Generator()
generator.fromdict(cfg["generator"])
pmap = ParameterMap(model=model, generator=generator)
pmap.fromdict(cfg["instructions"])
self.pmap = pmap

def write_config(self, filepath: str) -> None:
"""
Write dictionary to a HJSON file.
Expand Down
6 changes: 5 additions & 1 deletion c3/generator/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ def __init__(self, **props):
name = props.pop("name")
desc = props.pop("desc", "")
comment = props.pop("comment", "")
params = props

# Because of legacy usage, we might have parameters given withing props iself
# or in a "params" field. Here we combine them.
params = props.pop("params", {})
params.update(props)
super().__init__(name, desc, comment, params)
self.signal = {}

Expand Down
3 changes: 3 additions & 0 deletions c3/generator/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ def read_config(self, filepath: str) -> None:
"""
with open(filepath, "r") as cfg_file:
cfg = hjson.loads(cfg_file.read())
self.fromdict(cfg)

def fromdict(self, cfg: dict) -> None:
for name, props in cfg["Devices"].items():
props["name"] = name
dev_type = props.pop("c3type")
Expand Down
139 changes: 92 additions & 47 deletions c3/libraries/envelopes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def env_reg_deco(func):


@env_reg_deco
def no_drive(t, params):
def no_drive(t, params=None):
"""Do nothing."""
return tf.zeros_like(t, dtype=tf.float64)

Expand All @@ -37,10 +37,10 @@ def pwc(t, params):
def pwc_symmetric(t, params):
"""symmetic PWC pulse
This works only for inphase component"""
t_bin_start = tf.cast(params["t_bin_end"].get_value(), dtype=tf.float64)
t_bin_end = tf.cast(params["t_bin_start"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
inphase = tf.cast(params["inphase"].get_value(), dtype=tf.float64)
t_bin_start = tf.cast(params["t_bin_end"].get_value(), tf.float64)
t_bin_end = tf.cast(params["t_bin_start"].get_value(), tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
inphase = tf.cast(params["inphase"].get_value(), tf.float64)

t_interp = tf.where(tf.greater(t, t_final / 2), -t + t_final, t)
shape = tf.reshape(
Expand Down Expand Up @@ -72,18 +72,16 @@ def fourier_sin(t, params):

"""
amps = tf.reshape(
tf.cast(params["amps"].get_value(), dtype=tf.float64),
[params["amps"].shape[0], 1],
tf.cast(params["amps"].get_value(), tf.float64), [params["amps"].shape[0], 1]
)
freqs = tf.reshape(
tf.cast(params["freqs"].get_value(), dtype=tf.float64),
[params["freqs"].shape[0], 1],
tf.cast(params["freqs"].get_value(), tf.float64), [params["freqs"].shape[0], 1]
)
phases = tf.reshape(
tf.cast(params["phases"].get_value(), dtype=tf.float64),
tf.cast(params["phases"].get_value(), tf.float64),
[params["phases"].shape[0], 1],
)
t = tf.reshape(tf.cast(t, dtype=tf.float64), [1, t.shape[0]])
t = tf.reshape(tf.cast(t, tf.float64), [1, t.shape[0]])
return tf.reduce_sum(amps * tf.sin(freqs * t + phases), 0)


Expand All @@ -101,21 +99,19 @@ def fourier_cos(t, params):

"""
amps = tf.reshape(
tf.cast(params["amps"].get_value(), dtype=tf.float64),
[params["amps"].shape[0], 1],
tf.cast(params["amps"].get_value(), tf.float64), [params["amps"].shape[0], 1]
)
freqs = tf.reshape(
tf.cast(params["freqs"].get_value(), dtype=tf.float64),
[params["freqs"].shape[0], 1],
tf.cast(params["freqs"].get_value(), tf.float64), [params["freqs"].shape[0], 1]
)
t = tf.reshape(tf.cast(t, dtype=tf.float64), [1, t.shape[0]])
t = tf.reshape(tf.cast(t, tf.float64), [1, t.shape[0]])
return tf.reduce_sum(amps * tf.cos(freqs * t), 0)


@env_reg_deco
def rect(t, params):
"""Rectangular pulse. Returns 1 at every time step."""
return tf.ones_like(t, dtype=tf.float64)
return tf.ones_like(t, tf.float64)


@env_reg_deco
Expand All @@ -130,10 +126,10 @@ def trapezoid(t, params):
risefall : float
Length of the slope
"""
risefall = tf.cast(params["risefall"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
risefall = tf.cast(params["risefall"].get_value(), tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)

envelope = tf.ones_like(t, dtype=tf.float64)
envelope = tf.ones_like(t, tf.float64)
envelope = tf.where(
tf.less_equal(t, risefall * 2.5), t / (risefall * 2.5), envelope
)
Expand All @@ -159,8 +155,8 @@ def flattop_risefall(t, params):
with the start of the ramp-up and ends at the end of the ramp-down

"""
risefall = tf.cast(params["risefall"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
risefall = tf.cast(params["risefall"].get_value(), tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
t_up = risefall
t_down = t_final - risefall
return (
Expand All @@ -186,9 +182,9 @@ def flattop(t, params):
Length of the ramps.

"""
t_up = tf.cast(params["t_up"].get_value(), dtype=tf.float64)
t_down = tf.cast(params["t_down"].get_value(), dtype=tf.float64)
risefall = tf.cast(params["risefall"].get_value(), dtype=tf.float64)
t_up = tf.cast(params["t_up"].get_value(), tf.float64)
t_down = tf.cast(params["t_down"].get_value(), tf.float64)
risefall = tf.cast(params["risefall"].get_value(), tf.float64)
return (
(1 + tf.math.erf((t - t_up) / (risefall)))
/ 2
Expand All @@ -212,9 +208,9 @@ def flattop_cut(t, params):
Length of the ramps.

"""
t_up = tf.cast(params["t_up"].get_value(), dtype=tf.float64)
t_down = tf.cast(params["t_down"].get_value(), dtype=tf.float64)
risefall = tf.cast(params["risefall"].get_value(), dtype=tf.float64)
t_up = tf.cast(params["t_up"].get_value(), tf.float64)
t_down = tf.cast(params["t_down"].get_value(), tf.float64)
risefall = tf.cast(params["risefall"].get_value(), tf.float64)
shape = tf.math.erf((t - t_up) / (risefall)) * tf.math.erf(
(-t + t_down) / (risefall)
)
Expand All @@ -236,9 +232,9 @@ def flattop_cut_center(t, params):
Length of the ramps.

"""
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
width = tf.cast(params["width"].get_value(), dtype=tf.float64)
risefall = tf.cast(params["risefall"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
width = tf.cast(params["width"].get_value(), tf.float64)
risefall = tf.cast(params["risefall"].get_value(), tf.float64)
t_up = t_final / 2 - width / 2
t_down = t_final / 2 + width / 2
shape = tf.math.erf((t - t_up) / risefall) * tf.math.erf((-t + t_down) / risefall)
Expand All @@ -251,11 +247,11 @@ def slepian_fourier(t, params):
"""
----
"""
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
width = tf.cast(params["width"].get_value(), dtype=tf.float64)
fourier_coeffs = tf.cast(params["fourier_coeffs"].get_value(), dtype=tf.float64)
offset = tf.cast(params["offset"].get_value(), dtype=tf.float64)
amp = tf.cast(params["amp"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
width = tf.cast(params["width"].get_value(), tf.float64)
fourier_coeffs = tf.cast(params["fourier_coeffs"].get_value(), tf.float64)
offset = tf.cast(params["offset"].get_value(), tf.float64)
amp = tf.cast(params["amp"].get_value(), tf.float64)
shape = tf.zeros_like(t)
for n, coeff in enumerate(fourier_coeffs):
shape += coeff * (
Expand Down Expand Up @@ -290,8 +286,8 @@ def gaussian_sigma(t, params):
Width of the Gaussian.

"""
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
sigma = tf.cast(params["sigma"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
sigma = tf.cast(params["sigma"].get_value(), tf.float64)
gauss = tf.exp(-((t - t_final / 2) ** 2) / (2 * sigma ** 2))
norm = tf.sqrt(2 * np.pi * sigma ** 2) * tf.math.erf(
t_final / (np.sqrt(8) * sigma)
Expand Down Expand Up @@ -321,6 +317,55 @@ def gaussian(t, params):
return gaussian_sigma(t, params)


@env_reg_deco
def cosine(t, params):
"""
Cosine-shaped envelope. Maximum value is 1, area is given by length.

Parameters
----------
params : dict
t_final : float
Total length of the Gaussian.
sigma: float
Width of the Gaussian.

"""
# TODO Add zeroes for t>t_final
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
cos = 0.5 * (1 - tf.cos(2 * np.pi * t / t_final))
return cos


@env_reg_deco
def cosine_flattop(t, params):
"""
Cosine-shaped envelope. Maximum value is 1, area is given by length.

Parameters
----------
params : dict
t_final : float
Total length of the Gaussian.
sigma: float
Width of the Gaussian.

"""
t_rise = tf.cast(params["t_rise"].get_value(), tf.float64)
dt = t[1] - t[0]
n_rise = tf.cast(t_rise / dt, tf.int32)
n_flat = len(t) - 2 * n_rise
cos_flt = tf.concat(
[
0.5 * (1 - tf.cos(np.pi * t[:n_rise] / t_rise)),
tf.ones(n_flat, dtype=tf.float64),
0.5 * (1 + tf.cos(np.pi * t[:n_rise] / t_rise)),
],
axis=0,
)
return cos_flt


@env_reg_deco
def gaussian_nonorm(t, params):
"""
Expand All @@ -336,7 +381,7 @@ def gaussian_nonorm(t, params):

"""
# TODO Add zeroes for t>t_final
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
sigma = params["sigma"].get_value()
gauss = tf.exp(-((t - t_final / 2) ** 2) / (2 * sigma ** 2))
return gauss
Expand All @@ -345,8 +390,8 @@ def gaussian_nonorm(t, params):
@env_reg_deco
def gaussian_der_nonorm(t, params):
"""Derivative of the normalized gaussian (ifself not normalized)."""
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
sigma = tf.cast(params["sigma"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
sigma = tf.cast(params["sigma"].get_value(), tf.float64)
gauss_der = (
tf.exp(-((t - t_final / 2) ** 2) / (2 * sigma ** 2))
* (t - t_final / 2)
Expand All @@ -358,8 +403,8 @@ def gaussian_der_nonorm(t, params):
@env_reg_deco
def gaussian_der(t, params):
"""Derivative of the normalized gaussian (ifself not normalized)."""
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
sigma = tf.cast(params["sigma"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
sigma = tf.cast(params["sigma"].get_value(), tf.float64)
gauss_der = (
tf.exp(-((t - t_final / 2) ** 2) / (2 * sigma ** 2))
* (t - t_final / 2)
Expand All @@ -374,8 +419,8 @@ def gaussian_der(t, params):
@env_reg_deco
def drag_sigma(t, params):
"""Second order gaussian."""
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
sigma = tf.cast(params["sigma"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
sigma = tf.cast(params["sigma"].get_value(), tf.float64)
drag = tf.exp(-((t - t_final / 2) ** 2) / (2 * sigma ** 2))
norm = tf.sqrt(2 * np.pi * sigma ** 2) * tf.math.erf(
t_final / (np.sqrt(8) * sigma)
Expand All @@ -400,8 +445,8 @@ def drag(t, params):
@env_reg_deco
def drag_der(t, params):
"""Derivative of second order gaussian."""
t_final = tf.cast(params["t_final"].get_value(), dtype=tf.float64)
sigma = tf.cast(params["sigma"].get_value(), dtype=tf.float64)
t_final = tf.cast(params["t_final"].get_value(), tf.float64)
sigma = tf.cast(params["sigma"].get_value(), tf.float64)
norm = tf.sqrt(2 * np.pi * sigma ** 2) * tf.math.erf(
t_final / (np.sqrt(8) * sigma)
) - t_final * tf.exp(-(t_final ** 2) / (8 * sigma ** 2))
Expand Down
3 changes: 3 additions & 0 deletions c3/parametermap.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ def read_config(self, filepath: str) -> None:
"""
with open(filepath, "r") as cfg_file:
cfg = hjson.loads(cfg_file.read())
self.fromdict(cfg)

def fromdict(self, cfg: dict) -> None:
for key, gate in cfg.items():
if "mapto" in gate.keys():
instr = copy.deepcopy(self.instructions[gate["mapto"]])
Expand Down
6 changes: 3 additions & 3 deletions c3/signal/pulse.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,20 @@ def __init__(
self.shape = envelopes[shape]
else:
self.shape = shape
params_default = {
default_params = {
"amp": Qty(value=0.0, min_val=-1.0, max_val=+1.0, unit="V"),
"delta": Qty(value=0.0, min_val=-5.0, max_val=+5.0, unit="V"),
"freq_offset": Qty(value=0.0, min_val=-1.0, max_val=+1.0, unit="Hz 2pi"),
"xy_angle": Qty(value=0.0, min_val=-1.0, max_val=+1.0, unit="rad"),
"sigma": Qty(value=5e-9, min_val=-2.0, max_val=+2.0, unit="s"),
"t_final": Qty(value=0.0, min_val=-1.0, max_val=+1.0, unit="s"),
}
params_default.update(params)
default_params.update(params)
super().__init__(
name=name,
desc=desc,
comment=comment,
params=params_default,
params=default_params,
)

def write_config(self, filepath: str) -> None:
Expand Down
Loading