view rs_fsp7_noisetest.py @ 49:22187590594b

Turn averaging on otherwise we throw away all but the last sweep.
author Daniel O'Connor <doconnor@gsoft.com.au>
date Thu, 31 Jan 2013 12:53:22 +1030
parents 386e1cb04799
children d143ef509fb7
line wrap: on
line source

#!/usr/bin/env python

# Copyright (c) 2012
#      Daniel O'Connor <darius@dons.net.au>.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#

import math
import numpy
import optparse
import rsib
import scipy
import scpi
import sys

def findenr(frq):
    # ENR values from the noise source
    enrdb = numpy.array([15.55, 15.96, 15.68, 15.11, 15.07, 14.84, 14.77, 14.82, 14.86, 14.79, 14.83, 14.93, 14.93, 15.07, 15.19, 15.08, 15.14, 14.87, 14.97, 14.59])
    enrfrq = numpy.array([0.01e9, 0.1e9, 1.0e9, 2.0e9, 3.0e9, 4.0e9, 5.0e9, 6.0e9, 7.0e9, 8.0e9, 9.0e9, 10.0e9, 11.0e9, 12.0e9, 13.0e9, 14.0e9, 15.0e9, 16.0e9, 17.0e9, 18.0e9])

    # Convert back to linear values
    enr = 10 ** (enrdb / 10)

    # Interpolate
    rtn = scipy.interp([frq], enrfrq, enr)

    # Convert to dB
    rtndb = 10 * math.log10(rtn)

    return rtndb
    
def setup(r, freq, span, sweeps):
    # Reset to defaults
    r.write("*RST")

    # Set to single sweep mode
    r.write("INIT:CONT OFF")

    # Enable display updates
    r.write("SYST:DISP:UPD ON")

    # Set frequency range
    r.write("SENSE1:FREQ:CENT %f Hz" % (freq))
    r.write("SENSE1:FREQ:SPAN %f Hz" % (span))

    # Switch marker 1 on in screen A
    r.write("CALC:MARK1 ON")

    # Enable noise measurement
    r.write("CALC:MARK1:FUNC:NOIS ON")

    # Turn averaging on
    r.write("AVER:STAT ON")

    # Set number of sweeps
    r.write("SWE:COUN %d" % (sweeps))

    # Set resolution bandwidth
    r.write("SENS1:BAND:RES 1kHz")

    # Set video bandwidth (10x res BW)
    r.write("SENS1:BAND:VID 10kHz")
    
def getnoise(r):
    # Trigger the sweep
    r.write("INIT;*WAI")

    # Wait for it to be done
    r.write("*OPC?")
    opc = scpi.getdata(r.read(60), int)
    #print "OPC - %d" % (opc)
    assert(opc == 1)
    
    # Set data format
    r.write("FORM:DATA ASC")

    # Read noise value
    r.write("CALC:MARK1:FUNC:NOIS:RES?")
    data = r.read(10)
    #print "Data - " + data

    return float(data)

def setnoise(r, en):
    if en:
        val = "ON"
    else:
        val = "OFF"
    r.write("DIAG:SERV:NSO " + val)

def calcnf(enrdb, offdb, ondb):
    # Not possible but noisy results may result in it happening
    if ondb <= offdb:
        return 0
    ydb = ondb - offdb
    y = 10 ** (ydb / 10)
    enr = 10 ** (enrdb / 10)
    nf = 10 * math.log10(enr / (y - 1))
    return nf
    
def donoisetest(r, enr):
    print "Acquiring with noise off.."
    setnoise(r, False)
    off = getnoise(r)
    print "Acquiring with noise on.."
    setnoise(r, True)
    on = getnoise(r)
    return off, on, calcnf(enr, off, on)

if __name__ == '__main__':
    parser = optparse.OptionParser(usage = '%prog [options] address frequency')
    parser.add_option('-s', '--span', dest = 'span', default = 1e6, help = 'Span frequency (Hz)', type = float)
    parser.add_option('-i', '--input', dest = 'input', default = None, help = 'Input frequency (Hz) for down converters', type = float)
    parser.add_option('-w', '--sweeps', dest = 'sweeps', default = 20, help = 'Number of sweeps', type = int)

    (options, args) = parser.parse_args()

    if len(args) != 2:
        parser.error('Must supply the specan address and centre frequency')

    addr = args[0]
    try:
        freq = float(args[1])
    except ValueError:
        parser.error('Unable to parse frequency')

    if options.input == None:
        options.input = freq

    # Compute ENR at frequency of interest
    enr = findenr(options.input)

    # Connect to the analyser
    r = rsib.RSIBDevice(addr)

    # ID instrument
    r.write('*IDN?')
    print "ID is " + r.read(5)

    # Setup parameters
    setup(r, freq, options.span, options.sweeps)

    r.write("INIT:CONT OFF")

    while True:
        off, on, nf = donoisetest(r, enr)
        print "Off %.3f dB, on %.3f dB, ENR %.2f, NF %.2f" % (off, on, enr, nf)
        print "Press enter to perform a new measurement"
        sys.stdin.readline()