view logpps.py @ 84:4b4ae555067b

Use RMS detector and fix the sweep time for more accuracy. Add links to app notes discussing theory. Run forever without pause and print a summary on ctrl-c
author Daniel O'Connor <doconnor@gsoft.com.au>
date Thu, 03 Oct 2024 08:57:10 +0930
parents 6ffa6fcf278e
children
line wrap: on
line source

#!/usr/bin/env python

# Copyright (c) 2021
#      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.
#
# Expected DB schema
# CREATE TABLE ppslog (
#   name TEXT,
#   time TIMESTAMP WITH TIME ZONE,
#   delta12 NUMERIC(15, 12),
#   delta13 NUMERIC(15, 12)
# );

import datetime
import numpy
import psycopg2
#import sqlite3
import sys
import time
# Should try this code instead: https://github.com/python-ivi/python-usbtmc
import usb488

def main():
    u = usb488.USB488Device()
    print('Found device')

    # See "TDS2000 Programmer.pdf"
    res = u.ask('*IDN?')
    print('IDN reports ' + res)

    hostname = 'radartest1'
    nchan = 2
    #dbh = sqlite3.connect('logpps.db')
    dbh = psycopg2.connect('host=vm11 user=ppslog dbname=ppslog')
    #dbh = None
    test(u, nchan, dbh, hostname)

def test(u, nchan, dbh = None, name = None):
    if dbh != None:
        cur = dbh.cursor()

    u.write('ACQ:MODE SAMPLE')
    u.write('ACQ:STATE STOP')

    #u.write('DATA:ENC RIB')		# Big endian signed
    #u.write('DATA:WIDTH 2')		# 2 bytes wide

    vscales = []
    for i in range(nchan):
        tmp = float(u.ask('CH%d:SCALE?' % (i + 1)).split()[1])
        vscales.append(tmp)
        print(('Channel %d scale is %.2f volts/div' % (i + 1, tmp)))

    hscale = float(u.ask('HOR:MAIN:SCALE?').split()[1])
    print(('Horizontal scale is %.5f nsec/div' % (hscale * 1e9)))
    # TEK2024B doesn't grok HOR:DIV? so hard code 10 (has 8 vertically)
    acqwindow = hscale * 10.0

    while True:
        arys = acquire(u, vscales)
        #import matplotlib.pylab as pylab
        #for a in arys:
        #    pylab.plot(a)
        #pylab.show()
        sampletime = acqwindow / len(arys[0])
        deltas = []
        for i in range(nchan - 1):
            delta = getpdiffedge(arys[0], arys[i + 1]) * sampletime
            deltas.append(delta)
            print('Delta 1-%d is %.1f nsec' % (i + 2, delta * 1e9))

        if dbh != None:
            now = datetime.datetime.now()
            d12 = deltas[0]
            d13 = None
            if nchan > 2:
                d13 = deltas[1]
            cur.execute('INSERT INTO ppslog(name, time, delta12, delta13) VALUES(%s, %s, %s, %s)', (name, now, d12, d13))
            dbh.commit()

def getchannel(u, ch, vscale):
        u.write('DAT:SOU CH%d' % (ch))	# Set the curve source to desired channel
        result = u.ask('CURVE?', 1.0)	# Ask for the curve data
        data1 = buffer(result[13:])		# Chop off the header (should verify this really..)
        ary = numpy.frombuffer(data1, dtype = '>h')
        ary = ary / 32768.0 * vscale # Scale to volts
        return ary

def acquire(u, vscales):
        u.write('ACQ:STATE 1')	# Do a single acquisition
        u.write('*OPC?')
        u.read(2.0)	# Wait for it to complete

        arys = []
        for i in range(len(vscales)):
            arys.append(getchannel(u, i + 1, vscales[i]))

        return arys

def getpdiffedge(ary1, ary2):
    '''Return phase difference in samples between two signals by edge detection'''

    # Rescale to 0-1
    ary1 = ary1 - ary1.min()
    ary1 = ary1 / ary1.max()
    ary2 = ary2 - ary2.min()
    ary2 = ary2 / ary2.max()

    # Find rising edge of each
    ary1pos = numpy.argmax(ary1 > 0.2)
    ary2pos = numpy.argmax(ary2 > 0.2)

    return ary1pos - ary2pos

if __name__ == '__main__':
    main()