Ejemplo n.º 1
0
def SET_BAND(msg):
    '''Set IFSwitch band to BAND.  If this would change the selection,
       first sets Agilent to a safe level to avoid high power to mixer.'''
    log.debug('SET_BAND(%s)', msg.arg)
    if not initialised:
        raise drama.BadStatus(drama.APP_ERROR, 'task needs INITIALISE')
    args, kwargs = drama.parse_argument(msg.arg)
    band = set_band_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 ifswitch.get_band() != band:
        log.info('setting IF switch to band %d', band)
        # reduce power to minimum levels
        agilent.set_dbm(agilent.safe_dbm)
        agilent.update(publish_only=True)
        if photonics:
            photonics.set_attenuation(photonics.max_att)
        ifswitch.set_band(band)
    else:
        log.info('IF switch already at band %d', band)
Ejemplo n.º 2
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
Ejemplo n.º 3
0
parser.add_argument('dbm', type=float, help='synth power')
parser.add_argument('--note',
                    nargs='?',
                    default='',
                    help='note for file header')
args = parser.parse_args()

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)

ifswitch = namakanui.ifswitch.IFSwitch(datapath + 'ifswitch.ini', time.sleep,
                                       namakanui.nop)
ifswitch.set_band(args.band)
ifswitch.close()  # done with ifswitch

photonics = namakanui.photonics.Photonics(datapath + 'photonics.ini',
                                          time.sleep, namakanui.nop)
photonics.set_attenuation(photonics.max_att)

#prologix = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#prologix.settimeout(1)
#prologix.connect((args.IP, 1234))
#prologix.send(b'++savecfg 0\n')  # don't save settings to prologix EPROM
#prologix.send(b'++addr %d\n'%(args.GPIB))

# TODO: is it worth making a class for the N1913A?
pmeter = socket.socket()
pmeter.settimeout(1)
Ejemplo n.º 4
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)