Пример #1
0
def SET_SG_OUT(msg):
    '''Set Agilent output on (1) or off (0).'''
    log.debug('SET_SG_OUT(%s)', msg.arg)
    if not initialised:
        raise drama.BadStatus(drama.APP_ERROR, 'task needs INITIALISE')
    args, kwargs = drama.parse_argument(msg.arg)
    out = set_sg_out_args(*args, **kwargs)
    log.info('setting agilent output to %d', out)
    agilent.set_output(out)
    agilent.update(publish_only=True)
Пример #2
0
def loop():
    global i, prev_powers
    while i < 23:
        time.sleep(1)
        i += 1
        if i < 0:
            sys.stderr.write('.')
        else:
            sys.stderr.write('%d ' % (i))
        sys.stderr.flush()
        if i % 5 == 4:
            # retune the cart; make sure it loses the lock
            dbm = agilent.state['dbm']
            while dbm > agilent.safe_dbm and not cart.state['pll_unlock']:
                agilent.set_dbm(dbm)
                cart.update_all()
                dbm -= 0.1
            dbm = agilent.safe_dbm
            agilent.set_dbm(dbm)
            agilent.set_output(0)
            time.sleep(0.05)
            agilent.set_output(1)
            agilent.set_dbm(orig_dbm)
            time.sleep(0.05)
            cart.tune(lo_ghz, 0.0)
            time.sleep(0.05)
        transid = drama.obey("IFTASK@if-micro",
                             "WRITE_TP2",
                             FILE="NONE",
                             ITIME=0.1)
        cart.update_all()
        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
        if cart.state['pll_unlock']:
            logging.error('failed to tune')
            return
        powers = []
        for dcm in dcms:
            powers.append(msg.arg['POWER%d' % (dcm)])
        for j, (prev, curr) in enumerate(zip(prev_powers, powers)):
            pdiff = abs((prev - curr) / min(prev, curr)) * 100.0
            if pdiff > 1.5:
                logging.info('%.2f%% jump in DCM %d', pdiff, dcms[j])
                # let's write to the output file too, might come in handy
                sys.stdout.write('# jump DCM %d, %.2f%%\n' % (dcms[j], pdiff))
                if i < 0:
                    i = 0  # collect a bit more data, then quit
        prev_powers = powers
        output(powers)
Пример #3
0
parser.add_argument('--note',
                    nargs='?',
                    default='',
                    help='note for file header')
args = parser.parse_args()

sys.stdout.write(time.strftime('# %Y%m%d %H:%M:%S HST\n', time.localtime()))
sys.stdout.write('# %s\n' % (sys.argv))
sys.stdout.write('#\n')
sys.stdout.flush()

agilent = namakanui.agilent.Agilent(datapath + 'agilent.ini', time.sleep,
                                    namakanui.nop)
agilent.log.setLevel(logging.INFO)
agilent.set_dbm(agilent.safe_dbm)
agilent.set_output(1)

# TODO: is it worth making a class for the N1913A?
pmeter = socket.socket()
pmeter.settimeout(1)
pmeter.connect((args.ip, 5025))
pmeter.send(b'*idn?\n')
idn = pmeter.recv(256)
if b'N1913A' not in idn:
    logging.error('expected power meter model N1913A, but got %s', idn)
    sys.exit(1)
# just assume all this succeeds
pmeter.send(b'*cls\n')  # clear errors
pmeter.send(b'unit:power dbm\n')  # dBm readings
pmeter.send(b'init:cont on\n')  # free run mode
pmeter.send(b'mrate normal\n')  # 20 reads/sec
Пример #4
0
import os
import sys

import logging
logging.root.addHandler(logging.StreamHandler())
logging.root.setLevel(logging.INFO)

binpath, datapath = namakanui.util.get_paths()


def mypub(n, s):
    pass


logging.info('\ndisabling agilent output')
try:
    agilent = namakanui.agilent.Agilent(datapath + 'agilent.ini', time.sleep,
                                        namakanui.nop)
    agilent.set_dbm(agilent.safe_dbm)
    agilent.set_output(0)
