def _findAmplitude(self,voltages,frequency,shape): """ Only used by function calibrate. Measure and find the amplitude where the JBA is bi-evaluated, go to this point, and store this amplitude """ ps = [] max = 0 maxVoltage = 0 self.variances = zeros((len(voltages),2)) self.variances[:,0] = voltages data = Datacube("Variance") for i in range(0,len(voltages)): if self.stopped(): self._stopped = False raise Exception("Got stopped!") v = voltages[i] self.init() self.frequency(frequency=frequency,shape=v*shape) (av,trends, fr)=self.analyse() varsum =cov(trends[0,:,0])+cov(trends[1,:,0]) data.set(v = v) data.set(varsum=varsum) data.commit() self.notify("variance",(data.column("v"),data.column("varsum"))) self.notify("status","Variance at %g V: %g" % (v,varsum)) print "Variance at v = %f : %f" % (v,varsum) self.variances[i,1] = varsum ps.append(varsum) if varsum > max: max = varsum maxVoltage = voltages[i] self.frequency(frequency=frequency,shape=maxVoltage*shape) return (ps,max,maxVoltage,data)
def _attenuatorRangeCheck(self,voltages): ps = [] max = 0 maxVoltage = 0 self.variances = zeros((len(voltages),2)) self.variances[:,0] = voltages data = Datacube("Variance") for i in range(0,len(voltages)): if self.stopped(): self._stopped = False raise Exception("Got stopped!") v = voltages[i] self._attenuator.setVoltage(v) self._acqiris.bifurcationMap(ntimes = 10) trends = self._acqiris.trends() varsum =cov(trends[self._params["acqirisChannel"]])+cov(trends[self._params["acqirisChannel"]+1]) data.set(v = v) data.set(varsum=varsum) data.commit() self.notify("variance",(data.column("v"),data.column("varsum"))) self.notify("status","Variance at %g V: %g" % (v,varsum)) print "Variance: %f" % varsum self.variances[i,1] = varsum ps.append(varsum) if varsum > max: max = varsum maxVoltage = voltages[i] return (ps,max,maxVoltage)
def caracteriseIQvsFvsP(self,frequencies,voltages,data=None): if data==None: data=Datacube("JBA mapping") dataManager.addDatacube(data) try: previousShape=self.shape self.shape=zeros((20000),dtype = numpy.complex128) self.shape[10000:10010]=linspace(0,1,10) self.shape[10010:12100]=1 self.shape[12100:12110]=linspace(1,0,10) # return self.shape import scipy pvsv=Datacube("power") data.addChild(pvsv) for v in voltages: self.setAmplitude(amplitude=v) p=self.measureJBAPower(f='autodetect') pvsv.set(v=v,bluePower=p) pvsv.commit() pv=scipy.interpolate.interp1d(pvsv.column("v"),pvsv.column("bluePower")) data.savetxt() for f in frequencies: child=Datacube("f=%f"%f) data.addChild(child) self.setFrequency(f) for v in voltages: self.setAmplitude(amplitude=v) time.sleep(0.5) co=self.getThisMeasure()[1] var=cov(co[0])+cov(co[1]) if var>0.01: cod=Datacube("components at p=%f" %pv(v)) cod.createColumn('I',co[0]) cod.createColumn('Q',co[1]) cod.createColumn('bluePower',[pv(v)]*len(co[0])) child.addChild(cod) else: ####### ECRIRE QUELQUE CHOSE ICI [I,Q]=[mean(co[0]),mean(co[1])] child.set(f=f,v=v,I=I,Q=Q,sigma=var,bluePower=pv(v)) child.set(M=sqrt(I**2+Q**2)) child.set(phi=math.atan2(I,Q)) child.commit() data.set(f=f,v=v,I=I,Q=Q,sigma=var,bluePower=pv(v)) data.set(M=sqrt(I**2+Q**2)) data.set(phi=math.atan2(I,Q)) data.commit() data.savetxt() except: raise finally: data.savetxt() self.shape=previousShape
def measureSCurve(self,voltages = None,ntimes = 40,microwaveOff = True): self.notify("status","Measuring S curve...") def getVoltageBounds(v0,jba,variable,ntimes): v = v0 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = ntimes) p = jba._acqiris.Psw()[variable] while p > 0.03 and v < v0*2.0: v*=1.05 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = ntimes) p = jba._acqiris.Psw()[variable] vmax = v v = v0 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = ntimes) p = jba._acqiris.Psw()[variable] while p < 0.98 and v > v0/2.0: v/=1.05 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = ntimes) p = jba._acqiris.Psw()[variable] vmin = v return (vmin*0.95,vmax*1.2) try: v0 = self.voltage() state = self._qubitmwg.output() self._attenuator.turnOn() data = Datacube("S Curve") dataManager = DataManager() dataManager.addDatacube(data) if microwaveOff: self._qubitmwg.turnOff() if voltages == None: self.notify("status","Searching for proper voltage range...") (vmin,vmax) = getVoltageBounds(v0,self,self._params["variable"],ntimes) voltages = arange(vmin,vmax,0.005) self.notify("status","Measuring S curve in voltage range [%g - %g]..." % (vmin,vmax)) for v in voltages: self.setVoltage(v) self._acqiris.bifurcationMap(ntimes = ntimes) data.set(v = v) data.set(**(self._acqiris.Psw())) data.commit() self.notify("sCurve",(data.column("v"),data.column(self._params["variable"]))) finally: self.notify("status","S curve complete.") self.setVoltage(v0) if state: self._qubitmwg.turnOn()
def getTrace(self,correctPhase = False,waitFullSweep = False,timeOut = 200): print "Getting trace..." trace = Datacube() if DEBUG: print "Getting trace..." handle = self.getHandle() handle.timeout = timeOut if waitFullSweep: # freqs = self.ask_for_values("HLD;TRS;WFS;fma;msb;OFV;") 2011/12 VS self.write("TRS;WFS;") freqs = self.ask_for_values("fma;msb;OFV;") data = self.ask_for_values("fma;msb;OFD;") freqs.pop(0) data.pop(0) mag = [] phase = [] #If y length is twice the x length, we got phase and magnitude. if len(data) == 2*len(freqs): for i in range(0,len(data)): if i%2 == 0: mag.append(data[i]) else: phase.append(data[i]) else: mag = data trace.createColumn("freq",freqs) trace.createColumn("mag",mag) attenuation = float(self.ask("SA1?")) power = float(self.ask("PWR?")) trace.column("mag")[:]+= attenuation params = dict() params["attenuation"] = attenuation params["power"] = power trace.setParameters(params) if len(phase) > 0: correctedPhase = [] if correctPhase: correctedPhase.append(phase[0]) oldPhi = phase[0] for phi in phase[1:]: if fabs(phi+360.0-oldPhi) < fabs(phi-oldPhi): newPhi = phi+360.0 elif fabs(phi-360.0-oldPhi) < fabs(phi-oldPhi): newPhi = phi-360.0 else: newPhi = phi correctedPhase.append(newPhi) oldPhi = newPhi else: correctedPhase = phase trace.createColumn("phase",correctedPhase) print "returning trace." return trace
def sCurves(qubit,jba,variable = "p1x",data = None,ntimes = 20,optimize = "v20"): """ Measures the s curves of the JBA. Assumes that the qubit is alread preset to a pi-pulse. """ def getVoltageBounds(v0,jba,variable,ntimes): v = v0 jba.setVoltage(v) acqiris.bifurcationMap(ntimes = ntimes) p = acqiris.Psw()[variable] while p > 0.03 and v < v0*2.0: v*=1.05 jba.setVoltage(v) acqiris.bifurcationMap() p = acqiris.Psw()[variable] vmax = v v = v0 jba.setVoltage(v) acqiris.bifurcationMap(ntimes = ntimes) p = acqiris.Psw()[variable] while p < 0.98 and v > v0/2.0: v/=1.05 jba.setVoltage(v) acqiris.bifurcationMap() p = acqiris.Psw()[variable] vmin = v return (vmin*0.95,vmax*1.2) try: v0 = jba.voltage() if data == None: sData = Datacube() else: sData = data sData.setName("S curves - %s" % qubit.name()) sData.setParameters(instrumentManager.parameters()) s0 = Datacube("S0") s1 = Datacube("S1") s2 = Datacube("S2") sData.addChild(s0) sData.addChild(s1) sData.addChild(s2) qubit.turnOffDrive() (vmin,vmax) = getVoltageBounds(v0,jba,variable,ntimes) measureSingleS(voltages = arange(vmin,vmax,0.005),data = s0,jba = jba,ntimes = ntimes) qubit.turnOnDrive() loadPi01Pulse(qubit) measureSingleS(voltages = arange(vmin,vmax,0.005),data = s1,jba = jba,ntimes = ntimes) failed12 = False try: loadPi012Pulse(qubit) measureSingleS(voltages = arange(vmin,vmax,0.005),data = s2,jba = jba,ntimes = ntimes) s1.createColumn("contrast20",s2.column(variable)-s0.column(variable)) s1.createColumn("contrast21",s2.column(variable)-s1.column(variable)) qubit.parameters()["readout.v20"] = s1.column("v")[argmax(s1.column("contrast20"))] qubit.parameters()["readout.v21"] = s1.column("v")[argmax(s1.column("contrast21"))] except: failed12 = True raise s1.createColumn("contrast10",s1.column(variable)-s0.column(variable)) qubit.parameters()["readout.v10"] = s1.column("v")[argmax(s1.column("contrast10"))] if optimize == "v20" and not failed12: imax = argmax(s1.column("contrast20")) qubit.parameters()["readout.p11"] = s2.column(variable)[imax] v0 = s1.column("v")[imax] elif optimize == "v21" and not failed12: imax = argmax(s1.column("contrast21")) v0 = s1.column("v")[imax] else: imax = argmax(s1.column("contrast10")) qubit.parameters()["readout.p11"] = s1.column(variable)[imax] v0 = s1.column("v")[imax] #To do: Add dialog to ask to which voltage (v10,v20,v21) in qubit.parameters()["readout.p00"] = 1.0-s0.column(variable)[imax] return (sData,v0) finally: jba.setVoltage(v0) data.savetxt()
class IqOptimization(Reloadable): """ Optimizes the parameters of an IQ mixer. """ def __init__(self,mwg,fsp,awg,channels = [1,2]): Reloadable.__init__(self) self._mwg = mwg self._fsp = fsp self._awg = awg self._awgChannels = channels self.initCalibrationData() def initCalibrationData(self): """ Initialize the datacubes that contain the IQ calibration data. """ self._offsetCalibrationData = Datacube() self._offsetCalibrationData.setName("IQ mixer calibration - Offset Calibration Data") self._powerCalibrationData = Datacube() self._powerCalibrationData.setName("IQ mixer calibration - Power Calibration Data") self._sidebandCalibrationData = Datacube() self._sidebandCalibrationData.setName("IQ mixer calibration - Sideband Mixing Calibration Data") def sidebandCalibrationData(self): return self._sidebandCalibrationData def setSidebandCalibrationData(self,data): self._sidebandCalibrationData = data def offsetCalibrationData(self): """ Return the datacube containing the offset calibration data. """ return self._offsetCalibrationData def setOffsetCalibrationData(self,data): self._offsetCalibrationData = data self.updateOffsetCalibrationInterpolation() def updateOffsetCalibrationInterpolation(self): if len(self._offsetCalibrationData.column("frequency"))>1: frequencies = self._offsetCalibrationData.column("frequency") self._iOffsetInterpolation = scipy.interpolate.interp1d(frequencies,self._offsetCalibrationData.column("lowI")) self._qOffsetInterpolation = scipy.interpolate.interp1d(frequencies,self._offsetCalibrationData.column("lowQ")) else: self._iOffsetInterpolation=lambda x:self._offsetCalibrationData.column("lowI")[0] self._qOffsetInterpolation=lambda x:self._offsetCalibrationData.column("lowQ")[0] def powerCalibrationData(self): """ Return the datacube containing the power calibration data. """ return self._powerCalibrationData def setPowerCalibrationData(self,data): self._powerCalibrationData = data def teardown(self): """ Restore the original configuration. """ self._fsp.loadConfig("IQCalibration") self._awg.loadSetup("iq_calibration.awg") self._mwg.restoreState(self._mwgState) def setup(self,averaging = 10,reference = -50): """ Configure the AWG and the FSP for the IQ mixer calibration. """ self._fsp.storeConfig("IQCalibration") self._awg.saveSetup("iq_calibration.awg") self._mwgState = self._mwg.saveState("iq calibration") self._fsp.write("SENSE1:FREQUENCY:SPAN 0 MHz") period = int(1.0/self._awg.repetitionRate()*1e9) self._fsp.write("SWE:TIME 2 ms") self._rbw = 1000 self._fsp.write("SENSE1:BAND:RES %f Hz" % self._rbw) self._fsp.write("SENSE1:BAND:VIDEO AUTO") self._fsp.write("TRIG:SOURCE EXT") self._fsp.write("TRIG:HOLDOFF 0.02 s") self._fsp.write("TRIG:LEVEL 0.5 V") self._fsp.write("TRIG:SLOP POS") self._fsp.write("SENSE1:AVERAGE:COUNT %d" % averaging) self._fsp.write("SENSE1:AVERAGE:STAT1 ON") self._fsp.write("DISP:TRACE1:Y:RLEVEL %f" % reference) self.setupWaveforms() def setupWaveforms(self): self._awg.write("AWGC:RMOD CONT") period = int(1.0/self._awg.repetitionRate()*1e9) print period waveformOffset = zeros((period)) waveformActive = zeros((period))+1.0 waveformPassive = zeros((period))-1.0 self._markers = zeros((period),dtype = uint8) self._markers[1:len(self._markers)/2] = 255 self._awg.createRawWaveform("IQ_Offset_Calibration",waveformOffset,self._markers,"REAL") self._awg.createRawWaveform("IQ_Power_Calibration_active",waveformActive,self._markers,"REAL") self._awg.createRawWaveform("IQ_Power_Calibration_passive",waveformPassive,self._markers,"REAL") length = int(1.0/self._awg.repetitionRate()*1e9) waveform = self.generateSidebandWaveform(f_sb = 0, c = 0,phi = 0,length = length) self._awg.createRawWaveform("IQ_Sideband_Calibration_I",waveform,self._markers,"REAL") self._awg.createRawWaveform("IQ_Sideband_Calibration_Q",waveform,self._markers,"REAL") def loadSidebandWaveforms(self): self._awg.setWaveform(1,"IQ_Sideband_Calibration_I") self._awg.setWaveform(2,"IQ_Sideband_Calibration_Q") self._awg.setWaveform(3,"IQ_Sideband_Calibration_I") self._awg.setWaveform(4,"IQ_Sideband_Calibration_Q") def loadSidebandCalibrationWaveform(self,f_sb = 0,c = 0,phi = 0): length = int(1.0/self._awg.repetitionRate()*1e9) waveform = self.generateSidebandWaveform(f_sb = f_sb, c = c,phi = phi,length = length) self._awg.createRawWaveform("IQ_Sideband_Calibration_I",real(waveform)*0.5,self._markers,"REAL") self._awg.createRawWaveform("IQ_Sideband_Calibration_Q",imag(waveform)*0.5,self._markers,"REAL") return waveform def sidebandParameters(self,f_c,f_sb): if self.sidebandCalibrationData().column("f_c") == None: return (0,0) min_index = argmin(abs(self.sidebandCalibrationData().column("f_c")-f_c)) f_c = self.sidebandCalibrationData()["f_c"][min_index] if min_index == None: return (0,0) calibrationData = self.sidebandCalibrationData().children(f_c = f_c)[0] rows = calibrationData.search(f_sb = f_sb) if rows != []: c = calibrationData.column("c")[rows[0]] phi = calibrationData.column("phi")[rows[0]] else: phiInterpolation = scipy.interpolate.interp1d(calibrationData.column("f_sb"),calibrationData.column("phi")) cInterpolation = scipy.interpolate.interp1d(calibrationData.column("f_sb"),calibrationData.column("c")) c = cInterpolation(f_sb) phi = phiInterpolation(f_sb) return (c,phi) def calibrationParameters(self, f_c, f_sb): (iO,qO)=(self.iOffset(f_c),self.qOffset(f_c)) (c,phi) = self.sidebandParameters(f_c,f_sb) return (iO, qO, c, phi) def generateCalibratedSidebandWaveform(self,f_c,f_sb = 0,length = 100,delay = 0): (c,phi) = self.sidebandParameters(f_c,f_sb) # print "Generating a sideband waveform at f_c = %g GHz at f_sb = %g GHZ, c = %g, phi = %g deg" % (f_c,f_sb,c,phi*180.0/math.pi) return self.generateSidebandWaveform(f_sb,length = length,delay = delay,c = c,phi = phi)*0.8 def generateSidebandWaveform(self,f_sb = 0,c = 0,phi = 0,length = 100,delay = 0,normalize = True): """ Generates a sideband waveform using a sideband frequency "f_sb", an amplitude correction "c" and a phase correction "phi" """ if length == 0: return array([]) waveformIQ = zeros((max(1,length)),dtype = complex128) times = arange(0,length,1) cr = c*exp(1j*phi) waveformIQ = exp(-1.j*f_sb*2.0*math.pi*(times+float(delay)))+cr*exp(1.j*f_sb*2.0*math.pi*(times+float(delay))) return waveformIQ def calibrateIQPower(self,amplitude = 3.0): """ Calibrate the IQ mixer output power. """ try: self.setup(averaging = 100,reference = 0) params = dict() params["power"] = self._mwg.power() params["amplitude"] = amplitude params["channels"] = self._awgChannels params["mwg"] = self._mwg.name() params["awg"] = self._awg.name() params["fsp"] = self._fsp.name() self.powerCalibrationData().setParameters(params) freqs = self.offsetCalibrationData().column("frequency") Is = self.offsetCalibrationData().column("lowI") Qs = self.offsetCalibrationData().column("lowQ") for i in range(0,len(freqs)): f = freqs[i] amp = max(0,min(4.5,4.5-2.0*max(Is[i],Qs[i]))) self._mwg.setFrequency(f) self._awg.setLow(self._awgChannels[0],Is[i]) self._awg.setLow(self._awgChannels[1],Qs[i]) self._awg.setHigh(self._awgChannels[0],Is[i]+ amp) self._awg.setHigh(self._awgChannels[1],Qs[i]+amp) self._fsp.write("SENSE1:FREQUENCY:CENTER %f GHZ" % f) for channels in [[self._awgChannels[0],self._awgChannels[1],"I"],[self._awgChannels[1],self._awgChannels[0],"Q"]]: name = channels[2] self._awg.setWaveform(channels[0],"IQ_Power_Calibration_passive") self._awg.setWaveform(channels[1],"IQ_Power_Calibration_passive") time.sleep(0.5) trace = self._fsp.getSingleTrace() zero = mean(trace[1]) self._awg.setWaveform(channels[0],"IQ_Power_Calibration_active") time.sleep(0.5) trace = self._fsp.getSingleTrace() level = mean(trace[1]) diff = level - zero #This is the linear output coefficient: coefficient =(pow(10.0,level/10.0)-pow(10.0,zero/10.0))/pow(amp,2.0) self._powerCalibrationData.set(frequency = f) params = {"power"+name : sqrt(exp(log(10.0)*diff/10.0)),"powerDBM"+name : diff, "zero"+name : zero,"level"+name : level,"coeff"+name : coefficient} self._powerCalibrationData.set(**params) self._powerCalibrationData.commit() finally: self.teardown() def calibrateIQOffset(self,frequencyRange = None): """ Calibrate the IQ mixer DC offset. """ if frequencyRange==None: frequencyRange=[self._mwg.frequency()] try: self.setup() params = dict() params["power"] = self._mwg.power() params["channels"] = self._awgChannels params["mwg"] = self._mwg.name() params["awg"] = self._awg.name() params["fsp"] = self._fsp.name() self.offsetCalibrationData().setParameters(params) self._mwg.turnOn() for channel in [1,2,3,4]: self._awg.setWaveform(channel,"IQ_Offset_Calibration") for frequency in frequencyRange: self._mwg.setFrequency(frequency) (voltages,minimum) = self.optimizeIQMixerPowell() minimum = self.measurePower(voltages) print "Optimum value of %g dBm at offset %g V, %g V" % (minimum,voltages[0],voltages[1]) rows = self._offsetCalibrationData.search(frequency = frequency) if rows != []: self._offsetCalibrationData.removeRows(rows) self._offsetCalibrationData.set(frequency = frequency,lowI = voltages[0],lowQ = voltages[1],minimum = minimum) self._offsetCalibrationData.commit() self._offsetCalibrationData.sortBy("frequency") self._offsetCalibrationData.savetxt() except StopThread: pass except: traceback.print_exc() finally: self.teardown() self.updateOffsetCalibrationInterpolation() return self._offsetCalibrationData.filename() def calibrateSidebandMixing(self,frequencyRange = None,sidebandRange = arange(-0.5,0.51,0.1)): """ Calibrate the IQ mixer sideband generation. """ if frequencyRange==None: frequencyRange=[self._mwg.frequency()] try: self.setup() params = dict() params["power"] = self._mwg.power() params["channels"] = self._awgChannels params["mwg"] = self._mwg.name() params["awg"] = self._awg.name() params["fsp"] = self._fsp.name() self.sidebandCalibrationData().setParameters(params) self._mwg.turnOn() channels = self._awgChannels self.loadSidebandWaveforms() for f_c in frequencyRange: #We round the center frequency to an accuracy of 1 MHz f_c = round(f_c,3) self._mwg.setFrequency(f_c) self._awg.setAmplitude(channels[0],4.5) self._awg.setAmplitude(channels[1],4.5) self._awg.setOffset(channels[0],self.iOffset(f_c)) self._awg.setOffset(channels[1],self.qOffset(f_c)) data = Datacube("f_c = %g GHz" % f_c) rowsToDelete = [] try: for i in range(0,len(self._sidebandCalibrationData.column("f_c"))): if abs(self._sidebandCalibrationData.column("f_c")[i]-f_c) < 0.1: rowsToDelete.append(i) except: pass self._sidebandCalibrationData.removeRows(rowsToDelete) self._sidebandCalibrationData.addChild(data, f_c=f_c) self._sidebandCalibrationData.set(f_c = f_c) self._sidebandCalibrationData.commit() for f_sb in sidebandRange: print "f_c = %g GHz, f_sb = %g GHz" % (f_c,f_sb) self._fsp.write("SENSE1:FREQUENCY:CENTER %f GHZ" % (f_c+f_sb)) result = scipy.optimize.fmin_powell(lambda x,*args: self.measureSidebandPower(x,*args),[0,0],args = [f_sb],full_output = 1,xtol = 0.00001,ftol = 1e-4,maxiter = 2) params = result[0] value = result[1] print "f_c = %g GHz, f_sb = %g GHz, c = %g, phi = %g rad" % (f_c,f_sb,params[0],params[1]) self.loadSidebandCalibrationWaveform(f_sb = f_sb,c = params[0],phi = params[1]) for i in [-3,-2,-1,0,1,2,3]: self._fsp.write("SENSE1:FREQUENCY:CENTER %f GHZ" % (f_c+f_sb*i)) if i < 0: suppl = "m" else: suppl = "" data.set(**{"p_sb%s%d" % (suppl,abs(i)) : self.measureAveragePower()}) data.set(f_c = f_c,f_sb = f_sb,c = params[0],phi = params[1]) data.commit() self._sidebandCalibrationData.sortBy("f_c") self._sidebandCalibrationData.savetxt() finally: self.teardown() return self._sidebandCalibrationData.filename() def iOffset(self,f): return self._iOffsetInterpolation(f) def qOffset(self,f): return self._qOffsetInterpolation(f) def setDriveFrequency(self,f): self._mwg.setFrequency(f) self._awg.setOffset(self._awgChannels[0],self.iOffset(f)) self._awg.setOffset(self._awgChannels[1],self.qOffset(f)) def optimizeIQMixerPowell(self): """ Use Powell's biconjugate gradient method to minimize the power leak in the IQ mixer. """ f = self._mwg.frequency() self._mwg.turnOn() self._fsp.write("SENSE1:FREQUENCY:CENTER %f GHZ" % f) result = scipy.optimize.fmin_powell(lambda x: self.measurePower(x),[0.,0.],full_output = 1,xtol = 0.0001,ftol = 1e-2,maxiter =500,maxfun =1000, disp=True, retall=True) return (result[0],result) def measureSidebandPower(self,x,f_sb): c = x[0] if c > 0.5 or c < -0.5: return 100 phi = fmod(x[1],math.pi*2) self.loadSidebandCalibrationWaveform(f_sb = f_sb,c = c,phi = phi) power = self.measureAveragePower() print "Sideband power at f_sb = %g GHz,c = %g, phi = %g : %g dBm" % (f_sb,c,phi,power) return power def measureAveragePower(self): trace = self._fsp.getSingleTrace() if trace == None: return 0 minimum = mean(trace[1]) return minimum def measurePower(self,lows): """ Measure the leaking power of the IQ mixer at a given point. Used by optimizeIQMixerPowell. """ for i in [0,1]: if math.fabs(lows[i]) > 2.0: return 100.0 self._awg.setOffset(self._awgChannels[i],lows[i]) minimum = self.measureAveragePower() print "Measuring power at %g,%g : %g" % (lows[0],lows[1],minimum) linpower = math.pow(10.0,minimum/10.0)/10.0 return minimum
def measureSCurves(qubit,jba,variable = "p1x",data = None,ntimes = 20): """ Measures the s curves of the JBA. Assumes that the qubit is alread preset to a pi-pulse. """ def getVoltageBounds(v0,jba,variable,ntimes): v = v0 jba.setVoltage(v) acqiris.bifurcationMap(ntimes = ntimes) p = acqiris.Psw()[variable] while p > 0.03 and v < v0*2.0: v*=1.05 jba.setVoltage(v) acqiris.bifurcationMap() p = acqiris.Psw()[variable] vmax = v v = v0 jba.setVoltage(v) acqiris.bifurcationMap(ntimes = ntimes) p = acqiris.Psw()[variable] while p < 0.98 and v > v0/2.0: v/=1.05 jba.setVoltage(v) acqiris.bifurcationMap() p = acqiris.Psw()[variable] vmin = v return (vmin*0.9,vmax*1.1) try: v0 = jba.voltage() if data == None: sData = Datacube() else: sData = data sData.setName("S curves - %s" % qubit.name()) sData.setParameters(instrumentManager.parameters()) sOff = Datacube("SOFF") sOn = Datacube("SON") sData.addChild(sOff) sData.addChild(sOn) qubit.turnOffDrive() (vmin,vmax) = getVoltageBounds(v0,jba,variable,ntimes) for v in arange(vmin,vmax,0.005): jba.setVoltage(v) acqiris.bifurcationMap(ntimes = ntimes) sOff.set(**(acqiris.Psw())) sOff.set(v = v) sOff.commit() qubit.turnOnDrive() for v in arange(vmin,vmax,0.005): jba.setVoltage(v) acqiris.bifurcationMap(ntimes = ntimes) sOn.set(**acqiris.Psw()) sOn.set(v = v) sOn.commit() sOn.createColumn("contrast",sOn.column(variable)-sOff.column(variable)) v0 = sOn.column("v")[argmax(sOn.column("contrast"))] maxContrast = max(sOn.column("contrast")) return (sData,maxContrast,v0) finally: jba.setVoltage(v0)
def sCurves(jba,qubit = None,variable = "p1x",data = None,ntimes = 20,s2=False,optimize = "v10",step = 0.01,measureErrors = False,saveData = True,voltageBounds = None,**kwargs): """ Measures the s curves of the JBA. Assumes that the qubit is alread preset to a pi-pulse. """ def getVoltageBounds(v0,jba,variable,ntimes): v = v0 jba.setVoltage(v) acqiris.bifurcationMap(ntimes = ntimes) p = acqiris.Psw()[variable] while p > 0.03 and v < v0*2.0: v*=1.1 jba.setVoltage(v) acqiris.bifurcationMap() p = acqiris.Psw()[variable] vmax = v v = v0 jba.setVoltage(v) acqiris.bifurcationMap(ntimes = ntimes) p = acqiris.Psw()[variable] while p < 0.98 and v > v0/2.0: v/=1.1 jba.setVoltage(v) acqiris.bifurcationMap() p = acqiris.Psw()[variable] vmin = v return (vmin*0.95,vmax*1.1) hasFinished = False try: data.setParameters(instrumentManager.parameters()) v0 = jba.voltage() if data == None: sData = Datacube() else: sData = data if sData.name() == "datacube": if not qubit == None: sData.setName("S curves - %s" % qubit.name()) s0 = Datacube("S0") s1 = Datacube("S1") sData.addChild(s0) sData.addChild(s1) s0.parameters()["defaultPlot"]=[["v",variable]] s1.parameters()["defaultPlot"]=[["v",variable]] s1.parameters()["defaultPlot"].append(["v","contrast10"]) else: sData.setName("S curve - %s" % jba.name()) sData.parameters()["defaultPlot"]=[["v",variable]] error=False if not qubit == None: qubit.turnOnDrive() qubit.loadRabiPulse(length = 0) if voltageBounds == None: (vmin,vmax) = getVoltageBounds(v0,jba,variable,ntimes) else: (vmin,vmax) = voltageBound print vmin,vmax if qubit == None: measureSingleS(voltages = arange(vmin,vmax,step),data = sData,jba = jba,ntimes = ntimes) return else: measureSingleS(voltages = arange(vmin,vmax,step),data = s0,jba = jba,ntimes = ntimes) qubit.loadRabiPulse(phase = math.pi,**kwargs) measureSingleS(voltages = arange(vmin,vmax,step),data = s1,jba = jba,ntimes = ntimes) failed12 = False if s2: try: s2 = Datacube("S2") s2.parameters()["defaultPlot"]=[["v",variable]] sData.addChild(s2) loadPi012Pulse(qubit) measureSingleS(voltages = arange(vmin,vmax,step),data = s2,jba = jba,ntimes = ntimes) s1.createColumn("contrast20",s2.column(variable)-s0.column(variable)) s1.createColumn("contrast21",s2.column(variable)-s1.column(variable)) s1.parameters()["defaultPlot"].extend([["v","contrast20"],["v","contrast21"]]) qubit.parameters()["readout.v20"] = float(s1.column("v")[argmax(s1.column("contrast20"))]) qubit.parameters()["readout.v21"] = float(s1.column("v")[argmax(s1.column("contrast21"))]) qubit.parameters()["readout.contrast20"] = float(s1.column("contrast20")[argmax(s1.column("contrast20"))]) qubit.parameters()["readout.contrast21"] = float(s1.column("contrast21")[argmax(s1.column("contrast21"))]) data.setName(data.name()+" - v20 = %g" % qubit.parameters()["readout.contrast20"]) data.setName(data.name()+" - v21 = %g" % qubit.parameters()["readout.contrast21"]) except: failed12 = True raise else: failed12=True s1.createColumn("contrast10",s1.column(variable)-s0.column(variable)) s1.parameters()["defaultPlot"].append(["v",variable]) qubit.parameters()["readout.v10"] = float(s1.column("v")[argmax(s1.column("contrast10"))]) qubit.parameters()["readout.contrast10"] = float(s1.column("contrast10")[argmax(s1.column("contrast10"))]) data.setName(data.name()+" - v10 = %g" % qubit.parameters()["readout.contrast10"]) if optimize == "v21" or optimize == 'v20': qubit.parameters()["readout.use12"] = True else: qubit.parameters()["readout.use12"] = False if optimize == "v20" and not failed12: imax = argmax(s1.column("contrast20")) v0 = s1.column("v")[imax] elif optimize == "v21" and not failed12: imax = argmax(s1.column("contrast21")) v0 = s1.column("v")[imax] else: imax = argmax(s1.column("contrast10")) v0 = s1.column("v")[imax] hasFinished = True return (sData,v0) finally: jba.setVoltage(v0) if hasFinished: if optimize == 'v20': loadPi012Pulse(qubit) else: qubit.loadRabiPulse(phase = math.pi) if measureErrors: qubit.turnOnDrive() qubit.loadRabiPulse(phase=0) acqiris.bifurcationMap(ntimes = 1000) qubit.parameters()["readout.p00"] = float(1.0-acqiris.Psw()[variable]) if optimize == 'v10': qubit.loadRabiPulse(phase=math.pi) else: loadPi012Pulse(qubit) acqiris.bifurcationMap(ntimes = 1000) qubit.parameters()["readout.p11"] = float(acqiris.Psw()[variable]) if saveData: data.savetxt()
class Instr(Instrument): """ Single frequency JBA - VS 2012/01 Virtual Instrument able to generate and analyse JBA signals. """ def saveState(self,name): d=self._params d["frequency"]=self._frequency d["amplitude"]=self._amplitude d["shape"]=self._shapeParams d["bit"]=self.bit try: d["maxVoltage"]=self.maxVoltage except: pass return d def restoreState(self,state): self.bit=state["bit"] try: self.maxVoltage=state["maxVoltage"] except: pass self._shapeParams=state["shape"] self.shape[10000:10000+self._shapeParams["risingTime"]]=linspace(0,1,self._shapeParams["risingTime"]) self.shape[10000+self._shapeParams["risingTime"]:10000+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]]=1 self.shape[10000+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]:10000+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]]=linspace(1,self._shapeParams["plateau"],self._shapeParams["risingTime"]) self.shape[10000+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]:10000+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]+self._shapeParams["latchLength"]]=self._shapeParams["plateau"] self.setFrequency(state["frequency"]) self.setAmplitude(state["amplitude"]) self.sendWaveform() return None def startJBA(self): self._pulseGenerator.startPulse(name=self.name()) self._pulseAnalyser.startAnalyseFrequency(name=self.name()) def stopJBA(self): self._pulseGenerator.stopPulse(name=self.name()) self._pulseAnalyser.stopAnalyseFrequency(name=self.name()) def initialize(self, name, generator, analyser,magnitudeButton='formAmplitude'): """ Initialize instrument, and define default shape in self.shape """ instrumentManager=Manager() self._pulseGenerator=instrumentManager.getInstrument(generator) self._pulseAnalyser=instrumentManager.getInstrument(analyser) self._params=dict() self._params["pulseGenerator"]=generator self._params["pulseAnalyser"]=analyser self._change=True self._magnitudeButton=magnitudeButton self.data=Datacube() try: self._variableAttenuator=instrumentManager.getInstrument('jba_att') except: pass self._shapeParams=dict() self._shapeParams["risingTime"] = 10 self._shapeParams["plateauLength"] = 200 self._shapeParams["latchLength"] = 1000 self._shapeParams["plateau"] = 0.85 self.generateShape() self.bit=int(self.name()[-1])-1 self._phase=0 def generateShape(self): """ Use the folowing dictionnary to generate the shape: self._shapeParams["risingTime"] self._shapeParams["plateauLength"] self._shapeParams["latchLength"] self._shapeParams["plateau"] """ self.shape=zeros((20000),dtype = numpy.complex128) self.shape[10000:10000+self._shapeParams["risingTime"]]=linspace(0,1,self._shapeParams["risingTime"]) self.shape[10000+self._shapeParams["risingTime"]:10000+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]]=1 self.shape[10000+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]:10000+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]]=linspace(1,self._shapeParams["plateau"],self._shapeParams["risingTime"]) self.shape[10000+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]:10000+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]+self._shapeParams["latchLength"]]=self._shapeParams["plateau"] def parameters(self): """ Return parameters """ return self._params def init(self): """ Clear the JBA (no frequency to analyse) """ self._pulseGenerator.clearPulse() self._pulseAnalyser.clear() self._change=True def setFrequency(self, frequency, amplitude=1., duration=0., gaussian=False, delayFromZero=0,phase=None,shape=None): """ Add a new frequency to analyse """ if shape==None:shape=self.shape if phase==None: phase=self._phase self.phase=phase self._frequency=frequency self._amplitude=amplitude #self._pulseGenerator.clearPulse() self._pulseGenerator.generatePulse(duration=duration, frequency=self._frequency, amplitude=self._amplitude, DelayFromZero=delayFromZero,useCalibration=True, phase=phase,shape=amplitude*shape, name=self.name()) self._fsb=-(self._pulseGenerator._MWSource.frequency()-frequency) self._pulseAnalyser.addFrequency(f=self._fsb, name=self.name(),bit=self.bit) self._change=True def sendAllWaveforms(self,forceSend=False): """ Send all waveforms in pulseGenerator buffer """ self._pulseGenerator.sendPulse(forceSend) def sendWaveform(self,forceSend=False): """ Send waveform pf this JBA """ self._pulseGenerator.sendPulse(forceSend) def setAmplitude(self, amplitude, magnitudeButton=None, phase=None,**args): """ Set amplitude of the JBA pulse with button=magnitudeButton (if define, else self._magnitudeButton) """ if magnitudeButton==None: magnitudeButton=self._magnitudeButton if magnitudeButton=='formAmplitude': if phase==None: phase=self._phase self.phase=phase if abs(amplitude)>0.8: amplitude=amplitude/abs(amplitude)*0.8 self.setFrequency(frequency=self._frequency,shape=amplitude*self.shape,phase=phase) self.sendWaveform() time.sleep(0.5) elif magnitudeButton=='variableAttenuator': if amplitude>5:amplitude=5 if amplitude<0:amplitude=0 self._variableAttenuator.setVoltage(amplitude) time.sleep(0.2) elif magnitudeButton=='microwaveSource': if amplitude>19:amplitude=19 if amplitude<-19:amplitude=-19 self._pulseGenerator._MWSource.setPower(amplitude) time.sleep(0.1) else: print "Error in magnitudeButton value" self.amplitude=amplitude return amplitude def getMeasurement(self): """ Measure IQ signal at all frequencies previously added """ self.co=self._pulseAnalyser.analyse() self._change=False return self.co def calculateBifurcation(self): """ Acquire and calculate if JBA bifurcates or not """ if self._change: self._pulseGenerator.sendPulse() time.sleep(0.5) (av, co, fr)=self._pulseAnalyser.analyse() self._change=False r=self._pulseAnalyser._acqiris.multiplexedBifurcationMapAdd(co,fr) proba=self._pulseAnalyser._acqiris.convertToProbabilities(r) return (av, co, fr, proba) def calibrate(self,bounds=None,level = 0.5,accuracy = 0.025, magnitudeButton=None,onlyOne=False,dataS=None,voltages=None,**kwargs): """ Calibrate Offset and rotation for a single frequency f, and store it """ if magnitudeButton==None:magnitudeButton=self._magnitudeButton self.notify("status","Starting calibration...") self.notify("variance",0) maxVoltage = self._findAmplitude(magnitudeButton=magnitudeButton, frequency=self._frequency, shape=self.shape,bounds=bounds,**kwargs) if not(onlyOne): maxVoltage = self._findAmplitude(magnitudeButton=magnitudeButton, frequency=self._frequency, shape=self.shape,center=maxVoltage,color=1,bounds=bounds) self.notify("status","Voltage calibration complete...") self.voltage=maxVoltage self._adjustRotationAndOffset() self.adjustSwitchingLevel(level) def _findAmplitude(self,frequency=None,shape=None,magnitudeButton=None,center=None,color=0,bounds=None,dataValues=None): """ Only used by function calibrate. Measure and find the amplitude where the JBA is bi-evaluated, go to this point, and store this amplitude """ def fitLorentzian(fs,p1,f0=None): fitfunc = lambda p, x: p[2]+p[0]/(1.0+pow((x-fs[argmax(p1)])/p[1],2.0)) errfunc = lambda p, x, y,ff: pow(numpy.linalg.norm(ff(p,x)-y),2.0) ps = [(max(p1)-min(p1)),0.005,min(p1)] if f0!=None: if max(fs)>f0 and min(fs)<f0:ps[1]=f0 print "Initial guess:",ps import numpy.linalg import scipy import scipy.optimize p1s = scipy.optimize.fmin(errfunc, ps,args=(fs,p1,fitfunc)) rsquare = 1.0-numpy.cov(p1-fitfunc(p1s,fs))/numpy.cov(p1) print p1s return p1s.tolist() if frequency==None:frequency=self._frequency if shape==None:shape=self.shape if magnitudeButton==None:magnitudeButton=self._magnitudeButton self.setFrequency(frequency=frequency,shape=shape) self.sendWaveform() if magnitudeButton=='formAmplitude': """ values = voltage amplitude """ if center==None: values=arange(0,0.8,0.01) else: values=arange(center-0.025,center+0.025,0.001) elif magnitudeButton=='variableAttenuator': """ values = attenuator voltage """ if center==None: values=arange(0,5,0.1) else: values=arange(center-0.2,center+0.2,0.01) elif magnitudeButton=='microwaveSource': """ values = microwave Output power in dB """ self.setFrequency(frequency=frequency,shape=shape) self.sendWaveform() if center==None: values=arange(0,20,0.20) else: values=arange(center-1,center+1,0.05) else: print "Error in the value of magnitudeButton" if bounds!=None: if center==None: values=linspace(bounds[0],bounds[1],bounds[2]) else: print '' self.notify('iqP',0) ps = [] maxcov = 0 maxVoltage = 0 self.variances = zeros((len(values),2)) self.variances[:,0] = values self.data.clear() try: self.setAmplitude(magnitudeButton=magnitudeButton, amplitude=values[0]) time.sleep(0.5) for i in range(0,len(values)): if self.stopped(): self._stopped = False raise Exception("Got stopped!") v = values[i] v=self.setAmplitude(magnitudeButton=magnitudeButton, amplitude=v) trends=self.getComponents() varsum =cov(trends[0])+cov(trends[1]) if not dataValues==None: ch=Datacube() dataValues.addChild(ch) ch.createColumn('I',trends[0]) ch.createColumn('Q',trends[0]) dataValues.set(v=v,varsum=varsum) dataValues.commit() self.data.set(v = v) self.data.set(varsum=varsum) self.data.commit() self.notify("variance",(self.data.column("v"),self.data.column("varsum"),((color,0,0)))) x=1.*i/len(values) self.notify("iqP",(trends[0],trends[1],((x,0,1-x)))) self.notify("status","Variance at %g V: %g" % (v,varsum)) if DEBUG: print "Variance at v = %f : %f" % (v,varsum) self.variances[i,1] = varsum ps.append(varsum) if varsum > maxcov: maxcov = varsum maxVoltage = values[i] self.setAmplitude(magnitudeButton=magnitudeButton,amplitude=maxVoltage) self._vMaxAmplitude=maxVoltage self._sCurveParams=fitLorentzian(self.data['varsum'],self.data['v']) except: raise finally: return maxVoltage def _adjustRotationAndOffset(self,accurate=False): frequency=self._fsb """ Only used by function calibrate, use only where the JBA is bi-valued To find the rotation angle and offsets to discriminate properly the bi-valued values, at a single frequency, and store thoses values """ trends=self.getComponents() if accurate: density,Chi,XY,domain=convertToDensity(trends.transpose()) e,f,p= fit2D2Gaussian(Chi,XY) centers=[[p[2],p[3]],[p[7],p[8]]] sepCenter=(mean([centers[0][0],centers[1][0]]),mean([centers[0][1],centers[1][1]])) sepAngle=-math.atan2(centers[0][0]-centers[1][0],centers[0][1]-centers[1][1]) else: covar = cov(trends[0],trends[1]) print covar la,v = linalg.eig(covar) if la[1] > la[0]: angle = math.atan2(v[0,0],v[0,1]) else: angle = math.atan2(v[1,0],v[0,0]) sepCenter=(mean(trends[0]),mean(trends[1])) print sepCenter print angle sepAngle=angle self._setRotationAndOffset(sepCenter[0],sepCenter[1],sepAngle) p0=self.takePoint() self.setAmplitude(amplitude=self._vMaxAmplitude+0.05) p1=self.takePoint() self.setAmplitude(amplitude=self._vMaxAmplitude) print p0,p1 if p0>p1: self._setRotationAndOffset(sepCenter[0],sepCenter[1],sepAngle+math.pi) def _setRotationAndOffset(self, I0,Q0, angle): print I0,Q0,angle self._pulseAnalyser._acqiris.setFrequencyAnalysisCorrections(-self._fsb,I0,Q0,-angle) self.notify("iqPaxes",(I0,Q0,math.pi/2+angle)) def measureSCurve(self,voltages = None,ntimes = 10,microwaveOff = True,data=None,fspPower=False,corelations=False,**extraInDatacube): self.notify("status","Measuring S curve...") def getVoltageBounds(v0,jba,variable,ntimes): return (0.5,5) v = v0 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = ntimes) p = jba._acqiris.Psw()[variable] while p > 0.03 and v < v0*2.0: v*=1.05 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = ntimes) p = jba._acqiris.Psw()[variable] vmax = v v = v0 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = ntimes) p = jba._acqiris.Psw()[variable] while p < 0.98 and v > v0/2.0: v/=1.05 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = ntimes) p = jba._acqiris.Psw()[variable] vmin = v return (vmin*0.95,vmax*1.2) if fspPower: self._pulseGenerator._mixer._fsp.setFrequency(self._frequency) if data==None: data = Datacube("%s S Curve - f=%f" %(self.name(),self._frequency)) dataManager = DataManager() dataManager.addDatacube(data) else: data.setName("%s S Curve - f=%f" %(self.name(),self._frequency)) if voltages==None: bounds=[self._vMaxAmplitude-2*max(self._vMaxAmplitude/5,abs(self._sCurveParams[0])),self._vMaxAmplitude+2*max(self._vMaxAmplitude/5,abs(self._sCurveParams[0]))] voltages=linspace(bounds[0],bounds[1],200) try: for v in voltages: self.setAmplitude(v) data.set(v = v) d=self.measure(nLoops=ntimes) #d=self.getThisMeasure() data.set(**d[1]) if corelations: data.set(**d[4]) data.set(**extraInDatacube) if fspPower: time.sleep(1) data.set(fspPower=self._pulseGenerator._mixer._fsp.getValueAtMarker()) #self.notify("histograms",d[2][self.bit][0]) #self.notify("iqdata",(d[2][self.bit][0],d[2][self.bit][1])) ##self.notify("iqP",(d[0][:,0],d[0][:,1],((0,0,0)))) data.commit() #self.notify("sCurve",(data.column("v"),data.column("b%i"%self.bit))) data.createColumn("p-0.5",abs(data["b%i"%self.bit]-0.5)) data.sortBy("p-0.5") self._p50fromS=data['v'][0] data.sortBy('v') #data.sortBy("b%i"%self.bit) #p=data["b%i"%self.bit] #v=data['v'] #p=p[p>0] #v=v[p>0] ##p=p[p<1] #v=v[p<1] #self.sInterpolateVP=scipy.interpolate.interp1d(p,v) #data.sortBy('v') except: raise finally: data.savetxt() self.notify("status","S curve complete.") self.setAmplitude(self._vMaxAmplitude) return data def measureAll(self): return self._pulseAnalyser.measureAll() def adjustSwitchingLevel(self,level = 0.2,accuracy = 0.05,nLoops=40,function='dichotmie'):#,verbose = False,minSensitivity = 15.0,microwaveOff = True,nmax = 100): print 'adjusting %f, with %f precision' %(level,accuracy) def levelAt(amplitude,nLoops=10,**args): v=self.setAmplitude(amplitude,**args) p=self.takePoint(nLoops=nLoops) self.notify("goto",["singlePoint",[v,p]]) return (v,p) if function=='fit': fitfuncS = lambda p, x: exp(1-exp((x-p[0])/p[1]))/exp(1) def fitS(x,y,x0,dx): errfunc = lambda p, x, y,ff: pow(numpy.linalg.norm(ff(p,x)-y),2.0) ps=[x0,dx] p1s = scipy.optimize.fmin(errfunc, ps,args=(x,y,fitfuncS),retall=False,disp=False) rsquare = 1.0-numpy.cov(y-fitfuncS(p1s,x))/numpy.cov(y) print "fit parameters" print p1s return p1s.tolist() def addToArray(x): (nx,ny)=levelAt(x) print nx,ny self.x.append(nx) self.y.append(ny) def defineFunction(): self.notify('goto',['clear','']) self.x=[] self.y=[] [vmin,vmax]=[0.8*self._vMaxAmplitude,1.2*self._vMaxAmplitude]#[self._vMaxAmplitude-2*max(self._vMaxAmplitude/5,abs(self._sCurveParams[0])),self._vMaxAmplitude+2*max(self._vMaxAmplitude/5,abs(self._sCurveParams[0]))] addToArray(vmin) addToArray(vmax) print self.x, self.y for i in [1,2,3,4,5]: self.params=fitS(self.x,self.y,self._vMaxAmplitude,0.2) print self.params addToArray(self.params[0]) addToArray(self.params[0]-self.params[1]*3) addToArray(self.params[0]-self.params[1]*2) self.params=fitS(self.x,self.y,self._vMaxAmplitude,0.2) # Define the invert function from center-2linewidth to center+2linewidth #x = linspace(params[0]-5*params[1],params[0]+5*params[1],100) #f = lambda x: fitfuncS(params,x) #y = map(f,x) self.sfunction=lambda x:self.params[1]*log(1-log((x)*exp(1)))+self.params[0] self.notify('goto',['fit',self.sfunction]) if not(hasattr(self,'sfunction')): defineFunction() (v,l)=levelAt(self.sfunction(level),nLoops=nLoops) if abs(l-level)>accuracy: defineFunction() (v,l)=levelAt(self.sfunction(level),nLoops=nLoops) print "level at %f : %f"%(v,l) if function=="dichotmie": self.notify('goto',['clear','']) bounds=[0.8*self._vMaxAmplitude,1.2*self._vMaxAmplitude] p1=levelAt(bounds[0])[1] p2=levelAt(bounds[1])[1] if p1>p2: slope=-1 elif p1<p2: slope=1 else: raise Exception("BAD RANGE") values=[p1,p2] l=-1 n=0 error=False while abs(l-level)>accuracy and not error: newPoint=(level-values[0])*(bounds[1]-bounds[0])/(values[1]-values[0])+bounds[0] #newPoint=mean(bounds) o,l=levelAt(newPoint) if l<level: bounds[(1-slope)/2]=newPoint values[(1-slope)/2]=l else: bounds[(1+slope)/2]=newPoint values[(1+slope)/2]=l n+=1 if n>10:error=True self.notify('status',"level at %f : %f (found in %i tries)"%(newPoint,l,n) ) if error: return False else: return True #self.setAmplitude(self.sInterpolateVP(level)) #self.setAmplitude(self._vMaxAmplitude) #return True #def levelAt(amplitude,nLoops=1,**args): # self.setAmplitude(amplitude,**args) # return self.takePoint(nLoops=nLoops) # #[vmin,vmax]=[self._vMaxAmplitude-2*max(self._vMaxAmplitude/5,abs(self._sCurveParams[0])),self._vMaxAmplitude+2*max(self._vMaxAmplitude/5,abs(self._sCurveParams[0]))] #options=dict() #options['maxiter']=15 #result=scipy.optimize.minimize_scalar(levelAt,bracket=(vmin,self._vMaxAmplitude,vmax),bounds=(vmin,vmax),method='bounded',tol=accuracy,options=options) #return result #errfunc = lambda p, x, f:abs(f(x)-p) #v = scipy.optimize.fmin(errfunc, self._vMaxAmplitude,args=(p, self.sInterpolate),xtol=1e-5,ftol=1e-3) #print v #self.setAmplitude(v) def getIQp(self): co=self.getMeasurement() (clicks,IQData)=self._pulseAnalyser._acqiris.multiplexedBifurcationMapAdd(co,self._fsb) r = self._pulseAnalyser._acqiris.convertToProbabilities(clicks) return (r,IQData) def measure(self,nLoops=1,fast=False): """ acquire, measure and calculate probabilities """ toReturn = self._pulseAnalyser.analyse(nLoops,fast=fast) return toReturn def getThisMeasure(self,nLoops=10): """ Return proba, non-corrected IQ, corrected IQ """ r=self.measure(nLoops=nLoops) return (r[1]['b%i'%self.bit],r[0][self.bit],r[2][self.bit]) def takePoint(self,nLoops=1): return self.measure(nLoops=nLoops)[1]['b%i'%self.bit] def getComponents(self): return self.measure()[0][self.bit] def caracteriseJBA(self, shape, frequencies,test=False): for f in frequencies: self._pulseGenerator._MWSource.setFrequency(f) self._pulseGenerator._IQMixer.calibrate(offsetOnly=True) self.frequency(frequency=f,shape=shape) self._pulseGenerator.sendPulse() def caracteriseIQvsFvsP(self,frequencies,voltages,data=None): if data==None: data=Datacube("JBA mapping") dataManager.addDatacube(data) try: previousShape=self.shape self.shape=zeros((20000),dtype = numpy.complex128) self.shape[10000:10010]=linspace(0,1,10) self.shape[10010:12100]=1 self.shape[12100:12110]=linspace(1,0,10) # return self.shape import scipy pvsv=Datacube("power") data.addChild(pvsv) for v in voltages: self.setAmplitude(amplitude=v) p=self.measureJBAPower(f='autodetect') pvsv.set(v=v,bluePower=p) pvsv.commit() pv=scipy.interpolate.interp1d(pvsv.column("v"),pvsv.column("bluePower")) data.savetxt() for f in frequencies: child=Datacube("f=%f"%f) data.addChild(child) self.setFrequency(f) for v in voltages: self.setAmplitude(amplitude=v) time.sleep(0.5) co=self.getThisMeasure()[1] var=cov(co[0])+cov(co[1]) if var>0.01: cod=Datacube("components at p=%f" %pv(v)) cod.createColumn('I',co[0]) cod.createColumn('Q',co[1]) cod.createColumn('bluePower',[pv(v)]*len(co[0])) child.addChild(cod) else: ####### ECRIRE QUELQUE CHOSE ICI [I,Q]=[mean(co[0]),mean(co[1])] child.set(f=f,v=v,I=I,Q=Q,sigma=var,bluePower=pv(v)) child.set(M=sqrt(I**2+Q**2)) child.set(phi=math.atan2(I,Q)) child.commit() data.set(f=f,v=v,I=I,Q=Q,sigma=var,bluePower=pv(v)) data.set(M=sqrt(I**2+Q**2)) data.set(phi=math.atan2(I,Q)) data.commit() data.savetxt() except: raise finally: data.savetxt() self.shape=previousShape def measureJBAPower(self,f=None): if f==None: f=frequency=self._f01 else: f=self._pulseGenerator._MWSource.frequency() self._pulseGenerator.clearPulse() self._pulseGenerator.pulses[self.name()][1]=False self._pulseGenerator.generatePulse(duration=register['repetitionPeriod'],frequency=f,DelayFromZero=0.,useCalibration=False,name='calibration') self._pulseGenerator.pulses['calibration'][1]=True self._pulseGenerator.sendPulse() fsp=self._pulseGenerator._mixer._fsp fsp.write("SENSE1:FREQUENCY:CENTER %f GHZ" % f) fsp.write("SENSE1:FREQUENCY:SPAN 0 MHz") fsp.write("SWE:TIME 1 ms") rbw = 10000 fsp.write("SENSE1:BAND:RES %f Hz" % rbw) fsp.write("SENSE1:BAND:VIDEO AUTO") fsp.write("TRIG:SOURCE EXT") fsp.write("TRIG:HOLDOFF 0.0 s") fsp.write("TRIG:LEVEL 0.5 V") fsp.write("TRIG:SLOP POS") averaging=0 fsp.write("SENSE1:AVERAGE:COUNT %d" % averaging) fsp.write("SENSE1:AVERAGE:STAT1 ON") time.sleep(0.5) m=mean(fsp.getSingleTrace()[1]) print self._pulseGenerator.pulses self._pulseGenerator.pulses['calibration'][1]=False self._pulseGenerator.pulses[self.name()][1]=True self._pulseGenerator.sendPulse() print self._pulseGenerator.pulses return m
class Instr(Instrument): """ Single frequency JBA - VS 2012/01 Virtual Instrument able to generate and analyse JBA signals. """ def saveState(self,name): d=self._params d["frequency"]=self._frequency d["amplitude"]=self._amplitude d["shape"]=self._shapeParams d["bit"]=self.bit try: d["maxVoltage"]=self.maxVoltage except: pass return d def restoreState(self,state): self.bit=state["bit"] try: self.maxVoltage=state["maxVoltage"] except: raise self._shapeParams=state["shape"] self.shape[10000+self._shapeParams["offsetDelay"]:10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]]=linspace(0,1,self._shapeParams["risingTime"]) self.shape[10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]:10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]]=1 self.shape[10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]:10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]]=linspace(1,self._shapeParams["plateau"],self._shapeParams["risingTime"]) self.shape[10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]:10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]+self._shapeParams["latchLength"]]=self._shapeParams["plateau"] self.setFrequency(state["frequency"]) self.setAmplitude(state["amplitude"]) self.sendWaveform() return None def startJBA(self): self._started=True self._pulseGenerator.startPulse(name=self.name()) self._pulseAnalyser.startAnalyseFrequency(name=self.name()) def stopJBA(self): self._started=False self._pulseGenerator.stopPulse(name=self.name()) self._pulseAnalyser.stopAnalyseFrequency(name=self.name()) def initialize(self, name, generator, analyser,magnitudeButton='formAmplitude'): """ Initialize instrument, and define default shape in self.shape """ print "loading JBA" instrumentManager=Manager() self._pulseGenerator=instrumentManager.getInstrument(generator) self._pulseAnalyser=instrumentManager.getInstrument(analyser) self._params=dict() self._params["pulseGenerator"]=generator self._params["pulseAnalyser"]=analyser self._change=True self._started=True self._magnitudeButton=magnitudeButton self.data=Datacube() try: self._variableAttenuator=instrumentManager.getInstrument('jba_att') except: raise self._shapeParams=dict() print "shape params reinisitlised" self._shapeParams["risingTime"] = 10 self._shapeParams["plateauLength"] = 200 self._shapeParams["latchLength"] = 1000 self._shapeParams["plateau"] = 0.85 self._shapeParams["offsetDelay"] = 0 self.generateShape() self.bit=int(self.name()[-1])-1 self._phase=0 self._nLoopsMax=70 def generateShape(self): """ Use the folowing dictionnary to generate the shape: self._shapeParams["risingTime"] self._shapeParams["plateauLength"] self._shapeParams["latchLength"] self._shapeParams["plateau"] """ self.shape=zeros((20000),dtype = numpy.complex128) self.shape[10000+self._shapeParams["offsetDelay"]:10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]]=linspace(0,1,self._shapeParams["risingTime"]) self.shape[10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]:10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]]=1 self.shape[10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]:10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]]=linspace(1,self._shapeParams["plateau"],self._shapeParams["risingTime"]) self.shape[10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]:10000+self._shapeParams["offsetDelay"]+self._shapeParams["risingTime"]+self._shapeParams["plateauLength"]+self._shapeParams["risingTime"]+self._shapeParams["latchLength"]]=self._shapeParams["plateau"] def parameters(self): """ Return parameters """ return self._params def init(self): """ Clear the JBA (no frequency to analyse) """ self._pulseGenerator.clearPulse() self._pulseAnalyser.clear() self._change=True def setCarrierFrequency(self, f): self._pulseGenerator.setCarrierFrequency(f) def setFrequency(self, frequency, amplitude=1., duration=0., gaussian=False, delayFromZero=0,phase=None,shape=None, generatorToo=False): """ Add a new frequency to analyse """ if generatorToo: self.setCarrierFrequency(frequency) if shape==None:shape=self.shape if phase==None: phase=self._phase self.phase=phase self._frequency=frequency self._amplitude=amplitude #self._pulseGenerator.clearPulse() self._pulseGenerator.generatePulse(duration=duration, frequency=self._frequency, amplitude=self._amplitude, DelayFromZero=delayFromZero,useCalibration=True, phase=phase,shape=amplitude*shape, name=self.name()) self._fsb=-(self._pulseGenerator._MWSource.frequency()-frequency) self._pulseAnalyser.addFrequency(f=self._fsb, name=self.name(),bit=self.bit) self._change=True def sendAllWaveforms(self,forceSend=False): """ Send all waveforms in pulseGenerator buffer """ self._pulseGenerator.sendPulse(forceSend) def sendWaveform(self,forceSend=False): """ Send waveform pf this JBA """ self._pulseGenerator.sendPulse(forceSend) def setAmplitude(self, amplitude, magnitudeButton=None, phase=None,**args): """ Set amplitude of the JBA pulse with button=magnitudeButton (if define, else self._magnitudeButton) """ if magnitudeButton==None: magnitudeButton=self._magnitudeButton if magnitudeButton=='formAmplitude': if phase==None: phase=self._phase self.phase=phase if abs(amplitude)>1.2: amplitude=amplitude/abs(amplitude)*1.2 self.setFrequency(frequency=self._frequency,shape=amplitude*self.shape,phase=phase) self.sendWaveform() time.sleep(1.) elif magnitudeButton=='variableAttenuator': if amplitude>5:amplitude=5 if amplitude<0:amplitude=0 self._variableAttenuator.setVoltage(amplitude) time.sleep(0.2) elif magnitudeButton=='microwaveSource': if amplitude>19:amplitude=19 if amplitude<-19:amplitude=-19 self._pulseGenerator._MWSource.setPower(amplitude) time.sleep(0.1) else: print "Error in magnitudeButton value" self.amplitude=amplitude return amplitude def getMeasurement(self): """ Measure IQ signal at all frequencies previously added """ self.co=self._pulseAnalyser.analyse() self._change=False return self.co def calculateBifurcation(self): """ Acquire and calculate if JBA bifurcates or not """ if self._change: self._pulseGenerator.sendPulse() time.sleep(0.5) (av, co, fr)=self._pulseAnalyser.analyse() self._change=False r=self._pulseAnalyser._acqiris.multiplexedBifurcationMapAdd(co,fr) proba=self._pulseAnalyser._acqiris.convertToProbabilities(r) return (av, co, fr, proba) def calibrate(self,bounds=None,level = 0.5,accuracy = 0.025, magnitudeButton=None,onlyOne=False,dataS=None,voltages=None,**kwargs): """ Calibrate Offset and rotation for a single frequency f, and store it """ if magnitudeButton==None:magnitudeButton=self._magnitudeButton self.notify("status","Starting calibration...") self.notify("variance",0) maxVoltage,bounds = self._findAmplitude(magnitudeButton=magnitudeButton, frequency=self._frequency, shape=self.shape,bounds=bounds,fitModel=False,**kwargs) if not(onlyOne): maxVoltage,b = self._findAmplitude(magnitudeButton=magnitudeButton, frequency=self._frequency, shape=self.shape,color=1,bounds=bounds,fitModel=True) self.notify("status","Voltage calibration complete...") self.voltage=self.center self.setAmplitude(self.center) self.adjustSwitchingLevel(level) def _findAmplitude(self,frequency=None,shape=None,magnitudeButton=None,center=None,color=0,bounds=None,dataValues=None,fitModel=True,nLoops=10): """ Only used by function calibrate. Measure and find the amplitude where the JBA is bi-evaluated, go to this point, and store this amplitude """ def fitLorentzian(fs,p1,f0=None): fitfunc = lambda p, x: p[2]+p[0]/(1.0+pow((x-fs[argmax(p1)])/p[1],2.0)) errfunc = lambda p, x, y,ff: pow(numpy.linalg.norm(ff(p,x)-y),2.0) ps = [(max(p1)-min(p1)),0.005,min(p1)] if f0!=None: if max(fs)>f0 and min(fs)<f0:ps[1]=f0 print "Initial guess:",ps import numpy.linalg import scipy import scipy.optimize p1s = scipy.optimize.fmin(errfunc, ps,args=(fs,p1,fitfunc)) rsquare = 1.0-numpy.cov(p1-fitfunc(p1s,fs))/numpy.cov(p1) print p1s return p1s.tolist() if frequency==None:frequency=self._frequency if shape==None:shape=self.shape if magnitudeButton==None:magnitudeButton=self._magnitudeButton self.setFrequency(frequency=frequency,shape=shape) self.sendWaveform() if magnitudeButton=='formAmplitude': """ values = voltage amplitude """ if center==None: values=arange(0,0.8,0.01) else: if bounds!=None: values=linspace(center-0.025,center+0.025,bounds[2]/2) else: values=arange(center-0.025,center+0.025,0.001) elif magnitudeButton=='variableAttenuator': """ values = attenuator voltage """ if center==None: values=arange(0,5,0.1) else: values=arange(center-0.2,center+0.2,0.01) elif magnitudeButton=='microwaveSource': """ values = microwave Output power in dB """ self.setFrequency(frequency=frequency,shape=shape) self.sendWaveform() if center==None: values=arange(0,20,0.20) else: values=arange(center-1,center+1,0.05) else: print "Error in the value of magnitudeButton" if bounds!=None: if center==None: values=linspace(bounds[0],bounds[1],bounds[2]) else: print '' if fitModel:separatrixList=[] self.notify('iqP',0) ps = [] maxcov = 0 maxVoltage = 0 self.variances = zeros((len(values),2)) self.variances[:,0] = values self.data.clear() try: self.setAmplitude(magnitudeButton=magnitudeButton, amplitude=values[0]) time.sleep(0.5) for i in range(0,len(values)): if self.stopped(): self._stopped = False raise Exception("Got stopped!") v = values[i] v=self.setAmplitude(magnitudeButton=magnitudeButton, amplitude=v) trends=self.getComponents(nLoops=nLoops) varsum =cov(trends[0])+cov(trends[1]) x=1.*i/len(values) self.notify("iqP",(trends[0],trends[1],((x,0,1-x)))) if fitModel: try: fitResults=self.multiGaussianClusters(trends.transpose()) except: raise sep=self.separatrixBimodal(fitResults) separatrixList.append(sep) self.separatrixList=separatrixList s=[sep[0]] sepCenters=array([[p[0],p[1]] for p in s]).transpose() c=sep[3] centers=[[c[0][0],c[1][0]],[c[0][1],c[1][1]]] self.notify("centersIQ",[sepCenters, centers]) if not dataValues==None: ch=Datacube() dataValues.addChild(ch) ch.createColumn('I',trends[0]) ch.createColumn('Q',trends[1]) dataValues.set(v=v,varsum=varsum) dataValues.commit() self.data.set(v = v) self.data.set(varsum=varsum) self.data.commit() self.notify("variance",(self.data.column("v"),self.data.column("varsum"),((color,0,0)))) self.notify("status","Variance at %g V: %g" % (v,varsum)) if DEBUG: print "Variance at v = %f : %f" % (v,varsum) self.variances[i,1] = varsum ps.append(varsum) if varsum > maxcov: maxcov = varsum maxVoltage = values[i] self.setAmplitude(magnitudeButton=magnitudeButton,amplitude=maxVoltage) self._vMaxAmplitude=maxVoltage except: raise finally: # calculate separatrix print "fitModel: ",fitModel if fitModel: self.separatrixList=separatrixList sepCenters=[s[0] for s in self.separatrixList] centers=[s[3] for s in self.separatrixList] self.notify("centersIQ",[sepCenters, centers]) print "separatrixList: ",separatrixList coefs,st=self.separatrixMulti(separatrixList,0.1,0.9) I0=separatrixList[len(separatrixList)/2][0][0] Q0=coefs[0]*I0+coefs[1] angle=arctan(coefs[0]) self._setRotationAndOffset(I0,Q0,angle) self.setAmplitude(amplitude=self.center-abs(self.width)/2) p0=self.takePoint(nLoops=10) self.setAmplitude(amplitude=self.center+abs(self.width)/2) p1=self.takePoint(nLoops=010) print "p0 = ",p0, " p1= ", p1 if p0>p1: self._setRotationAndOffset(I0,Q0,angle+math.pi) bounds=[] else: #calculate bounds variances=self.data['varsum'].tolist() voltages=self.data['v'].tolist() yTarget=max(variances)*0.4+min(variances)*0.6 print yTarget vmax=firstXCrossTargetYFromAnEnd(variances,voltages,yTarget=yTarget,direction='rightToLeft')[4] vmin=firstXCrossTargetYFromAnEnd(variances,voltages,yTarget=yTarget,direction='leftToRight')[4] vmin=vmin#-(vmax-vmin)*0.5 vmax=vmax#+(vmax-vmin)*0.5 if vmax==None or vmin==None: center=extremum(x=voltages, y=variances, minOrMax="max") vmin,vmax=[center*0.8,center*1.2] self.center=(vmin+vmax)/2 self.width=abs(vmax-vmin) bounds=[vmin,vmax,15.] print "bounds = " + str(bounds) return maxVoltage,bounds def _adjustRotationAndOffset(self,accurate=False): frequency=self._fsb """ Only used by function calibrate, use only where the JBA is bi-valued To find the rotation angle and offsets to discriminate properly the bi-valued values, at a single frequency, and store thoses values """ oldAmplitude=self.amplitude trends=self.getComponents() #if accurate: # density,Chi,XY,domain=convertToDensity(trends.transpose()) # e,f,p= fit2D2Gaussian(Chi,XY) # centers=[[p[2],p[3]],[p[7],p[8]]] # sepCenter=(mean([centers[0][0],centers[1][0]]),mean([centers[0][1],centers[1][1]])) # sepAngle=-math.atan2(centers[0][0]-centers[1][0],centers[0][1]-centers[1][1]) #else: # covar = cov(trends[0],trends[1]) # print covar # la,v = linalg.eig(covar) # if la[1] > la[0]: # angle = math.atan2(v[0,0],v[0,1]) # else: # angle = math.atan2(v[1,0],v[0,0]) # sepCenter=(mean(trends[0]),mean(trends[1])) # print sepCenter # print angle # sepAngle=angle print "means = " + str(mean(trends[0])) + " " + str(mean(trends[1])) fitResults=self.multiGaussianClusters(trends.transpose()) sep=self.separatrixBimodal(fitResults) sepCenter=sep[0] sepAngle=sep[1] self._setRotationAndOffset(sepCenter[0],sepCenter[1],sepAngle) self.setAmplitude(amplitude=self.center-abs(self.width)/2) p0=self.takePoint(nLoops=10) self.setAmplitude(amplitude=self.center+abs(self.width)/2) p1=self.takePoint(nLoops=010) if __DEBUG__:print "center, width=" if __DEBUG__:print self.center, self.width if __DEBUG__:print "P0, p1=" if __DEBUG__:print p0,p1 if p0>p1: print "reversing separatrix" self._setRotationAndOffset(sepCenter[0],sepCenter[1],sepAngle-math.pi) self.setAmplitude(oldAmplitude) def _setRotationAndOffset(self, I0,Q0, angle): self._demodulatorCorrections={"I0":I0, "Q0":Q0, "angle":angle} if __DEBUG__:print I0,Q0,angle self._pulseAnalyser._acqiris.setFrequencyAnalysisCorrections(-self._fsb,I0,Q0,angle) self.notify("iqPaxes",(I0,Q0,angle)) def measureSCurve(self,voltages = None,nLoops = 5,microwaveOff = True,data=None,fspPower=False,corelations=False,**extraInDatacube): self.notify("status","Measuring S curve...") def getVoltageBounds(v0,jba,variable,ntimes): return (0.5,5) v = v0 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = nLoops) p = jba._acqiris.Psw()[variable] while p > 0.03 and v < v0*2.0: v*=1.05 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = nLoops) p = jba._acqiris.Psw()[variable] vmax = v v = v0 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = nLoops) p = jba._acqiris.Psw()[variable] while p < 0.98 and v > v0/2.0: v/=1.05 jba.setVoltage(v) jba._acqiris.bifurcationMap(ntimes = nLoops) p = jba._acqiris.Psw()[variable] vmin = v return (vmin*0.95,vmax*1.2) if fspPower: self._pulseGenerator._mixer._fsp.setFrequency(self._frequency) if data==None: data = Datacube("%s S Curve - f=%f" %(self.name(),self._frequency)) dataManager = DataManager() dataManager.addDatacube(data) else: data.setName("%s S Curve - f=%f" %(self.name(),self._frequency)) if voltages==None: bounds=[self.center-self.width*1,self.center+self.width*1] # voltages=linspace(bounds[0],bounds[1],200) voltages=SmartLoop(bounds[0],(bounds[1]-bounds[0])/50, bounds[1], name="Scurve voltages") print "entering in loop" try: for v in voltages: print "voltage :",v self.setAmplitude(v) data.set(v = v) print "measuring" d=self.measure(nLoops=nLoops) print "got point" #d=self.getThisMeasure() #data.set(**d[1]) data.set(**d[-1]) print "in datacube" #data.set(**extraInDatacube) print "extra in datacube" if fspPower: time.sleep(1) data.set(fspPower=self._pulseGenerator._mixer._fsp.getValueAtMarker()) #self.notify("histograms",d[2][self.bit][0]) #self.notify("iqdata",(d[2][self.bit][0],d[2][self.bit][1])) ##self.notify("iqP",(d[0][:,0],d[0][:,1],((0,0,0)))) print "commiting" data.commit() print "commited" #self.notify("sCurve",(data.column("v"),data.column("b%i"%self.bit))) print "first loop over" #data.sortBy('v') #data.sortBy("b%i"%self.bit) #p=data["b%i"%self.bit] #v=data['v'] #p=p[p>0] #v=v[p>0] ##p=p[p<1] #v=v[p<1] #self.sInterpolateVP=scipy.interpolate.interp1d(p,v) #data.sortBy('v') print "first loop over" except: raise finally: data.savetxt() self.notify("status","S curve complete.") self.setAmplitude(self._vMaxAmplitude) return data def measureAll(self): return self._pulseAnalyser.measureAll() def adjustSwitchingLevel(self,level = 0.2,accuracy = 0.05,nLoops=40,function='dichotmie'):#,verbose = False,minSensitivity = 15.0,microwaveOff = True,nmax = 100): print 'adjusting %f, with %f precision' %(level,accuracy) def levelAt(amplitude,nLoops=10,**args): v=self.setAmplitude(amplitude,**args) p=self.takePoint(nLoops=nLoops) self.notify("goto",["singlePoint",[v,p]]) return (v,p) if function=='fit': fitfuncS = lambda p, x: exp(1-exp((x-p[0])/p[1]))/exp(1) def fitS(x,y,x0,dx): errfunc = lambda p, x, y,ff: pow(numpy.linalg.norm(ff(p,x)-y),2.0) ps=[x0,dx] p1s = scipy.optimize.fmin(errfunc, ps,args=(x,y,fitfuncS),retall=False,disp=False) rsquare = 1.0-numpy.cov(y-fitfuncS(p1s,x))/numpy.cov(y) print "fit parameters" print p1s return p1s.tolist() def addToArray(x): (nx,ny)=levelAt(x) print nx,ny self.x.append(nx) self.y.append(ny) def defineFunction(): self.notify('goto',['clear','']) self.x=[] self.y=[] [vmin,vmax]=[self.center-self.width/4, self.center+self.width/4]#[self._vMaxAmplitude-2*max(self._vMaxAmplitude/5,abs(self._sCurveParams[0])),self._vMaxAmplitude+2*max(self._vMaxAmplitude/5,abs(self._sCurveParams[0]))] addToArray(vmin) addToArray(vmax) print self.x, self.y for i in [1,2,3,4,5]: self.params=fitS(self.x,self.y,self._vMaxAmplitude,0.2) print self.params addToArray(self.params[0]) addToArray(self.params[0]-self.params[1]/4) addToArray(self.params[0]-self.params[1]/4) self.params=fitS(self.x,self.y,self._vMaxAmplitude,0.2) # Define the invert function from center-2linewidth to center+2linewidth #x = linspace(params[0]-5*params[1],params[0]+5*params[1],100) #f = lambda x: fitfuncS(params,x) #y = map(f,x) self.sfunction=lambda x:self.params[1]*log(1-log((x)*exp(1)))+self.params[0] self.notify('goto',['fit',self.sfunction]) if not(hasattr(self,'sfunction')): defineFunction() (v,l)=levelAt(self.sfunction(level),nLoops=nLoops) if abs(l-level)>accuracy: defineFunction() (v,l)=levelAt(self.sfunction(level),nLoops=nLoops) print "level at %f : %f"%(v,l) if function=="dichotmie": self.notify('goto',['clear','']) bounds=[self.center-self.width/3,self.center+self.width/3] p1=levelAt(bounds[0])[1] p2=levelAt(bounds[1])[1] if p1>p2: slope=-1 elif p1<p2: slope=1 else: raise Exception("BAD RANGE") values=[p1,p2] l=-1 n=0 error=False while abs(l-level)>accuracy and not error: newPoint=(level-values[0])*(bounds[1]-bounds[0])/(values[1]-values[0])+bounds[0] #newPoint=mean(bounds) o,l=levelAt(newPoint) if l<level: bounds[(1-slope)/2]=newPoint values[(1-slope)/2]=l else: bounds[(1+slope)/2]=newPoint values[(1+slope)/2]=l n+=1 if n>10:error=True self.notify('status',"level at %f : %f (found in %i tries)"%(newPoint,l,n) ) if error: return False else: return True #self.setAmplitude(self.sInterpolateVP(level)) #self.setAmplitude(self._vMaxAmplitude) #return True #def levelAt(amplitude,nLoops=1,**args): # self.setAmplitude(amplitude,**args) # return self.takePoint(nLoops=nLoops) # #[vmin,vmax]=[self._vMaxAmplitude-2*max(self._vMaxAmplitude/5,abs(self._sCurveParams[0])),self._vMaxAmplitude+2*max(self._vMaxAmplitude/5,abs(self._sCurveParams[0]))] #options=dict() #options['maxiter']=15 #result=scipy.optimize.minimize_scalar(levelAt,bracket=(vmin,self._vMaxAmplitude,vmax),bounds=(vmin,vmax),method='bounded',tol=accuracy,options=options) #return result #errfunc = lambda p, x, f:abs(f(x)-p) #v = scipy.optimize.fmin(errfunc, self._vMaxAmplitude,args=(p, self.sInterpolate),xtol=1e-5,ftol=1e-3) #print v #self.setAmplitude(v) def getIQp(self): co=self.getMeasurement() (clicks,IQData)=self._pulseAnalyser._acqiris.multiplexedBifurcationMapAdd(co,self._fsb) r = self._pulseAnalyser._acqiris.convertToProbabilities(clicks) return (r,IQData) def measure(self,nLoops=None,fast=False): """ acquire, measure and calculate probabilities """ try: if nLoops==None: nLoops=self.nLoops() if nLoops>self._nLoopsMax: firstNLoops=nLoops-int(nLoops/self._nLoopsMax)*self._nLoopsMax try: r=self._pulseAnalyser.analyse(firstNLoops,fast=fast)#[-1] except: print "error in pre-loop -> catched" if __DEBUG__: print r[0],r[-1] toReturn=dict() for key in r[-1].keys(): toReturn[key]=firstNLoops*r[-1][key] # for key in r[0].keys(): # toReturn[key]=firstNLoops*r[0][key] # r[key]*=firstNLoops extraLoop= int(nLoops/self._nLoopsMax) if __DEBUG__: print toReturn for i in range(0,extraLoop): for j in [0,1,2]: try: print "index:",i , " over ",extraLoop r=self._pulseAnalyser.analyse(self._nLoopsMax,fast=fast) if __DEBUG__: print r[0],r[-1] for key in r[-1].keys(): toReturn[key]+=self._nLoopsMax*r[-1][key] #for key in r[0].keys(): # toReturn[key]+=self._nLoopsMax*r[0][key] if __DEBUG__: print toReturn print "OK !" except Exception as a : print "error in extraLoop-> catched" print a pass else: break if __DEBUG__: print "dividing by ",nLoops for key in toReturn.keys(): toReturn[key]/=nLoops toReturn=[toReturn] else: toReturn = self._pulseAnalyser.analyse(nLoops,fast=fast) return toReturn except Exception as a : print "error in extraLoop->not catched" print a def nLoops(self): try: return self._nLoops except: return 20 def getThisMeasure(self,nLoops=10): """ Return proba, non-corrected IQ, corrected IQ """ r=self.measure(nLoops=nLoops) return (r[1]['b%i'%self.bit],r[0][self.bit],r[2][self.bit]) def takePoint(self,nLoops=1): return self.measure(nLoops=nLoops)[1]['b%i'%self.bit] def getComponents(self,nLoops=10): return self.measure(nLoops=nLoops)[0][self.bit] def caracteriseJBA(self, shape, frequencies,test=False): for f in frequencies: self._pulseGenerator._MWSource.setFrequency(f) self._pulseGenerator._IQMixer.calibrate(offsetOnly=True) self.frequency(frequency=f,shape=shape) self._pulseGenerator.sendPulse() def caracteriseIQvsFvsP(self,frequencies,voltages,data=None): if data==None: data=Datacube("JBA mapping") dataManager.addDatacube(data) try: previousShape=self.shape self.shape=zeros((20000),dtype = numpy.complex128) self.shape[10000:10010]=linspace(0,1,10) self.shape[10010:12100]=1 self.shape[12100:12110]=linspace(1,0,10) # return self.shape import scipy pvsv=Datacube("power") data.addChild(pvsv) for v in voltages: self.setAmplitude(amplitude=v) p=self.measureJBAPower(f='autodetect') pvsv.set(v=v,bluePower=p) pvsv.commit() pv=scipy.interpolate.interp1d(pvsv.column("v"),pvsv.column("bluePower")) data.savetxt() for f in frequencies: child=Datacube("f=%f"%f) data.addChild(child) self.setFrequency(f) for v in voltages: self.setAmplitude(amplitude=v) time.sleep(0.5) co=self.getThisMeasure()[1] var=cov(co[0])+cov(co[1]) if var>0.01: cod=Datacube("components at p=%f" %pv(v)) cod.createColumn('I',co[0]) cod.createColumn('Q',co[1]) cod.createColumn('bluePower',[pv(v)]*len(co[0])) child.addChild(cod) else: ####### ECRIRE QUELQUE CHOSE ICI [I,Q]=[mean(co[0]),mean(co[1])] child.set(f=f,v=v,I=I,Q=Q,sigma=var,bluePower=pv(v)) child.set(M=sqrt(I**2+Q**2)) child.set(phi=math.atan2(I,Q)) child.commit() data.set(f=f,v=v,I=I,Q=Q,sigma=var,bluePower=pv(v)) data.set(M=sqrt(I**2+Q**2)) data.set(phi=math.atan2(I,Q)) data.commit() data.savetxt() except: raise finally: data.savetxt() self.shape=previousShape def measureJBAPower(self,f=None): if f==None: f=frequency=self._f01 else: f=self._pulseGenerator._MWSource.frequency() self._pulseGenerator.clearPulse() self._pulseGenerator.pulses[self.name()][1]=False self._pulseGenerator.generatePulse(duration=register['repetitionPeriod'],frequency=f,DelayFromZero=0.,useCalibration=False,name='calibration') self._pulseGenerator.pulses['calibration'][1]=True self._pulseGenerator.sendPulse() fsp=self._pulseGenerator._mixer._fsp fsp.write("SENSE1:FREQUENCY:CENTER %f GHZ" % f) fsp.write("SENSE1:FREQUENCY:SPAN 0 MHz") fsp.write("SWE:TIME 1 ms") rbw = 10000 fsp.write("SENSE1:BAND:RES %f Hz" % rbw) fsp.write("SENSE1:BAND:VIDEO AUTO") fsp.write("TRIG:SOURCE EXT") fsp.write("TRIG:HOLDOFF 0.0 s") fsp.write("TRIG:LEVEL 0.5 V") fsp.write("TRIG:SLOP POS") averaging=0 fsp.write("SENSE1:AVERAGE:COUNT %d" % averaging) fsp.write("SENSE1:AVERAGE:STAT1 ON") time.sleep(0.5) m=mean(fsp.getSingleTrace()[1]) print self._pulseGenerator.pulses self._pulseGenerator.pulses['calibration'][1]=False self._pulseGenerator.pulses[self.name()][1]=True self._pulseGenerator.sendPulse() print self._pulseGenerator.pulses return m # Utility functions for separating clusters def multiGaussianClusters(self,distribution,n_components=2,scale=True,returnGMM=False,predict=False): scaler = preprocessing.StandardScaler() distribution2=distribution if scale: distribution2=scaler.fit_transform(distribution) gmm = mixture.GMM(n_components=n_components, covariance_type='full') gmm.fit(distribution2) weights,centers,covars=[gmm.weights_,gmm.means_,gmm.covars_] if scale: centers=scaler.inverse_transform(centers) for i in range(len(covars)): covars[i]= np.diag(scaler.std_).dot(covars[i]).dot(np.diag(scaler.std_)) ind=argsort(weights)[::-1];weights=weights[ind] # sort by decreasing weights [weights,centers,covars]= [elmt[ind] for elmt in [weights,centers,covars]] eigen= map(linalg.eigh,covars) # diagonalize all covariance matrices to find the principal axes and variances model=() #sort principal axes with largest variance first for index in range(len(weights)) : eigvals,eigvecs=eigen[index] ind=argsort(eigvals)[::-1] # principal axis with largest sigma first [eigvals,eigvecs]=[elmt[ind] for elmt in [eigvals,eigvecs]] angle=rad2deg(arctan(eigvecs[0,1]/eigvecs[0,0])) model=model+([weights[index],centers[index],angle,sqrt(eigvals)],) if returnGMM: model=model+(gmm,) if predict: model=model+(gmm.predict(distribution2),) return(model) def separatrixBimodal(self, bimodalGaussian): ''' Find the best separatrix orthogonal to the line joining the two centers of a 2D bimodal Gaussian distribution. Return the list [sepPoint,beta,array([w1,w2]),array([c1,c2]),array([s1,s2])] with - sepPoint the point of the separatrix on the segment joining the centers C1 and C2, - beta the angle between x and the separatrix, - w1,w2 the weights of the two components, - c1,c2 the two centers of the Gaussian - s1,s2 the two sigmas along the C1C2 Note that the first component is on the left of the oriented axe defined by the point and the oriented angle. ''' cluster1,cluster2=bimodalGaussian[0:2] w1,w2=cluster1[0],cluster2[0] c1,c2=cluster1[1],cluster2[1] x,y=c1c2=c2-c1 dist=linalg.norm([x,y]) alpha=arctan2(y,x) # angle between the segment joining the centers and X sigmasAlongC1C2=[] for cluster in [cluster1,cluster2]: c,a,s=cluster[1:4] tangent=tan(a-alpha) sAlongC1C2=sqrt((1+tangent**2)/(1/s[0]**2+(tangent/s[1])**2)) sigmasAlongC1C2.append(sAlongC1C2) s1,s2=sigmasAlongC1C2 sigmaSum=sum(sigmasAlongC1C2) if sigmaSum>dist: print 'Alert: separation between clouds 1 and 2 smaller than sigma1 + sigma2' sepPoint= s1/(s1+s2)*c1c2+c1 beta=alpha+math.pi/2 return [sepPoint,beta,array([w1,w2]),array([c1,c2]),array([s1,s2])] def separatrixMulti(self,ListOfSeparatrices,wMin=0,wMax=1): ''' Find the best separatrix line given a list of separatrices of the form [separatrix1,separatrix2,...] with separatrixi = [sepPoint,beta,weightsW1W2,centersC1C2,sigmasAlongC1C2] Return the a and b parameters of the separatrix equation y=a x + b Separatrices correponding to weight > wMax or weight < wMin are ignored Alert with a message if the separatrix - approaches one of the Gaussian peak at less than a sigma - or is on the wrong side of the gaussian peak ''' __DEBUG__=False # selection=[elmt for elmt in ListOfSeparatrices if (elmt[2][0] > wMin and elmt[2][1] < wMax)] # bug here with the order of the two complementary weights selection=[elmt for elmt in ListOfSeparatrices if abs(elmt[2][1]-elmt[2][0])<=abs(wMax-wMin)] abs(elmt[2][1]-elmt[2][0]) weights=[elmt[2] for elmt in selection] points=[elmt[0] for elmt in selection] status='ok' if len(points)==0: # no separatrices selected => error status='Error:Cannot proceed with an empty ListOfSeparatrices.' print status return [None,status] elif len(points)==1: # only one separatrice selected => return it sepPoint,angle=ListOfSeparatrices[1][:2] a=tan(angle) b=sepPoint[1]-a*sepPoint[0] return [array([a,b]),status] x,y=array(points).T # several separatrices => fit the best new separatrix ## COMPLETELY WRONG !!! minimize y distance betweend separatrix and points A = vstack([x, ones(len(x))]).T a,b= abarray = linalg.lstsq(A, y)[0] for separatrix in selection: # Check if the new separatrix a x + b is valid sepPoint,beta,weights,[c1,c2],[s1,s2]=separatrix if __DEBUG__: print "sepPoint: ", sepPoint c1c2=c2-c1 xi=dot(array([b-c1[1],c1[0]]),c1c2)/dot(array([-a,1]),c1c2) # intersection of a x +b separatrix with C1C2 yi=a*xi+b ci=array([xi,yi]) cic1=c1-ci;cic2=c2-ci; inside=dot(cic1,cic2)<0 if inside: tooClose=linalg.norm(cic1) < s1 or linalg.norm(cic2) <s2 if tooClose: status='invalid' print 'Alert: Separatrix for weights=',weights,' approaches one of the peak by less than a sigma.' else: status='invalid' print 'Alert: Separatrix for weights=',weights,' does not pass between the gaussian peaks' if __DEBUG__: print "a,b: ",a,b return [abarray,status] # return the list of a,b array and status string