"""Pulse class."""fromtypingimportAnnotated,Literal,Union,castfromuuidimportuuid4importnumpyasnpfrompydanticimportUUID4,Fieldfrom..serializeimportModelfrom.envelopeimportEnvelope,IqWaveform,Waveform__all__=["Acquisition","Align","Delay","Pulse","PulseId","PulseLike","Readout","VirtualZ",]PulseId=UUID4"""Unique identifier for a pulse."""class_PulseLike(Model):id_:PulseId=Field(default_factory=uuid4,exclude=True)@propertydefid(self)->PulseId:"""Instruction identifier."""returnself.id_defnew(self)->"PulseLike":returncast(PulseLike,self.model_copy(deep=True,update={"id_":uuid4()}))def__eq__(self,other:object)->bool:"""Compare instances."""# TODO: for the time being, Pydantic does not support fields# inclusion/exclusion in comparison, otherwise it would be much better to# exclude them rather then applying this recursive definition# https://github.com/pydantic/pydantic/discussions/6717s=vars(self)o=vars(other)returnisinstance(other,type(self))andall(s[k]==o[k]forkinsifk!="id_")def__hash__(self)->int:returnhash(tuple(vfork,vinvars(self).items()ifk!="id_"))
[docs]classPulse(_PulseLike):"""A pulse to be sent to the QPU. Valid on any channel, except acquisition ones. """kind:Literal["pulse"]="pulse"duration:float"""Pulse duration."""amplitude:float"""Pulse digital amplitude (unitless). Pulse amplitudes are normalised between -1 and 1. """envelope:Envelope"""The pulse envelope shape. See :class:`qibolab.Envelope` for list of available shapes. """relative_phase:float=0.0"""Relative phase of the pulse, in radians."""
[docs]defi(self,sampling_rate:float)->Waveform:"""Compute the envelope of the waveform i component."""samples=int(self.duration*sampling_rate)returnself.amplitude*self.envelope.i(samples)
[docs]defq(self,sampling_rate:float)->Waveform:"""Compute the envelope of the waveform q component."""samples=int(self.duration*sampling_rate)returnself.amplitude*self.envelope.q(samples)
[docs]defenvelopes(self,sampling_rate:float)->IqWaveform:"""Compute a tuple with the i and q envelopes."""returnnp.array([self.i(sampling_rate),self.q(sampling_rate)])
[docs]classDelay(_PulseLike):"""Wait instruction. During its length no pulse is sent on the same channel. Valid on any channel. """kind:Literal["delay"]="delay"duration:float"""Duration in ns."""
[docs]classVirtualZ(_PulseLike):"""Implementation of Z-rotations using virtual phase. Only valid on a drive channel. """kind:Literal["virtualz"]="virtualz"phase:float"""Phase that implements the rotation."""@propertydefduration(self):"""Duration of the virtual gate should always be zero."""return0
[docs]classAcquisition(_PulseLike):"""Acquisition instruction. This event instructs the device to acquire samples for the event span. Only valid on an acquisition channel. """kind:Literal["acquisition"]="acquisition"duration:float"""Duration in ns."""
[docs]classReadout(_PulseLike):"""Readout instruction. This event instructs the device to acquire samples for the event span. Only valid on an acquisition channel. """kind:Literal["readout"]="readout"acquisition:Acquisitionprobe:Pulse
[docs]@classmethoddeffrom_probe(cls,probe:Pulse):"""Create a whole readout operation from its probe pulse. The acquisition is made to match the same probe duration. """returncls(acquisition=Acquisition(duration=probe.duration),probe=probe)
@propertydefduration(self)->float:"""Duration in ns."""returnself.acquisition.duration@propertydefid(self)->PulseId:"""Instruction identifier."""returnself.acquisition.id