except socket.timeout as e:
    logging.warning('*** WARNING: socket.timeout, skipping agilent. ***')

for band in [3, 6, 7]:
    logging.info('\nband %d:', band)
    cart = namakanui.cart.Cart(band, datapath + 'band%d.ini' % (band),
                               time.sleep, mypub)
    cart.power(0)

logging.info('\nall cartridges powered down.')
Пример #5
0
def setup_script(band, lock_side, sleep=time.sleep, publish=namakanui.nop):
    '''
    Perform common setup for a standalone script:
        - Create agilent and set to safe levels with output enabled.
        - Create photonics (if in namaknui.ini) and set max attenuation.
        - Create cart(band) and set given lock side.
        - Zero out pa/lna on unused bands.
        - Set ifswitch to given band.
        - Check reference (floog) power level.
    Returns cart, agilent, photonics.
    '''
    import namakanui.ini
    import namakanui.cart
    import namakanui.agilent
    import namakanui.photonics
    import namakanui.ifswitch
    
    binpath, datapath = get_paths()
    
    agilent = namakanui.agilent.Agilent(datapath+'agilent.ini', sleep, publish)
    agilent.set_dbm(agilent.safe_dbm)
    agilent.set_output(1)
    
    photonics = None
    nconfig = namakanui.ini.IncludeParser(datapath+'namakanui.ini')
    if 'photonics_ini' in nconfig['namakanui']:
        pini = nconfig['namakanui']['photonics_ini']
        photonics = namakanui.photonics.Photonics(datapath+pini, sleep, publish)
        photonics.set_attenuation(photonics.max_att)
    
    ifswitch = namakanui.ifswitch.IFSwitch(datapath+'ifswitch.ini', sleep, publish)
    ifswitch.set_band(band)
    ifswitch.close()  # done with ifswitch
    
    cart = namakanui.cart.Cart(band, datapath+'band%d.ini'%(band), sleep, publish)
    cart.power(1)
    if lock_side is not None:
        lock_side = lock_side.lower() if hasattr(lock_side, 'lower') else lock_side
        lock_side = {0:0, 1:1, 'below':0, 'above':1}[lock_side]
        cart.femc.set_cartridge_lo_pll_sb_lock_polarity_select(cart.ca, lock_side)
        cart.state['pll_sb_lock'] = lock_side  # cart never updates this
    
    # zero out unused carts
    femc = cart.femc
    for b in [3,6,7]:
        if b == band:
            continue
        ca = b-1
        if not femc.get_pd_enable(ca):
            continue
        for po in range(2):
            femc.set_cartridge_lo_pa_pol_drain_voltage_scale(ca, po, 0)
            femc.set_cartridge_lo_pa_pol_gate_voltage(ca, po, 0)
            for sb in range(2):
                femc.set_lna_enable(ca, po, sb, 0)
    
    # this mainly checks that the IF switch really has this band selected
    cart.update_all()
    rp = cart.state['pll_ref_power']
    if rp < -3.0:
        raise RuntimeError('PLL ref (FLOOG 31.5 MHz) power high (%.2fV), needs padding'%(rp))
    if rp > -0.5:
        raise RuntimeError('PLL ref (FLOOG 31.5 MHz) power low (%.2fV), check IF switch'%(rp))
    
    return cart, agilent, photonics
