[docs]classRfChain(Serializable):"""Radio-frequency (RF) chain model."""yaml_tag="RfChain"__phase_offset:float__amplitude_imbalance:float__power_amplifier:PowerAmplifier|None__phase_noise:PhaseNoise__adc:AnalogDigitalConverterdef__init__(self,phase_offset:float|None=None,amplitude_imbalance:float|None=None,adc:AnalogDigitalConverter|None=None,power_amplifier:PowerAmplifier|None=None,phase_noise:PhaseNoise|None=None,)->None:""" Args: phase_offset (float, optional): I/Q phase offset in radians. amplitude_imbalance (float, optional): I/Q amplitude imbalance. adc (AnalogDigitalConverter, optional): The analog to digital converter at the end of the RF receive chain. If not specified, ideal analog-to-digital conversion introducing no additional noise is assumed. power_amplifier (PowerAmplifier, optional): The power amplifier at the beginning of the RF transmit chain. If not specified, ideal linear power amplification is assumed. phase_noise (PhaseNoise, optional): Phase noise model configuration. If not specified, an ideal oscillator introducing no phase noise is assumed. """# Initialize class attributesself.phase_offset=0.0ifphase_offsetisNoneelsephase_offsetself.amplitude_imbalance=0.0ifamplitude_imbalanceisNoneelseamplitude_imbalanceself.adc=AnalogDigitalConverter()ifadcisNoneelseadcself.power_amplifier=power_amplifierself.phase_noise=NoPhaseNoise()ifphase_noiseisNoneelsephase_noise@propertydefamplitude_imbalance(self)->float:"""I/Q amplitude imbalance. Raises: ValueError: If the imbalance is less than zero or more than one. """returnself.__amplitude_imbalance@amplitude_imbalance.setterdefamplitude_imbalance(self,val)->None:if0>valorval>1.0:raiseValueError("Amplitude imbalance must be within interval [0, 1].")self.__amplitude_imbalance=val@propertydefphase_offset(self)->float:"""I/Q phase offset. Returns: Phase offset in radians. """returnself.__phase_offset@phase_offset.setterdefphase_offset(self,value:float)->None:self.__phase_offset=value@propertydefadc(self)->AnalogDigitalConverter:"""The analog to digital converter at the end of the RF receive chain."""returnself.__adc@adc.setterdefadc(self,value:AnalogDigitalConverter)->None:self.__adc=value
[docs]deftransmit(self,input_signal:Signal)->Signal:"""Returns the distorted version of signal in "input_signal". According to transmission impairments. """transmitted_signal=input_signal.copy()# Simulate IQ imbalancetransmitted_signal.set_samples(self.add_iq_imbalance(transmitted_signal[:,:]))# Simulate phase noisetransmitted_signal=self.phase_noise.add_noise(transmitted_signal)# Simulate power amplifierifself.power_amplifierisnotNone:transmitted_signal.set_samples(self.power_amplifier.send(transmitted_signal[:,:]))returntransmitted_signal
[docs]defadd_iq_imbalance(self,input_signal:np.ndarray)->np.ndarray:"""Adds Phase offset and amplitude error to input signal. Notation taken from https://en.wikipedia.org/wiki/IQ_imbalance. Args: input_signal (np.ndarray): Signal to be deteriorated as a matrix in shape `#no_antennas x #no_samples`. `#no_antennas` depends if on receiver or transmitter side. Returns: np.ndarray: Deteriorated signal with the same shape as `input_signal`. """x=input_signaleps_delta=self.__phase_offseteps_a=self.__amplitude_imbalanceeta_alpha=np.cos(eps_delta/2)+1j*eps_a*np.sin(eps_delta/2)eta_beta=eps_a*np.cos(eps_delta/2)-1j*np.sin(eps_delta/2)returneta_alpha*x+eta_beta*np.conj(x)
[docs]defreceive(self,input_signal:Signal)->Signal:"""Returns the distorted version of signal in "input_signal". According to reception impairments. """input_signal=input_signal.copy()# Simulate IQ imbalanceinput_signal.set_samples(self.add_iq_imbalance(input_signal[:,:]))# Simulate phase noiseinput_signal=self.phase_noise.add_noise(input_signal)returninput_signal
@propertydefpower_amplifier(self)->PowerAmplifier:"""Access the `PowerAmplifier` of the rf chain. Returns: A handle to the `PowerAmplifier`. """returnself.__power_amplifier@power_amplifier.setterdefpower_amplifier(self,value:PowerAmplifier)->None:self.__power_amplifier=value@propertydefphase_noise(self)->PhaseNoise:"""Phase Noise model configuration."""returnself.__phase_noise@phase_noise.setterdefphase_noise(self,value:PhaseNoise)->None:self.__phase_noise=value