Skip to content
Merged
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
43 changes: 22 additions & 21 deletions qupulse/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def forced_hash(obj) -> int:


def to_next_multiple(sample_rate: ExpressionLike, quantum: int,
min_quanta: Optional[int] = None) -> Callable[[ExpressionLike],ExpressionScalar]:
min_quanta: Optional[int] = None) -> Callable[[ExpressionScalar], ExpressionLike]:
"""Construct a helper function to expand a duration to one corresponding to
valid sample multiples according to the arguments given.
Useful e.g. for PulseTemplate.pad_to's 'to_new_duration'-argument.
Expand All @@ -141,33 +141,34 @@ def to_next_multiple(sample_rate: ExpressionLike, quantum: int,
quantum: number of samples to whose next integer multiple the duration shall be rounded up to.
min_quanta: number of multiples of quantum not to fall short of.
Returns:
A function that takes a duration (ExpressionLike) as input, and returns
A function that takes a duration as input, and returns
a duration rounded up to the next valid samples count in given sample rate.
The function returns 0 if duration==0, <0 is not checked if min_quanta is None.

"""
sample_rate = ExpressionScalar(sample_rate)

#is it more efficient to omit the Max call if not necessary?
if min_quanta is None:
#double negative for ceil division.
return lambda duration: -(-(duration*sample_rate)//quantum) * (quantum/sample_rate)
else:
qI = sp.Integer(quantum)
k = qI / sample_rate # factor to go from #quanta -> duration
mqI = sp.Integer(min_quanta)
def _build_sym(d):
u = d*sample_rate/qI # "duration in quanta" (real)
ce = sp.ceiling(u) # number of quanta after rounding up

# Enforce: 0 if d <= 0; else at least mqI quanta.
# max(mqI, ceil(u)) <=> mqI if u <= mqI, else ceil(u)
# do not evaluate right now because parameters could still be variable,
# then it's just overhead.
return sp.Piecewise(
(0, sp.Le(d, 0)),
(k*mqI, sp.Le(u, mqI)),
(k*ce, True)
, evaluate=False)
return lambda duration: ExpressionScalar(_build_sym(duration))
# work with sympy
sample_rate = sample_rate.sympified_expression
duration_per_quantum = sp.Integer(quantum) / sample_rate
minimal_duration = duration_per_quantum * min_quanta

def build_next_multiple(duration: ExpressionScalar) -> ExpressionLike:
duration = sp.sympify(duration)
n_quanta = sp.ceiling(duration / duration_per_quantum)
rounded_up_duration = n_quanta * duration_per_quantum

next_multiple_sp = sp.Piecewise(
(0, sp.Le(n_quanta, 0)),
(minimal_duration, sp.Le(n_quanta, min_quanta)),
(rounded_up_duration, True),
evaluate=False,
)
return ExpressionScalar(next_multiple_sp)

return build_next_multiple
Loading