if converged[iq, hi] == 1:
chain.h[hi].ota[iq].offset = int(values[iq, hi])
- #for i,n in enumerate(values[0]):
- ## only update flagged values
- #if converged[0, i]:
- #chain.h[i].otaA.offset = int(n)
-
- #for i,n in enumerate(values[1]):
- ## only update flagged values
- #if converged[0, i]:
- #chain.h[i].otaB.offset = int(n)
-
chain.write()
sleep(1.0) # TODO: better delay value?
+def amux_a_offset(x, c, verbose=True):
+ #xi = int(x[0])
+ xi = int(x)
+ amux.otaA.offset = xi
+ amux.write()
+ sleep(MUX_CAL_DELAY)
+ adc.read()
+ values = []
+ for i in range(N_SAMPLES):
+ values.append(offset2signed(adc.read(), 16))
+ sleep(SAMPLE_DELAY)
+ mv = mean(values)
+ #if verbose: print tpx(xi), tplot(mv)
+ return array((mv,))
+
+def amux_b_offset(x, c, verbose=True):
+ xi = int(x)
+ amux.otaB.offset = xi
+ amux.write()
+ sleep(MUX_CAL_DELAY)
+ adc.read()
+ values = []
+ for i in range(N_SAMPLES):
+ values.append(offset2signed(adc.read(), 16))
+ sleep(SAMPLE_DELAY)
+ mv = mean(values)
+ #if verbose: print tpx(xi), tplot(mv)
+ return array((mv,))
+
+
+def arb_outputs(converged, verbose=True):
+ adc.triggerMode(adc.MODE_IDLE)
+ adc.mux(6) #amux.otaA, arb_out0
+ adc.fifo(1)
+ adc.triggerMode(adc.MODE_MANUAL_MANUAL)
+
+ outs = zeros(converged.shape)
+ #each harmonic
+ for i in range(outs.shape[1]):
+ # skip evaluating converged channel groups
+ # output values are ignored for these channels
+ if sum(converged[:,i]) == 0:
+ outs[0, i] = 0.0
+ outs[1, i] = 0.0
+ if verbose: print 'skipping converged channel pair: %02i' % i
+ continue
+
+ amux.selA = i
+ amux.selB = i
+ amux.write()
+ sleep(MUX_SETTLE_DELAY)
+
+ # I, Q
+ for j in range(2):
+ # also ignore individual channel
+ # (small speedup, but it all helps...)
+ if converged[j, i] == 0:
+ outs[j, i] = 0.0
+ if verbose: print 'skipping converged channel %i %s' % (i, ('A','B')[j])
+ continue
+
+ adc.mux(6+j) #vouts on channels 6,7
+ adc.read()
+ values = []
+ v = offset2signed(adc.read(), 16)
+ values.append(v)
+ for k in range(N_SAMPLES-1):
+ sleep(SAMPLE_DELAY)
+ v = offset2signed(adc.read(), 16)
+ values.append(v)
+ if N_SAMPLES >= 2:
+ mv = mean(values[-1*min(10, N_SAMPLES):-1]) #TODO
+ else:
+ mv = values[0]
+ outs[j, i] = mv
+
+ if verbose:
+ print '*** measured outputs: ***'
+ print outs
+
+ return outs
+
+
+
+def arb_offsets(values, converged, mux_offset, verbose=True):
+ if verbose:
+ print
+ print '*** sending values: ***'
+ print values
+
+ for hi in range(16):
+ for iq in range(2):
+ # only update flagged values
+ if converged[iq, hi] == 1:
+ arb.h[hi].ota[iq].offset = int(values[iq, hi])
+
+ arb.write()
+ sleep(1.0) # TODO: better delay value?
+
+ outs = arb_outputs(converged, verbose=verbose)
+
+ # remove measured residual offset from mux to "see through" the pad buffer
+ for i in range(2):
+ outs[i,:] -= mux_offset[i]
+
+ return outs
+
+
+
+
dac.vina(1.25)
dac.vinb(1.25)
dac.vcmi(1.25)
-import datetime as dt
+def calibrate(name, elements=None, verbose=True):
+ """Calibrate the block identified by name. If ids is specified, this is
+ an element or list of the specific elements to be calibrated, leaving
+ others alone.
+
+ returns: (offsets, stats)
+
+ NB: The calibration routines only modify the relevant ota.offset values,
+ and sets the .cal bit for the chains. All other settings (.fast, cint,
+ etc) are left un-touched.
+ """
+ #all amplifiers share this
+ limits = (-128, 127)
+
+ #
+ # Main 48-channel chain
+ #
+ if name == 'chain':
+ N_CHANNELS = 48
+ def func(values, converging):
+ return chain_offsets(
+ values,
+ converging,
+ (int(mux.otaA.offset), int(mux.otaB.offset))
+ )
+
+ #setup initial guess, just use the current values
+ x0 = zeros((2, N_CHANNELS), dtype=int)
+ for i in range(N_CHANNELS):
+ for j in range(2):
+ x0[j,i] = chain.h[i].ota[j].offset
+ offsets, stats = secant_opt(func, x0, limits,
+ elements=elements, verbose=verbose)
+
+ #
+ # Main pad buffer + mux
+ #
+ elif name == 'mux':
+ #save mux state
+ old_mode = [mux.ota[i].mode for i in range(2)]
+
+ mux.otaA.mode = mux.otaA.CAL_CMP
+ mux.otaB.mode = mux.otaB.CAL_CMP
+ mux.write()
+ adc.mux(4)
+
+ def func(values, converging):
+ outA = mux_a_offset(values[0], converging[0], verbose)
+ outB = mux_b_offset(values[1], converging[1], verbose)
+ out = zeros((2,))
+ out[0] = outA
+ out[1] = outB
+ return out
+ return array([outA, outB])
+
+ #setup initial guess, just use the current values
+ x0 = zeros((2,), dtype=int)
+ for i in range(2):
+ x0[i] = int(mux.ota[i].offset)
+
+ offsets, stats = secant_opt(func, x0, limits,
+ elements=elements, verbose=verbose)
+
+ #restore mux state
+ for i,mode in enumerate(old_mode):
+ mux.ota[i].mode = mode
+ mux.write()
+
+ #
+ # Secondary arbitrary function, 16 channels
+ #
+ if name == 'arb':
+ N_CHANNELS = 16
+ def func(values, converging):
+ return arb_offsets(
+ values,
+ converging,
+ (int(amux.otaA.offset), int(amux.otaB.offset))
+ )
+
+ #setup initial guess, just use the current values
+ x0 = zeros((2, N_CHANNELS), dtype=int)
+ for i in range(N_CHANNELS):
+ for j in range(2):
+ x0[j,i] = arb.h[i].ota[j].offset
+ offsets, stats = secant_opt(func, x0, limits,
+ elements=elements, verbose=verbose)
+
+ #
+ # Secondary pad buffer + mux
+ #
+ elif name == 'amux':
+ #save mux state
+ old_mode = [amux.ota[i].mode for i in range(2)]
+
+ amux.otaA.mode = amux.otaA.CAL_CMP
+ amux.otaB.mode = amux.otaB.CAL_CMP
+ amux.write()
+ adc.mux(6)
+
+ def func(values, converging):
+ outA = amux_a_offset(values[0], converging[0], verbose)
+ outB = amux_b_offset(values[1], converging[1], verbose)
+ out = zeros((2,))
+ out[0] = outA
+ out[1] = outB
+ return out
+ return array([outA, outB])
+
+ #setup initial guess, just use the current values
+ x0 = zeros((2,), dtype=int)
+ for i in range(2):
+ x0[i] = int(amux.ota[i].offset)
+
+ offsets, stats = secant_opt(func, x0, limits,
+ elements=elements, verbose=verbose)
+
+ #restore mux state
+ for i,mode in enumerate(old_mode):
+ amux.ota[i].mode = mode
+ amux.write()
+
+ else:
+ print 'ERROR: unknown name %s' % name
+
+ return (offsets, stats)
+
+
+
+
+
+
+
while False:
+ import datetime as dt
if 1:
mux.otaA.mode = mux.otaA.CAL_BUF
mux.otaA.fast = 1
-def calibrate(name, elements=None, verbose=True):
- """Calibrate the block identified by name. If ids is specified, this is
- an element or list of the specific elements to be calibrated, leaving
- others alone.
-
- returns: (offsets, stats)
-
- NB: The calibration routines only modify the relevant ota.offset values,
- and sets the .cal bit for the chains. All other settings (.fast, cint,
- etc) are left un-touched.
- """
- #all amplifiers share this
- limits = (-128, 127)
-
- if name == 'chain':
- def func(values, converging):
- return chain_offsets(
- values,
- converging,
- (int(mux.otaA.offset), int(mux.otaB.offset))
- )
-
- #setup initial guess, just use the current values
- x0 = zeros((2, N_CHANNELS), dtype=int)
- for i in range(N_CHANNELS):
- for j in range(2):
- x0[j,i] = chain.h[i].ota[j].offset
- offsets, stats = secant_opt(func, x0, limits,
- elements=elements, verbose=verbose)
- elif name == 'mux':
- #save mux state
- old_mode = [mux.ota[i].mode for i in range(2)]
-
- mux.otaA.mode = mux.otaA.CAL_CMP
- mux.otaB.mode = mux.otaB.CAL_CMP
- mux.write()
- adc.mux(4)
-
- def func(values, converging):
- outA = mux_a_offset(values[0], converging[0], verbose)
- outB = mux_b_offset(values[1], converging[1], verbose)
- out = zeros((2,))
- out[0] = outA
- out[1] = outB
- return out
- return array([outA, outB])
-
- #setup initial guess, just use the current values
- x0 = zeros((2,), dtype=int)
- for i in range(2):
- x0[i] = int(mux.ota[i].offset)
-
- offsets, stats = secant_opt(func, x0, limits,
- elements=elements, verbose=verbose)
-
- #restore mux state
- for i,mode in enumerate(old_mode):
- mux.ota[i].mode = mode
- mux.write()
-
- else:
- print 'ERROR: unknown name %s' % name
-
- return (offsets, stats)
-
-
-
-