[docs]classDelayCalibration(DelayCalibrationBase,Serializable):"""Static delay calibration"""yaml_tag="DelayCalibration"__delay:floatdef__init__(self,delay:float,physical_device:PhysicalDevice|None=None)->None:# Initialize base classDelayCalibrationBase.__init__(self,physical_device)# Initialize class attributesself.delay=delay@propertydefdelay(self)->float:returnself.__delay@delay.setterdefdelay(self,value:float)->None:self.__delay=valuedefto_HDF(self,group:Group)->None:# Serialize attributesgroup.attrs["delay"]=self.delay@classmethoddeffrom_HDF(cls:Type[DelayCalibration],group:Group)->DelayCalibration:# Deserialize attributesdelay=group.attrs["delay"]# Return new instancereturncls(delay=delay)
[docs]@staticmethoddefEstimate(device:PhysicalDevice,max_delay:float,num_iterations:int=10,wait:float=0.0)->DelayCalibration:"""Estimate a physical device's inherent transmit-receive delay. Ideally, the transmit and receive channels of the device should be connected by a patch cable. WARNING: An attenuator element may be required! Be careful!!!! Args: device (PhysicalDevice): The physical device to calibrate, i.e. the device of which a delay is to be estimated. max_delay (float): The maximum expected delay which the calibration should compensate for in seconds. num_iterations (int, optional): Number of calibration iterations. Default is 10. wait (float, optional): Idle time between iteration transmissions in seconds. Zero by default. Returns: An initialized delay calibration instance. """ifnum_iterations<1:raiseValueError("The number of iterations must be greater or equal to one")ifwait<0.0:raiseValueError("The waiting time must be greater or equal to zero")sampling_rate=device.max_sampling_ratenum_samples=int(2*max_delay*device.max_sampling_rate)ifnum_samples<=1:raiseValueError("The assumed maximum delay is not resolvable by the configured sampling rate")dirac_index=int(max_delay*sampling_rate)waveform=np.zeros((device.num_antennas,num_samples),dtype=complex)waveform[:,dirac_index]=1.0calibration_signal=Signal.Create(waveform,sampling_rate,device.carrier_frequency)propagated_signals:List[Signal]=[]propagated_dirac_indices=np.empty(num_iterations,dtype=int)# Make multiple iteration calls for calibrationforninrange(num_iterations):propagated_signal=device.trigger_direct(calibration_signal)# Infer the implicit delay by estimating the sample index of the propagated diracpropagated_signals.append(propagated_signal)propagated_dirac_indices[n]=np.argmax(np.abs(propagated_signal[0,:]))# Wait the configured amount of time between iterationssleep(wait)# Compute calibration delay# This is just a ML estimationmean_dirac_index=np.mean(propagated_dirac_indices)calibration_delay=(mean_dirac_index-dirac_index)/propagated_signal.sampling_rate# Visualize the results# Feature currently deactivated# fig, axes = plt.subplots(2, 1)# fig.suptitle("Device Delay Calibration")# axes[0].plot(calibration_signal.timestamps, abs(calibration_signal[0, :]))# for sig in propagated_signals:# axes[1].plot(sig.timestamps, abs(sig[0, :]), color="blue")# axes[1].axvline(x=(dirac_index / sampling_rate - calibration_delay), color="red")returnDelayCalibration(calibration_delay)