def close(self): '''closing instruments: ''' AWG.Abort_Gen(self.awgsess) AWG.close(self.awgsess) PSGA.rfoutput(self.saga, action=['Set', 0]) PSGA.close(self.saga, False) MXA.close(self.mxa, False)
def nelder_mead(self, no_improve_thr=10e-6, no_improv_break=10, max_iter=0, alpha=1., gamma=2., rho=-0.5, sigma=0.5, time=0): ''' Pure Python/Numpy implementation of the Nelder-Mead algorithm. Reference: https://en.wikipedia.org/wiki/Nelder%E2%80%93Mead_method ''' ''' @param f (function): function to optimize, must return a scalar score and operate over a numpy array of the same dimensions as x_start @param x_start (numpy array): initial position @param step (float): look-around radius in initial step @no_improv_thr, no_improv_break (float, int): break after no_improv_break iterations with an improvement lower than no_improv_thr @max_iter (int): always break after this number of iterations. Set it to 0 to loop indefinitely. @alpha, gamma, rho, sigma (floats): parameters of the algorithm (see Wikipedia page for reference) return: tuple (best parameter array, best score) ''' index = time % 2 dim = len(self.var) "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, self.IQparams) "read signal amplitude at LO frequency in and assign it as score" MXA.preamp(mxa, action=['Set', 'OFF']) # MXA.preamp_band(mxa, action=['Set','FULL']) # MXA.attenuation(mxa, action=['Set','14dB']) MXA.attenuation_auto(mxa, action=['Set', 'ON']) power = float((MXA.fpower( mxa, str(5.5 - 0.025 * index) + 'GHz')).split('dBm')[0]) - index * float( (MXA.fpower(mxa, str(5.5 + 0.025 * index) + 'GHz')).split('dBm')[0]) prev_best = power no_improv = 0 res = [[self.var, prev_best]] # while True: # print("LOPower: %s" %power) # if bool(input('hello')): break for i in range(dim): x = copy.copy(self.var) x[i] = x[i] + self.step[i] "tell AWG to apply DC offset(x) on I & Q" if self.suppression == 'LO': self.IQparams[:2] = x elif self.suppression == 'MR': self.IQparams[2:] = x AWG_Sinewave(25, self.IQparams) "read signal amplitude at LO frequency in and assign it as score" power = float( (MXA.fpower(mxa, str(5.5 - 0.025 * index) + 'GHz')).split('dBm')[0] ) - index * float( (MXA.fpower(mxa, str(5.5 + 0.025 * index) + 'GHz')).split('dBm')[0]) score = power res.append([x, score]) # simplex iter iters = 0 while 1: # order res.sort(key=lambda x: x[1]) if self.suppression == 'LO': self.IQparams[:2] = res[0][0] elif self.suppression == 'MR': self.IQparams[2:] = res[0][0] # print(Fore.YELLOW + "\rProgress time#%s: %s" %(time, self.IQparams), end='\r', flush=True) best = res[0][1] # break after max_iter if max_iter and iters >= max_iter: return res[0] iters += 1 # AWG_Sinewave(25, self.IQparams) # if float((RSA5.fpower(rsa, str(5.5)+'GHz')).split('dBm')[0]) < -65. and float((RSA5.fpower(rsa, str(5.475)+'GHz')).split('dBm')[0]) < -65.: # return array([self.IQparams, best, 0.]) if best < prev_best - no_improve_thr or best == prev_best: no_improv = 0 prev_best = best else: no_improv += 1 if no_improv >= no_improv_break: AWG_Sinewave(25, self.IQparams) print("Rest at Optimized IQ Settings: %s" % self.IQparams) return array([self.IQparams, best]) # Optimized parameters # centroid x0 = [0.] * dim for tup in res[:-1]: for i, c in enumerate(tup[0]): x0[i] += c / (len(res) - 1) # reflection xr = x0 + alpha * (x0 - res[-1][0]) if self.suppression == 'LO': self.IQparams[:2] = xr elif self.suppression == 'MR': self.IQparams[2:] = xr "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, self.IQparams) "read signal amplitude at LO frequency in and assign it as score" power = float( (MXA.fpower(mxa, str(5.5 - 0.025 * index) + 'GHz')).split('dBm')[0] ) - index * float( (MXA.fpower(mxa, str(5.5 + 0.025 * index) + 'GHz')).split('dBm')[0]) rscore = power if res[0][1] <= rscore < res[-2][1]: del res[-1] res.append([xr, rscore]) continue # expansion if rscore < res[0][1]: xe = x0 + gamma * (x0 - res[-1][0]) if self.suppression == 'LO': self.IQparams[:2] = xe elif self.suppression == 'MR': self.IQparams[2:] = xe "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, self.IQparams) "read signal amplitude at LO frequency in and assign it as score" power = float((MXA.fpower( mxa, str(5.5 - 0.025 * index) + 'GHz')).split('dBm')[0]) - index * float((MXA.fpower( mxa, str(5.5 + 0.025 * index) + 'GHz')).split('dBm')[0]) escore = power if escore < rscore: del res[-1] res.append([xe, escore]) continue else: del res[-1] res.append([xr, rscore]) continue # contraction xc = x0 + rho * (x0 - res[-1][0]) if self.suppression == 'LO': self.IQparams[:2] = xc elif self.suppression == 'MR': self.IQparams[2:] = xc "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, self.IQparams) "read signal amplitude at LO frequency in and assign it as score" power = float( (MXA.fpower(mxa, str(5.5 - 0.025 * index) + 'GHz')).split('dBm')[0] ) - index * float( (MXA.fpower(mxa, str(5.5 + 0.025 * index) + 'GHz')).split('dBm')[0]) cscore = power if cscore < res[-1][1]: del res[-1] res.append([xc, cscore]) continue # reduction x1 = res[0][0] nres = [] for tup in res: redx = x1 + sigma * (tup[0] - x1) if self.suppression == 'LO': self.IQparams[:2] = redx elif self.suppression == 'MR': self.IQparams[2:] = redx "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, self.IQparams) "read signal amplitude at LO frequency in and assign it as score" power = float((MXA.fpower( mxa, str(5.5 - 0.025 * index) + 'GHz')).split('dBm')[0]) - index * float((MXA.fpower( mxa, str(5.5 + 0.025 * index) + 'GHz')).split('dBm')[0]) score = power nres.append([redx, score]) res = nres
import copy from pyqum.instrument.benchtop import RSA5, PSGA, MXA from pyqum.instrument.modular import AWG from pyqum.instrument.logger import status_code from pyqum.instrument.analyzer import curve from numpy import sin, cos, pi, array, float64, sum, dot # Initialize instruments: # PSGA saga = PSGA.Initiate() PSGA.rfoutput(saga, action=['Set', 1]) PSGA.frequency(saga, action=['Set', "5.5" + "GHz"]) PSGA.power(saga, action=['Set', "12" + "dBm"]) # SA mxa = MXA.Initiate() MXA.frequency(mxa, action=['Set', '5.525GHz']) MXA.fspan(mxa, action=['Set', '150MHz']) MXA.rbw(mxa, action=['Set', '1MHz']) MXA.vbw(mxa, action=['Set', '100kHz']) MXA.trigger_source(mxa, action=['Set', 'EXTernal1']) # AWG awgsess = AWG.InitWithOptions() AWG.Abort_Gen(awgsess) AWG.ref_clock_source(awgsess, action=['Set', int(1)]) # External 10MHz clock-reference AWG.predistortion_enabled(awgsess, action=['Set', True]) AWG.output_mode_adv(awgsess, action=['Set', int(2)]) # Sequence output mode AWG.arb_sample_rate(awgsess, action=['Set', float(1250000000)]) # maximum sampling rate AWG.active_marker(awgsess, action=['Set', '3']) # master
def Initialize(self): # Initialize instruments: # PSGA self.saga = PSGA.Initiate() PSGA.rfoutput(self.saga, action=['Set', 1]) PSGA.frequency(self.saga, action=['Set', "5.5" + "GHz"]) PSGA.power(self.saga, action=['Set', "12" + "dBm"]) # SA self.mxa = MXA.Initiate() MXA.frequency(self.mxa, action=['Set', '5.525GHz']) MXA.fspan(self.mxa, action=['Set', '150MHz']) MXA.rbw(self.mxa, action=['Set', '1MHz']) MXA.vbw(self.mxa, action=['Set', '100kHz']) MXA.trigger_source(self.mxa, action=['Set', 'EXTernal1']) # AWG self.awgsess = AWG.InitWithOptions() AWG.Abort_Gen(self.awgsess) AWG.ref_clock_source(self.awgsess, action=['Set', int(1)]) # External 10MHz clock-reference AWG.predistortion_enabled(self.awgsess, action=['Set', True]) AWG.output_mode_adv(self.awgsess, action=['Set', int(2)]) # Sequence output mode AWG.arb_sample_rate(self.awgsess, action=['Set', float(1250000000) ]) # maximum sampling rate AWG.active_marker(self.awgsess, action=['Set', '3']) # master AWG.marker_delay(self.awgsess, action=['Set', float(0)]) AWG.marker_pulse_width(self.awgsess, action=['Set', float(1e-7)]) AWG.marker_source(self.awgsess, action=['Set', int(7)]) samplingrate = AWG.arb_sample_rate(self.awgsess)[1] dt = 1e9 / samplingrate # in ns # PRESET Output: for ch in range(2): channel = str(ch + 1) AWG.output_config(self.awgsess, RepCap=channel, action=["Set", 0]) # Single-ended AWG.output_filter_bandwidth(self.awgsess, RepCap=channel, action=["Set", 0]) AWG.arb_gain(self.awgsess, RepCap=channel, action=["Set", 0.5]) AWG.output_impedance(self.awgsess, RepCap=channel, action=["Set", 50]) # output settings: for ch in range(2): channel = str(ch + 1) AWG.output_enabled(self.awgsess, RepCap=channel, action=["Set", int(1)]) # ON AWG.output_filter_enabled(self.awgsess, RepCap=channel, action=["Set", True]) AWG.output_config(self.awgsess, RepCap=channel, action=["Set", int(2)]) # Amplified 1:2 AWG.output_filter_bandwidth(self.awgsess, RepCap=channel, action=["Set", 0]) AWG.arb_gain(self.awgsess, RepCap=channel, action=["Set", 0.5]) AWG.output_impedance(self.awgsess, RepCap=channel, action=["Set", 50])
def test(): LO_0 = float((MXA.fpower(mxa, str(5.5) + 'GHz')).split('dBm')[0]) Mirror_0 = float((MXA.fpower(mxa, str(5.475) + 'GHz')).split('dBm')[0]) Initial = [0., 0., 1., 0., 0.] time = 0 OPT = IQ_Cal() OPT.IQparams = array(Initial, dtype=float64) #overwrite initial values result = OPT.nelder_mead(time=time) prev = result[0] no_improv, no_improv_thr, no_improv_break = 0, 1e-5, 4 LO, Mirror, T = [], [], [] while True: time += 1 if time % 2: OPT = IQ_Cal('MR', result[0], ratio=time) else: OPT = IQ_Cal('LO', result[0], ratio=time) result = OPT.nelder_mead(time=time) # if len(result) == 3: # print("Optimized IQ parameters:\n %s" %result) # break LO.append( float((MXA.fpower(mxa, str(5.5) + 'GHz')).split('dBm')[0]) - LO_0) Mirror.append( float((MXA.fpower(mxa, str(5.475) + 'GHz')).split('dBm')[0]) - Mirror_0) print(Back.BLUE + Fore.WHITE + "Mirror has been suppressed for %s from %s" % (Mirror[-1], Mirror_0)) T.append(time) ssq = sum((result[0] - prev)**2) if ssq > no_improv_thr: no_improv = 0 prev = result[0] else: no_improv += 1 if no_improv >= no_improv_break: AWG_Sinewave(25, OPT.IQparams) print(type(OPT.IQparams)) print("Optimized IQ parameters:\n %s" % result) print("Amplitude Imbalance:\n %s" % OPT.IQparams[2]) if OPT.IQparams[3] > OPT.IQparams[ 4] and OPT.IQparams[3] - OPT.IQparams[4] < 180: print("phase skew I-Q:\n %s" % (OPT.IQparams[3] - OPT.IQparams[4])) if OPT.IQparams[3] > OPT.IQparams[ 4] and OPT.IQparams[3] - OPT.IQparams[4] > 180: print("phase skew Q-I:\n %s" % (360 - (OPT.IQparams[3] - OPT.IQparams[4]))) if (OPT.IQparams[4] > OPT.IQparams[3] and OPT.IQparams[4] - OPT.IQparams[3] < 180) or ( OPT.IQparams[3] > OPT.IQparams[4] and OPT.IQparams[3] - OPT.IQparams[4] > 180): print("phase skew Q-I:\n %s" % (OPT.IQparams[4] - OPT.IQparams[3])) if (OPT.IQparams[2] > -1.0) and (OPT.IQparams[2] < 1.0): Iamp = 1 Qamp = Iamp * OPT.IQparams[2] else: Qamp = 1 Iamp = Qamp / OPT.IQparams[2] print("Ioffset:\n %s" % OPT.IQparams[0]) print("Qoffset:\n %s" % OPT.IQparams[1]) print("Iamp:\n %s" % Iamp) print("Qamp:\n %s" % Qamp) print("Iphase:\n %s" % OPT.IQparams[3]) print("Qphase:\n %s" % OPT.IQparams[4]) break curve(T, LO, 'LO Leakage vs time', 'T(#)', 'DLO(dB)') curve(T, Mirror, 'Mirror Image vs time', 'T(#)', 'DMirror(dB)') # closing instruments: ans = input("Press any keys to close AWG, PSGA and RSA-5 ") AWG.Abort_Gen(awgsess) AWG.close(awgsess) PSGA.rfoutput(saga, action=['Set', 0]) PSGA.close(saga, False) MXA.close(mxa, False)
def __init__(self, LO_freq, LO_powa, IF_freq): ''' Initialize relevant instruments: LO_freq: LO frequency in GHz LO_powa: LO power in dBm IF_freq: IF frequency in GHz ''' self.LO_freq, self.LO_powa, self.IF_freq = LO_freq, LO_powa, IF_freq # SA self.mxa = MXA.Initiate() MXA.frequency(self.mxa, action=['Set', '%sGHz' % (LO_freq + IF_freq)]) MXA.fspan(self.mxa, action=['Set', '150MHz']) MXA.rbw(self.mxa, action=['Set', '1MHz']) MXA.vbw(self.mxa, action=['Set', '100kHz']) MXA.trigger_source(self.mxa, action=['Set', 'EXTernal1']) # PSGA self.saga = PSGA.Initiate() PSGA.rfoutput(self.saga, action=['Set', 1]) PSGA.frequency(self.saga, action=['Set', "%sGHz" % LO_freq]) PSGA.power(self.saga, action=['Set', "%sdBm" % LO_powa]) # AWG self.awgsess = AWG.InitWithOptions() AWG.Abort_Gen(self.awgsess) AWG.ref_clock_source(self.awgsess, action=['Set', int(1)]) # External 10MHz clock-reference AWG.predistortion_enabled(self.awgsess, action=['Set', True]) AWG.output_mode_adv(self.awgsess, action=['Set', int(2)]) # Sequence output mode AWG.arb_sample_rate(self.awgsess, action=['Set', float(1250000000) ]) # maximum sampling rate AWG.active_marker(self.awgsess, action=['Set', '3']) # master AWG.marker_delay(self.awgsess, action=['Set', float(0)]) AWG.marker_pulse_width(self.awgsess, action=['Set', float(1e-7)]) AWG.marker_source(self.awgsess, action=['Set', int(7)]) # PRESET Output: for ch in range(2): channel = str(ch + 1) AWG.output_config(self.awgsess, RepCap=channel, action=["Set", 0]) # Single-ended AWG.output_filter_bandwidth(self.awgsess, RepCap=channel, action=["Set", 0]) AWG.arb_gain(self.awgsess, RepCap=channel, action=["Set", 0.5]) AWG.output_impedance(self.awgsess, RepCap=channel, action=["Set", 50]) # output settings: for ch in range(2): channel = str(ch + 1) AWG.output_enabled(self.awgsess, RepCap=channel, action=["Set", int(1)]) # ON AWG.output_filter_enabled(self.awgsess, RepCap=channel, action=["Set", True]) AWG.output_config(self.awgsess, RepCap=channel, action=["Set", int(2)]) # Amplified 1:2 AWG.output_filter_bandwidth(self.awgsess, RepCap=channel, action=["Set", 0]) AWG.arb_gain(self.awgsess, RepCap=channel, action=["Set", 0.5]) AWG.output_impedance(self.awgsess, RepCap=channel, action=["Set", 50])
def run(self): self.LO_Initial = float( (MXA.fpower(self.mxa, str(self.LO_freq) + 'GHz')).split('dBm')[0]) self.Mirror_Initial = float((MXA.fpower( self.mxa, str(self.LO_freq - self.IF_freq) + 'GHz')).split('dBm')[0]) self.settings() result = self.nelder_mead() prev = result[0] no_improv, no_improv_thr, no_improv_break = 0, 1e-5, 6 time, LO, Mirror, T = 0, [], [], [] while True: time += 1 if time % 2: self.settings('MR', result[0], logratio=time) else: self.settings('LO', result[0], logratio=time) result = self.nelder_mead(time=time) LO.append( float((MXA.fpower(self.mxa, str(self.LO_freq) + 'GHz')).split('dBm')[0]) - self.LO_Initial) Mirror.append( float((MXA.fpower(self.mxa, str(self.LO_freq - self.IF_freq) + 'GHz')).split('dBm')[0]) - self.Mirror_Initial) print(Back.BLUE + Fore.WHITE + "Mirror has been suppressed for %s from %s" % (Mirror[-1], self.Mirror_Initial)) T.append(time) ssq = sum((result[0] - prev)**2) if ssq > no_improv_thr: no_improv = 0 prev = result[0] else: no_improv += 1 if no_improv >= no_improv_break: print("Calibration completed!") AWG_Sinewave(self.awgsess, self.IF_freq * 1000, self.IQparams) print(type(self.IQparams)) print("Optimized IQ parameters:\n %s" % result) print("Amplitude Imbalance:\n %s" % self.IQparams[2]) if self.IQparams[3] > self.IQparams[ 4] and self.IQparams[3] - self.IQparams[4] < 180: print("phase skew I-Q:\n %s" % (self.IQparams[3] - self.IQparams[4])) if self.IQparams[3] > self.IQparams[ 4] and self.IQparams[3] - self.IQparams[4] > 180: print("phase skew Q-I:\n %s" % (360 - (self.IQparams[3] - self.IQparams[4]))) if (self.IQparams[4] > self.IQparams[3] and self.IQparams[4] - self.IQparams[3] < 180) or ( self.IQparams[3] > self.IQparams[4] and self.IQparams[3] - self.IQparams[4] > 180): print("phase skew Q-I:\n %s" % (self.IQparams[4] - self.IQparams[3])) if (self.IQparams[2] > -1.0) and (self.IQparams[2] < 1.0): Iamp = 1 Qamp = Iamp * self.IQparams[2] else: Qamp = 1 Iamp = Qamp / self.IQparams[2] print("Ioffset:\n %s" % self.IQparams[0]) print("Qoffset:\n %s" % self.IQparams[1]) print("Iamp:\n %s" % Iamp) print("Qamp:\n %s" % Qamp) print("Iphase:\n %s" % self.IQparams[3]) print("Qphase:\n %s" % self.IQparams[4]) break