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 as MXA from pyqum.instrument.benchtop import PSGA 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', "13" + "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 __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(5.5) + 'GHz')).split('dBm')[0]) self.Mirror_Initial = float( (MXA.fpower(self.mxa, str(5.475) + 'GHz')).split('dBm')[0]) self.settings() result = self.nelder_mead() prev = result[0] no_improv, no_improv_thr, no_improv_break = 0, 1e-5, 4 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(5.5) + 'GHz')).split('dBm')[0]) - self.LO_Initial) Mirror.append( float((MXA.fpower(self.mxa, str(5.475) + '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
def nelder_mead(x_start, step=[-0.5, -0.5, 0.5, -0.5, 10, 10], no_improve_thr=10e-6, no_improv_break=10, max_iter=0, alpha=1., gamma=2., rho=-0.5, sigma=0.5): ''' @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) ''' # init dim = len(x_start) "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, x_start[0], x_start[1], x_start[2], x_start[3], x_start[4], x_start[5]) "read signal amplitude at LO frequency in and assign it as score" LOpower = float((RSA5.fpower(rsa, '5.5GHz')).split('dBm')[0]) Mrrpower = float((RSA5.fpower(rsa, '5.475GHz')).split('dBm')[0]) prev_best = Mrrpower + 0 no_improv = 0 res = [[x_start, prev_best]] while True: print("LO Power: %s" % LOpower) print("Mirror Power: %s" % Mrrpower) if bool(input('hello')): break for i in range(dim): x = copy.copy(x_start) x[i] = x[i] + step[i] print('applying %s' % x) "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, x[0], x[1], x[2], x[3], x[4], x[5]) "read signal amplitude at LO frequency in and assign it as score" LOpower = float((RSA5.fpower(rsa, '5.5GHz')).split('dBm')[0]) Mrrpower = float((RSA5.fpower(rsa, '5.475GHz')).split('dBm')[0]) score = Mrrpower + 0 res.append([x, score]) # simplex iter iters = 0 while 1: # order res.sort(key=lambda x: x[1]) best = res[0][1] # break after max_iter if max_iter and iters >= max_iter: return res[0] iters += 1 # break after no_improv_break iterations with no improvement print('...best so far:', best) 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: print("Rest at Optimized IQ Settings: %s" % res[0][0]) AWG_Sinewave(25, res[0][0][0], res[0][0][1], res[0][0][2], res[0][0][3], res[0][0][4], res[0][0][5]) return res[0] # 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]) "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, xr[0], xr[1], xr[2], xr[3], xr[4], xr[5]) "read signal amplitude at LO frequency in and assign it as score" LOpower = float((RSA5.fpower(rsa, '5.5GHz')).split('dBm')[0]) Mrrpower = float((RSA5.fpower(rsa, '5.475GHz')).split('dBm')[0]) rscore = Mrrpower + 0 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]) "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, xe[0], xe[1], xe[2], xe[3], xe[4], xe[5]) "read signal amplitude at LO frequency in and assign it as score" LOpower = float((RSA5.fpower(rsa, '5.5GHz')).split('dBm')[0]) Mrrpower = float((RSA5.fpower(rsa, '5.475GHz')).split('dBm')[0]) escore = Mrrpower + 0 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]) "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, xc[0], xc[1], xc[2], xc[3], xc[4], xc[5]) "read signal amplitude at LO frequency in and assign it as score" LOpower = float((RSA5.fpower(rsa, '5.5GHz')).split('dBm')[0]) Mrrpower = float((RSA5.fpower(rsa, '5.475GHz')).split('dBm')[0]) cscore = Mrrpower + 0 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) "tell AWG to apply DC offset(x) on I & Q" AWG_Sinewave(25, redx[0], redx[1], redx[2], redx[3], redx[4], redx[5]) "read signal amplitude at LO frequency in and assign it as score" LOpower = float((RSA5.fpower(rsa, '5.5GHz')).split('dBm')[0]) Mrrpower = float((RSA5.fpower(rsa, '5.475GHz')).split('dBm')[0]) score = Mrrpower + 0 nres.append([redx, score]) res = nres
import copy from pyqum.instrument.benchtop import RSA5, PSGA from pyqum.instrument.modular import AWG from pyqum.instrument.logger import status_code from numpy import sin, cos, pi, array, lcm, float64 # print('lcm of 12 ad 10 is %s' %lcm(12,10)) # 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', "0" + "dBm"]) # Rigol SA rsa = RSA5.Initiate() RSA5.frequency(rsa, action=['Set', '5.525GHz']) RSA5.fspan(rsa, action=['Set', '150MHz']) RSA5.rbw(rsa, action=['Set', '1MHz']) RSA5.vbw(rsa, action=['Set', '100kHz']) # 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', '1']) # master AWG.marker_delay(awgsess, action=['Set', float(0)])
from pyqum.instrument.benchtop import PSGA 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, lcm, float64, sum, dot # print('lcm of 12 ad 10 is %s' %lcm(12,10)) # 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"]) # Rigol SA rsa = RSA5.Initiate() RSA5.frequency(rsa, action=['Set', '5.525GHz']) RSA5.fspan(rsa, action=['Set', '150MHz']) RSA5.rbw(rsa, action=['Set', '1MHz']) RSA5.vbw(rsa, action=['Set', '100kHz']) # 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', '1']) # master AWG.marker_delay(awgsess, action=['Set', float(0)])