def iv(target, rows): if target == 'hot': p_index = hot_p_index else: p_index = sky_p_index load.move('b%d_%s' % (band, target)) if target == 'hot': cart.tune(lo_ghz, 0.0, skip_servo_pa=True) cart._set_pa([pas[0], pas[1]]) cart.update_all() if namakanui.util.iftask_setup(2, 1000, 6, dcms): # level only return 1 sys.stderr.write('%s: ' % (target)) sys.stderr.flush() mult = 1.0 if band == 6: mult = -1.0 cart._ramp_sis_bias_voltages( [mult * mvs[0], mvs[0], mult * mvs[0], mvs[0]]) for i, mv in enumerate(mvs): if (i + 1) % 20 == 0: sys.stderr.write('%.2f%% ' % (0.0 + 50 * i / len(mvs))) sys.stderr.flush() cart.update_all() # for anyone monitoring for po in range(2): cart.femc.set_sis_voltage(cart.ca, po, 0, mult * mv) cart.femc.set_sis_voltage(cart.ca, po, 1, mv) rows[i][mv_index] = mv # start IFTASK action while we average the mixer current readings transid = drama.obey("IFTASK@if-micro", "WRITE_TP2", FILE="NONE", ITIME=0.1) # TODO: separate hot/cold mixer currents, or only calc hot for j in range(ua_n): for po in range(2): for sb in range(2): ua = cart.femc.get_sis_current(cart.ca, po, sb) * 1e3 rows[i][ua_avg_index + po * 2 + sb] += abs( ua) # for band 6 rows[i][ua_dev_index + po * 2 + sb] += ua * ua # get IFTASK reply msg = transid.wait(5) if msg.reason != drama.REA_COMPLETE or msg.status != 0: logging.error('bad reply from IFTASK.WRITE_TP2: %s', msg) return 1 for j, dcm in enumerate(dcms): rows[i][p_index + j] = msg.arg['POWER%d' % (dcm)] sys.stderr.write('\n') sys.stderr.flush() return 0
def LOAD_MOVE(msg): '''Move the load. Arguments: POSITION: Named position or absolute encoder counts. ''' log.debug('LOAD_MOVE(%s)', msg.arg) if not initialised: raise drama.BadStatus(drama.APP_ERROR, 'task needs INITIALISE') if msg.reason == drama.REA_OBEY: args, kwargs = drama.parse_argument(msg.arg) pos = load_move_args(*args, **kwargs) log.info('moving load to %s...', pos) load.move(pos) log.info('load at %d, %s.', load.state['pos_counts'], load.state['pos_name']) else: log.error('LOAD_MOVE stopping load due to unexpected msg %s', msg) load.stop()
def ip(target, rows, pas): if target == 'hot': p_index = hot_p_index else: p_index = sky_p_index load.move('b%d_%s' % (band, target)) sys.stderr.write('%s: ' % (target)) sys.stderr.flush() for i, pa in enumerate(pas): if (i + 1) % 20 == 0: sys.stderr.write('%.2f%% ' % (100.0 * i / len(pas))) sys.stderr.flush() cart.update_all() cart._set_pa([pa, pa]) rows[i][pa_index] = pa # start IFTASK action while we average the mixer current readings transid = drama.obey("IFTASK@if-micro", "WRITE_TP2", FILE="NONE", ITIME=0.1) for j in range(ua_n): for po in range(2): for sb in range(2): ua = cart.femc.get_sis_current(cart.ca, po, sb) * 1e3 rows[i][ua_avg_index + po * 2 + sb] += abs( ua) # for band 6 rows[i][ua_dev_index + po * 2 + sb] += ua * ua # get IFTASK reply msg = transid.wait(5) if msg.reason != drama.REA_COMPLETE or msg.status != 0: logging.error('bad reply from IFTASK.WRITE_TP2: %s', msg) return 1 for j, dcm in enumerate(dcm_0 + dcm_1): rows[i][p_index + j] = msg.arg['POWER%d' % (dcm)] sys.stderr.write('\n') sys.stderr.flush() return 0
parser.add_argument('--level_only', action='store_true') args = parser.parse_args() band = args.band lo_ghz = args.lo_ghz lo_range = {6:[219,266], 7:[281,367]}[band] if not lo_range[0] <= lo_ghz <= lo_range[1]: logging.error('lo_ghz %g outside %s range for band %d', lo_ghz, lo_range, band) sys.exit(1) # perform basic setup and get handles cart, agilent, photonics = util.setup_script(args.band, args.lock_side) # init load controller and set to hot (ambient) load for this band load = namakanui.load.Load(datapath+'load.ini', time.sleep, namakanui.nop) load.move('b%d_hot'%(band)) # tune cartridge, adjusting power as needed if not util.tune(cart, agilent, photonics, lo_ghz): logging.error('failed to tune to %.3f ghz', lo_ghz) sys.exit(1) # determine dbm limits dbm = agilent.state['dbm'] orig_dbm = dbm while dbm < agilent.max_dbm and cart.state['pll_if_power'] > -2.5 and not cart.state['pll_unlock']: dbm += 0.1 agilent.set_dbm(dbm) time.sleep(0.05) cart.update_all() logging.info('+ dbm %.2f, pll_if %.3f', dbm, cart.state['pll_if_power'])
action='store_true', help='print additional debug output') parser.add_argument('pos', help='"home", counts, or a named position from load.ini') args = parser.parse_args() if args.verbose: logging.root.setLevel(logging.DEBUG) logging.debug('verbose: log level set to DEBUG') binpath, datapath = namakanui.util.get_paths() def mypub(n, s): pass load = namakanui.load.Load(datapath + 'load.ini', time.sleep, mypub) pos = args.pos.strip() if pos.lower() == 'home': logging.info('homing load controller...') load.home() else: logging.info('moving to %s...', pos) load.move(pos) load.update() logging.info('done, load at %d: %s', load.state['pos_counts'], load.state['pos_name'])
for mixer in ['01', '02', '11', '12']: sys.stdout.write(' ua%s' % (mixer)) for po in ['0', '1']: sys.stdout.write(' vd%s' % (po)) for po in ['0', '1']: sys.stdout.write(' id%s' % (po)) for po in ['0', '1']: sys.stdout.write(' vg%s' % (po)) sys.stdout.write('\n') sys.stdout.flush() # init load controller and set desired load (default hot) load = namakanui.load.Load(datapath + 'load.ini', time.sleep, namakanui.nop) if args.load == 'hot' or args.load == 'sky': args.load = 'b%d_' % (band) + args.load load.move(args.load) # perform basic setup and get handles cart, agilent, photonics = namakanui.util.setup_script(args.band, args.lock_side) # main loop for lo in los: if not namakanui.util.tune(cart, agilent, photonics, lo): continue sys.stdout.write('%.3f ' % (lo)) pa_drain_s = cart.state['pa_drain_s'] sys.stdout.write('%.3f %.3f ' % (pa_drain_s[0], pa_drain_s[1])) # average mixer currents n = 10 uas = [0.0] * 4
parser.add_argument('--vg') # range (for b6, use -.40:.14:.01) parser.add_argument('--vd', type=float, default=2.5) # vd for both pols during vg sweep args = parser.parse_args() args.lock_side = 'above' los = namakanui.util.parse_range(args.lo, maxlen=1e3) vgs = namakanui.util.parse_range(args.vg, maxlen=1e2) # TODO okay for b7? # perform basic setup and get handles cart, agilent, photonics = namakanui.util.setup_script(args.band, args.lock_side) # init load controller and set to hot (ambient) load for this band load = namakanui.load.Load(datapath + 'load.ini', time.sleep, namakanui.nop) load.move('b%d_hot' % (args.band)) # for _servo_pa output cart.log.setLevel(logging.DEBUG) # write out a header for our output file print(time.strftime('# %Y%m%d %H:%M:%S HST', time.localtime())) print('#', sys.argv) print('# vdX: LO PA drain voltage for polX') print('# vdX: LO PA gate voltage for polX') print('#') print('#lo_ghz vd0 vd1 vg0 vg1') # 7-point averaging function to smooth vg-ua curves def smooth(y):
def iv(target, rows, pa): if target == 'hot': p_index = hot_p_index else: p_index = sky_p_index load.move('b%d_%s' % (band, target)) # TODO Maybe it's wrong to relevel for each PA; it makes it harder # to compare power between PAs if the leveling is slightly different. # Ambient temperature shouldn't be changing much compared to the # difference between hot load and sky, either. # at the start of a HOT row, re-tune and re-level the power meters # at the nominal values. do not relevel on SKY or y-factor won't work. # actually re-leveling makes it difficult to compare power levels # across sweeps, so skip it. retuning is fine though. # 20200221 but ACTUALLY we're having problems with saturating power levels, # so DO relevel the detectors here. we won't be able to see # relative power levels, but we mostly only do 2 PAs these days and care # more about Y-factor values anyway. if target == 'hot': # dbm/att should already be set from namakanui.util.tune cart.tune(lo_ghz, 0.0, skip_servo_pa=True) cart._set_pa([pa, pa]) cart.update_all() if namakanui.util.iftask_setup(2, 1000, 6, dcms): # level only return 1 sys.stderr.write('%s: ' % (target)) sys.stderr.flush() # NOTE: The two SIS mixers in each polarization module are not really USB and LSB. # Rather the input to one is phase-shifted relative to the other, and their # signals are then combined to produce USB and LSB outputs. So to check the # power output and Y-factor from each mixer individually, the other one needs # to have its output disabled by setting its bias voltage to zero. # Since we still need to smoothly ramp SIS bias voltage for large changes, # we therefore do two separate loops for sis1 and sis2. # TODO: Once we have the mixers optimized individually, we might still need # to optimize their combined outputs. This will require a 2D scan of # mixer bias voltage for each PA setting. # sis1 sb = 0 mult = 1.0 if band == 6: mult = -1.0 if args.zero: cart._ramp_sis_bias_voltages([mult * mvs[0], 0.0, mult * mvs[0], 0.0]) else: cart._ramp_sis_bias_voltages( [mult * mvs[0], nom_v[1], mult * mvs[0], nom_v[3]]) for i, mv in enumerate(mvs): if (i + 1) % 20 == 0: sys.stderr.write('%.2f%% ' % (0.0 + 50 * i / len(mvs))) sys.stderr.flush() cart.update_all() # for anyone monitoring for po in range(2): cart.femc.set_sis_voltage(cart.ca, po, sb, mult * mv) rows[i][mv_index] = mv # start IFTASK action while we average the mixer current readings transid = drama.obey("IFTASK@if-micro", "WRITE_TP2", FILE="NONE", ITIME=0.1) for j in range(ua_n): for po in range(2): ua = cart.femc.get_sis_current(cart.ca, po, sb) * 1e3 rows[i][ua_avg_index + po * 2 + sb] += abs(ua) # for band 6 rows[i][ua_dev_index + po * 2 + sb] += ua * ua # get IFTASK reply msg = transid.wait(5) if msg.reason != drama.REA_COMPLETE or msg.status != 0: logging.error('bad reply from IFTASK.WRITE_TP2: %s', msg) return 1 for j, dcm in enumerate(dcm_0): rows[i][p_index + j + 0] = msg.arg['POWER%d' % (dcm)] for j, dcm in enumerate(dcm_1): rows[i][p_index + j + 16] = msg.arg['POWER%d' % (dcm)] # sis2 sb = 1 if args.zero: cart._ramp_sis_bias_voltages([0.0, mvs[0], 0.0, mvs[0]]) else: cart._ramp_sis_bias_voltages([nom_v[0], mvs[0], nom_v[2], mvs[0]]) for i, mv in enumerate(mvs): if (i + 1) % 20 == 0: sys.stderr.write('%.2f%% ' % (50.0 + 50 * i / len(mvs))) sys.stderr.flush() cart.update_all() # for anyone monitoring for po in range(2): cart.femc.set_sis_voltage(cart.ca, po, sb, mv) rows[i][mv_index] = mv # start IFTASK action while we average the mixer current readings transid = drama.obey("IFTASK@if-micro", "WRITE_TP2", FILE="NONE", ITIME=0.1) for j in range(ua_n): for po in range(2): ua = cart.femc.get_sis_current(cart.ca, po, sb) * 1e3 rows[i][ua_avg_index + po * 2 + sb] += ua rows[i][ua_dev_index + po * 2 + sb] += ua * ua # get IFTASK reply msg = transid.wait(5) if msg.reason != drama.REA_COMPLETE or msg.status != 0: logging.error('bad reply from IFTASK.WRITE_TP2: %s', msg) return 1 for j, dcm in enumerate(dcm_0): rows[i][p_index + j + 8] = msg.arg['POWER%d' % (dcm)] for j, dcm in enumerate(dcm_1): rows[i][p_index + j + 24] = msg.arg['POWER%d' % (dcm)] sys.stderr.write('\n') sys.stderr.flush() return 0