Source code for qupulse.hardware.util
from typing import List, Sequence
import itertools
import numpy as np
__all__ = ['voltage_to_uint16']
[docs]def voltage_to_uint16(voltage: np.ndarray, output_amplitude: float, output_offset: float, resolution: int) -> np.ndarray:
"""
:param voltage:
:param output_amplitude:
:param output_offset:
:param resolution:
:return:
"""
if resolution < 1 or not isinstance(resolution, int):
raise ValueError('The resolution must be an integer > 0')
non_dc_voltage = voltage - output_offset
if np.any(np.abs(non_dc_voltage) > output_amplitude):
raise ValueError('Voltage of range', dict(voltage=voltage,
output_offset=output_offset,
output_amplitude=output_amplitude))
non_dc_voltage += output_amplitude
non_dc_voltage *= (2**resolution - 1) / (2*output_amplitude)
np.rint(non_dc_voltage, out=non_dc_voltage)
return non_dc_voltage.astype(np.uint16)
def make_combined_wave(segments: List['TaborSegment'], destination_array=None, fill_value=None) -> np.ndarray:
quantum = 16
if len(segments) == 0:
return np.zeros(0, dtype=np.uint16)
segment_lengths = np.fromiter((segment.num_points for segment in segments), count=len(segments), dtype=int)
if np.any(segment_lengths % quantum != 0):
raise ValueError('Segment is not a multiple of 16')
n_quanta = np.sum(segment_lengths) // quantum + len(segments) - 1
if destination_array is not None:
if len(destination_array) != 2*n_quanta*quantum:
raise ValueError('Destination array has an invalid length')
destination_array = destination_array.reshape((2*n_quanta, quantum))
else:
destination_array = np.empty((2*n_quanta, quantum), dtype=np.uint16)
if fill_value:
destination_array[:] = fill_value
# extract data that already includes the markers
data, next_data = itertools.tee(((segment.data_a, segment.data_b) for segment in segments), 2)
next(next_data, None)
current_quantum = 0
for (data_a, data_b), next_segment, segment_length in itertools.zip_longest(data, next_data, segment_lengths):
segment_quanta = 2 * (segment_length // quantum)
segment_destination = destination_array[current_quantum:current_quantum+segment_quanta, :]
if data_b is not None:
segment_destination[::2, :].flat = data_b
if data_a is not None:
segment_destination[1::2, :].flat = data_a
current_quantum += segment_quanta
if next_segment:
# fill one quantum with first data point from next segment
next_data_a, next_data_b = next_segment
if next_data_b is not None:
destination_array[current_quantum, :] = next_data_b[0]
if next_data_a is not None:
destination_array[current_quantum+1, :] = next_data_a[0]
current_quantum += 2
return destination_array.ravel()
def find_positions(data: Sequence, to_find: Sequence) -> np.ndarray:
"""Find indices of the first occurrence of the elements of to_find in data. Elements that are not in data result in
-1"""
data_sorter = np.argsort(data)
pos_left = np.searchsorted(data, to_find, side='left', sorter=data_sorter)
pos_right = np.searchsorted(data, to_find, side='right', sorter=data_sorter)
found = pos_left < pos_right
positions = np.full_like(to_find, fill_value=-1, dtype=np.int64)
positions[found] = data_sorter[pos_left[found]]
return positions