Пример #6
0
def CART_TUNE(msg):
    '''Tune a cartridge, after setting reference frequency.  Arguments:
            BAND:      One of 3,6,7
            LO_GHZ:    Local oscillator frequency in gigahertz
            VOLTAGE:   Desired PLL control voltage, [-10,10].
                       If not given, voltage will not be adjusted
                       following the initial lock.
            LOCK_ONLY: if True, bias voltage, PA, LNA, and magnets will not
                       be adjusted after locking the receiver.
       
       TODO: lock polarity (below or above reference) could be a parameter.
             for now we just read back from the cartridge task.
       
       TODO: save dbm offset and use it for close frequencies.
    '''
    log.debug('CART_TUNE(%s)', msg.arg)
    if not initialised:
        raise drama.BadStatus(drama.APP_ERROR, 'task needs INITIALISE')
    args, kwargs = drama.parse_argument(msg.arg)
    band, lo_ghz, voltage, lock_only = cart_tune_args(*args, **kwargs)
    if band not in [3, 6, 7]:
        raise drama.BadStatus(drama.INVARG,
                              'BAND %d not one of [3,6,7]' % (band))
    if not 70 <= lo_ghz <= 400:  # TODO be more specific
        raise drama.BadStatus(drama.INVARG,
                              'LO_GHZ %g not in [70,400]' % (lo_ghz))
    if voltage and not -10 <= voltage <= 10:
        raise drama.BadStatus(drama.INVARG,
                              'VOLTAGE %g not in [-10,10]' % (voltage))

    if ifswitch.get_band() != band:
        log.info('setting IF switch to band %d', band)
        # reduce power first
        agilent.set_dbm(agilent.safe_dbm)
        if photonics:
            photonics.set_attenuation(photonics.max_att)
        ifswitch.set_band(band)

    cartname = cartridge_tasknames[band]

    # TODO don't assume pubname is DYN_STATE
    dyn_state = drama.get(cartname, "DYN_STATE").wait().arg["DYN_STATE"]
    lock_polarity = dyn_state['pll_sb_lock']  # 0=below_ref, 1=above_ref
    lock_polarity = -2.0 * lock_polarity + 1.0

    fyig = lo_ghz / (cold_mult[band] * warm_mult[band])
    fsig = (fyig * warm_mult[band] +
            agilent.floog * lock_polarity) / agilent.harmonic
    if photonics:
        dbm = agilent.interp_dbm(0, fsig)
        att = photonics.interp_attenuation(band, lo_ghz)
        log.info('setting photonics attenuator to %d counts', att)
    else:
        dbm = agilent.interp_dbm(band, lo_ghz)
    dbm = min(dbm, agilent.max_dbm)
    log.info('setting agilent to %g GHz, %g dBm', fsig, dbm)
    # set power safely while maintaining lock, if possible.
    hz = fsig * 1e9
    if photonics:
        if att < photonics.state['attenuation']:
            agilent.set_hz_dbm(hz, dbm)
            photonics.set_attenuation(att)
        else:
            photonics.set_attenuation(att)
            agilent.set_hz_dbm(hz, dbm)
    else:
        agilent.set_hz_dbm(hz, dbm)
    agilent.set_output(1)
    agilent.update(publish_only=True)
    time.sleep(0.05)  # wait 50ms; for small changes PLL might hold lock
    vstr = ''
    band_kwargs = {"LO_GHZ": lo_ghz}
    if voltage is not None:
        vstr += ', %g V' % (voltage)
        band_kwargs["VOLTAGE"] = voltage
    if lock_only:
        vstr += ', LOCK_ONLY'
        band_kwargs["LOCK_ONLY"] = lock_only
    log.info('band %d tuning to LO %g GHz%s...', band, lo_ghz, vstr)

    pll_if_power = 0.0

    # tune in a loop, adjusting signal to get pll_if_power in proper range.
    # adjust attenuator if present, then adjust output dBm.
    if photonics:
        orig_att = att
        att_min = max(0, att - 24)  # limit 2x nominal power
        tries = 0
        max_tries = 5
        while True:
            tries += 1
            msg = drama.obey(cartname, 'TUNE', **band_kwargs).wait()
            if msg.reason != drama.REA_COMPLETE:
                raise drama.BadStatus(drama.UNEXPMSG,
                                      '%s bad TUNE msg: %s' % (cartname, msg))
            elif msg.status == drama.INVARG:
                # frequency out of range
                agilent.set_dbm(agilent.safe_dbm)
                photonics.set_attenuation(photonics.max_att)
                raise drama.BadStatus(msg.status,
                                      '%s TUNE failed' % (cartname))
            elif msg.status != 0:
                # tune failure, raise the power and try again
                old_att = att
                att -= 8
                if att < att_min:
                    att = att_min
                if att == old_att or tries > max_tries:  # stuck at the limit, time to give up
                    photonics.set_attenuation(orig_att)
                    raise drama.BadStatus(msg.status,
                                          '%s TUNE failed' % (cartname))
                log.warning(
                    'band %d tune failed, retuning at %d attenuator counts...',
                    band, att)
                photonics.set_attenuation(att)
                time.sleep(0.05)
                continue
            # we got a lock.  check the pll_if_power level.
            # TODO don't assume pubname is DYN_STATE
            dyn_state = drama.get(cartname,
                                  "DYN_STATE").wait().arg["DYN_STATE"]
            pll_if_power = dyn_state['pll_if_power']
            if tries > max_tries:  # avoid bouncing around forever
                break
            old_att = att
            if pll_if_power < -2.5:  # power too high
                att += 4
            elif pll_if_power > -0.7:  # power too low
                att -= 4
            else:  # power is fine
                break
            if att < att_min:
                att = att_min
            elif att > photonics.max_att:
                att = photonics.max_att
            if att == old_att:  # stuck at the limit, so it'll have to do
                break
            log.warning(
                'band %d bad pll_if_power %.2f; retuning at %d attenuator counts...',
                band, pll_if_power, att)
            photonics.set_attenuation(att)
            time.sleep(0.05)
        log.info(
            'band %d tuned to LO %g GHz, pll_if_power %.2f at %.2f dBm, %d attenuator counts',
            band, lo_ghz, pll_if_power, dbm, att)
    #else:
    if not (-2.5 <= pll_if_power <=
            -0.7):  # adjust dbm after photonics if needed
        orig_dbm = dbm
        orig_att = att if photonics else 0
        dbm_max = min(agilent.max_dbm, dbm + 3.0)  # limit to 2x nominal power
        att_min = max(0, att - 6) if photonics else 0  # ditto
        tries = 0
        max_tries = 5
        while True:
            tries += 1
            msg = drama.obey(cartname, 'TUNE', **band_kwargs).wait()
            if msg.reason != drama.REA_COMPLETE:
                raise drama.BadStatus(drama.UNEXPMSG,
                                      '%s bad TUNE msg: %s' % (cartname, msg))
            elif msg.status == drama.INVARG:
                # frequency out of range
                agilent.set_dbm(agilent.safe_dbm)
                raise drama.BadStatus(msg.status,
                                      '%s TUNE failed' % (cartname))
            elif msg.status != 0:
                # tune failure, raise the power and try again
                old_dbm = dbm
                dbm += 1.0
                if dbm > dbm_max:
                    dbm = dbm_max
                if dbm == old_dbm or tries > max_tries:  # stuck at the limit, time to give up
                    agilent.set_dbm(orig_dbm)
                    raise drama.BadStatus(msg.status,
                                          '%s TUNE failed' % (cartname))
                log.warning('band %d tune failed, retuning at %.2f dBm...',
                            band, dbm)
                agilent.set_dbm(dbm)
                time.sleep(0.05)
                continue
            # we got a lock.  check the pll_if_power level.
            # TODO don't assume pubname is DYN_STATE
            dyn_state = drama.get(cartname,
                                  "DYN_STATE").wait().arg["DYN_STATE"]
            pll_if_power = dyn_state['pll_if_power']
            if tries > max_tries:  # avoid bouncing around forever
                break
            old_dbm = dbm
            if pll_if_power < -2.5:  # power too high
                dbm -= 0.5
            elif pll_if_power > -0.7:  # power too low
                dbm += 0.5
            else:  # power is fine
                break
            if dbm > dbm_max:
                dbm = dbm_max
            elif dbm < -20.0:
                dbm = -20.0
            if dbm == old_dbm:  # stuck at the limit, so it'll have to do
                break
            log.warning(
                'band %d bad pll_if_power %.2f; retuning at %.2f dBm...', band,
                pll_if_power, dbm)
            agilent.set_dbm(dbm)
            time.sleep(0.05)
        log.info('band %d tuned to LO %g GHz, pll_if_power %.2f at %.2f dBm.',
                 band, lo_ghz, pll_if_power, dbm)