Author Topic: Simple 2 MHz sine generator & Python Bode-plotting script for Picoscope 2204a  (Read 2446 times)

0 Members and 1 Guest are viewing this topic.

Offline jasonRFTopic starter

  • Regular Contributor
  • *
  • Posts: 203
  • Country: us
This beginner-friendly project includes a basic sine-wave generator and a Python script that controls it to make Bode plots with a Picoscope 2204a.  The approach is to use a single frequency per waveform capture, which is slow but maximizes the dynamic range.  Yes, the 2204a already has a built-in signal generator and nice Bode plotting software, but it is limited to 100 kHz while this project is usable up to 5 MHz.   

Both the hardware and software are about as bare-bones as I could make them while still maintaining the required capability to do Bode plots.  I am sharing this in the hopes of getting some  feedback before I start soldering, so other 2204a (and probably 2205a) users can play with it, and because I think some other folks might be able to modify the script to work with other scopes (perhaps SCPI-capable ones). 

This first post will describe the current hardware, and a second post will describe the Python script. 

The sine-wave generator is yet another Arduino-controlled AD9833-based project.   One of my self-imposed constraints is that I wanted a design that is easy to keep stable when implemented on a solderless breadboard.  So no cranky or high-speed op amps in general.  Here are the approximate specs for the breadboarded version in the photo:
* Sine waves only (is trivial to add triangles, but adding square waves is another story)
* AC voltages: 6V peak-to-peak into high-Z; 3V peak-to-peak into 50 Ohms
* DC offset voltages: +/- 4V into high-Z; +/- 2V into 50 Ohms
* 1.6Hz - 2.4 MHz (-3 dB) bandwidth; -8 dB at 5 MHz; not usable beyond 5 MHz
* 50 Ohm output impedance

The schematic is almost exactly what is on the breadboard.  Some notes:
* Power is from a wall-wart 15V AC transformer, leading into the half-wave rectifiers and LM7812/LM1912. 
   I just threw in capacitors that I grabbed from a drawer, and haven't yet calculated what is really needed.
* I am using a Seeeduino Nano board that has a maximum power input of 12V, which is why the rails are 12V.
* A simple common-emitter is used for all of the voltage gain.  Many other  small-signal BJTs
   could also work for Q1 and Q2,  although the biasing is really designed for devices with hfe > 200 or so. 
* The TLE2082cp op amp (10 MHz, 40 V/us, 40 mA/channel output, $4.27 from Digikey) used as an output buffer is approaching both
   slew-rate and current limiting with this design.  The op amp dominates the distortion when driving low-impedance
   loads at high frequencies.  At 2 MHz into 50 Ohms, crossover distortion is easy to see on the waveform. 
* I use an audio-taper 10k pot for amplitude control, and a linear-taper 100k pot with center detent for the DC offset control.
   The SPDT switch enables/disables the DC offset control.   
* the lack of a serious low-pass filter to handle DDS artifacts will scream at some of you.   I did add C2 to
   provide some extra roll-off.  The spectra below
   show that the DDS artifacts near 25MHz are far enough down that they shouldn't interfere with Bode plotting.

Finally, here is the code for the Arduino.  I am using the AD9833 library you can download at https://github.com/Billwilliams1952/AD9833-Library-Arduino
Code: [Select]
#include <AD9833.h>
#define FNC_PIN 10

// simple code to control AD9833 on breakouto board with
// 25 MHz closk.  Accepts desired frequencies in Hz over serial,
// prints the actual frequency to serial.  Only includes
// sine waves for this example.   
//
// On startup the arduino will produce a 1 kHz sine 
//

AD9833 gen(FNC_PIN);

double freq = 1000.00; 
double newFreq = 0;
double actFreq = 0.0;
long dig = 0;
double postDec = 0;
long wavetype = SINE_WAVE;

void setup() {
  // start serial and generator
  Serial.begin(9600);
  gen.Begin();
 
  // have generator output the initial frequency freq
  gen.ApplySignal(wavetype,REG0,freq);
  gen.EnableOutput(true);
  delay(10); 
}

void loop() {
  Serial.flush();

  while (Serial.available() == 0)
  {
  }

  // parse serial inputs to get new desired frequency
  while (Serial.available() > 0)
  { // read one digit at a time
    dig = Serial.read() - '0';
    if (dig == -2) {postDec = 10;}
 
    else if ((dig >=0 ) && (dig <= 9)){
      if (postDec != 0){newFreq = newFreq + dig/postDec;
          postDec = postDec*10;}
        else if (postDec==0)
      {
        newFreq = newFreq * 10;
        newFreq = newFreq + dig;
      }
    delay(10);
  }
}

// apply new frequency
freq = newFreq;
gen.ApplySignal(wavetype,REG0,freq);

     
// read and print the actual frequency, which will be different
// in general.  The printed actual frequency will be read
// by the Python Bode plotting script
actFreq = gen.GetActualProgrammedFrequency(REG0);
Serial.println(actFreq);   

// reset variables for the next frequency
newFreq = 0;
dig = 0;
postDec = 0;
 

}

You will see that at startup it outputs a 1 kHz sine-wave.  After that, it reads the desired frequency (decimal format - no scientific notation) from serial over the usb cable, then writes the actual frequency it is generating back to the serial port.   It is easy to control it using the serial monitor tool built into the Arduino IDE. 

This is the first time I have ever used an Ardino, and since I am just using a downloaded library I would not claim that I know anything at all about them (or any other microcontroller for that matter) beyond the basic idea.  All suggestions or hints  for better ways implement this task would be much appreciated!

Finally, I have included some output waveforms and spectra as measured by a picoscope 5244B.  All measurements use the full 200 MHz bandwidth with 12-bit resolution.  The image filenames indicate the frequency (100 kHz or 1 MHz) and the load (51 Ohms or 10 kOhms). 

Jason
 
The following users thanked this post: ledtester, balnazzar

Offline jasonRFTopic starter

  • Regular Contributor
  • *
  • Posts: 203
  • Country: us
In this post I describe the Python script.   I do not really know Python at all, so it is pretty kludgy.  It requires numpy, picoSDK and the Picotech python wrappers for picoSDk you can download from 
https://github.com/picotech/picosdk-python-wrappers

I run it from Spyder (Anaconda) python 3.9; I don't know what modifications would be required to run it under different versions of Python.
Code: [Select]
# Simple Bode plotting script that uses
# an arduino-controlled AD9833 sine-wave generator
# and a picoscope 2204a.  Will probably work with
# Picoscope 2205a as well. 
#
# The approach is to step through each desired frequency.
# At each frequency, it adjusts the vertical setting,
# then does the measurements. 
#
# Version 0: no bells and whistles.
#
#
# This script is a modification of the ps2000blockExample.py
# script provided by Picotech.  Hence the following
# copyright and licensing information:
#
#
# Copyright © 2018-2019 Pico Technology Ltd.
#
# Permission to use, copy, modify, and/or distribute this
# software for any purpose with or without fee is hereby
# granted, provided that the above copyright notice and
# this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
#


# import stuff
import ctypes
import numpy as np
from picosdk.ps2000 import ps2000 as ps
import matplotlib.pyplot as plt
from picosdk.functions import adc2mV, assert_pico2000_ok
import time
import serial


# USER INPUTS
# =====================================================

# setup picoscope channels
# Note that the trigger level is set to 0V in the
# code, so if using DC coupling you may want to
# modify the trigger level.  I have only really
# tested with AC coupling
chAprobe = 1   # 10 for x10 probe, 1 for x1 probe
chA_DCcouple = 0 # 1 for DCvcoupled, 0 for AC coupled
chBprobe = 1   # 10 for x10 probe, 1 for x1 probe
chB_DCcouple = 0 # 1 for DCvcoupled, 0 for AC coupled

# setup input/output.  Set chAoutput to 1 if chA is
# connected to the output of the DUT; set to 0
# if chA is connected to the input of the DUT
chAoutput = 1; 

# Set frequencies we want for Bode plot.
# For not setup for log-spaced frequencies, but
# is easy to add option for linear-spaced
minfreq = 1
maxfreq = 5e6
freqPerDecade = 7

# specify the COM port for the sine generator
sinePort = 'COM5'

# specify nominal number of samples per period desired
# in scope measurements.  Obviously the 2204a is limited
# to 50 MS/s with both channels running, so at the higher
# frequencies you may get fewer than this.   
sampsPerPeriod = 100;

# Processing
# =====================================================

# make vector of frequencies and pre-allocate gain and phase arrays
numFreqs = round(1 + freqPerDecade*np.log10(maxfreq/minfreq))
allfreq = np.round(100*np.logspace(np.log10(minfreq), np.log10(maxfreq), numFreqs))/100
allgain_dB = np.zeros(len(allfreq))
allphase = np.zeros(len(allfreq))
allvA = 0.0j+np.zeros(len(allfreq))  #peak voltage of chA in Volts
allvB = 0.0j+np.zeros(len(allfreq))  #peak voltage of chB in Volts
actualFreq = np.zeros(len(allfreq))

# startup function gen
# On my computer it is COM5; you may need to
# modify that
ser = serial.Serial()
ser.baudrate = 9600
ser.port = sinePort
ser.open()
ser.flush()

# Create picoscope status ready for use
status = {}

# Open 2000 series PicoScope
# Returns handle to chandle for use in future API functions
status["openUnit"] = ps.ps2000_open_unit()
assert_pico2000_ok(status["openUnit"])

# Create chandle for use
chandle = ctypes.c_int16(status["openUnit"])

# Set up channels A and B
# handle = chandle
# channel: PS2000_CHANNEL_A = 0 and PS2000_CHANNEL_B=1
# enabled = 1
# coupling type = PS2000_DC = 1
# range = PS2000_5V = 8
# analogue offset = 0 V
#
# voltage ranges:1=20mV, 2=50mV, 3=100mV, 4=200mV,
#                5=500mV, 6=1V, 7=2V, 8=5V, 9=10V, 10=20V
 
chARange = 8
status["setChA"] = ps.ps2000_set_channel(chandle, 0, 1, chA_DCcouple, chARange)
assert_pico2000_ok(status["setChA"])

chBRange = 8
status["setChB"] = ps.ps2000_set_channel(chandle, 1, 1, chB_DCcouple, chBRange)
assert_pico2000_ok(status["setChB"])

# Set up edge trigger with threshold at 0 volts
# handle = chandle
# source = 0 for channel A or 1 for channel B
# threshold = 0  (needs to be between -32767 and +32767)
# direction = PS2000_RISING = 0
# delay = 0 s
# auto Trigger = 1000 ms
triggerThresh = 0
if chAoutput==1:
    triggerChannel = 1  # trigger on B
else:
    triggerChannel = 0  # trigger on A
status["trigger"] = ps.ps2000_set_trigger(chandle, triggerChannel, triggerThresh, 0, 0, 1000)
assert_pico2000_ok(status["trigger"])

# Set number of pre and post trigger samples to be collected
# hard-coded to use 2000 samples.  For some reason get
# errors when trying to use 4000 samples...
preTriggerSamples = 1000
postTriggerSamples = 1000
maxSamples = preTriggerSamples + postTriggerSamples

# define simple function used in my crude vertical 'autoset'
def checkVertical(minBuffer, maxBuffer, lowThresh, highThresh, chRange):
    if maxBuffer<highThresh and minBuffer>-highThresh:
        highVoltage = False
    else:
        highVoltage = True
     
    if maxBuffer<lowThresh and minBuffer>-lowThresh:
        underflow = True
    else:
        underflow = False
 
    if highVoltage and chRange == 10:
        highVoltage = False
        underflow = False
        print("Signal is Big")
    elif highVoltage and chRange < 10:
        print("increasing vertical scale")
        chRange = chRange + 1
    elif underflow and chRange > 2:
        print("decreasing  vertical scale")
        chRange = chRange - 1
    elif underflow and chRange == 2:
        print("signal is small")
        highVoltage = False
        underflow = False
   
    return underflow, highVoltage, chRange




# main loop over allfreq.  Does high freq first
# since collection times are shorter and so it
# takes much less time to 'autoset' the amplitude.
# Unless there is a narrow resonance or something,
# the amplitude change frequency-to-frequency
# is often small. 
for k in range(len(allfreq)-1, -1, -1):

    approxFreq = allfreq[k]   # frequency
   
    # set function generator to the desired frequency
    ser.write(str(approxFreq).encode('ascii'))
    time.sleep(0.5)    #to give time for frequency change
    tmpActFreq = str(ser.readline())
    actualFreq[k] = np.double(tmpActFreq[2:][:-5])

    print('processing frequency '+str(k+1)+' of '+str(len(allfreq))+' (ask for '+str(approxFreq)+' Hz, get '+str(actualFreq[k])+' Hz)')
   
    # set timebase.  2204a sample rate = 100 MS/s / 2^timebease
    tmptimebase = np.log2(100e6 / (sampsPerPeriod*approxFreq))
    timebase = int(np.floor(tmptimebase))
    if timebase<1:   # if asking for > 50 MS/s sample rate
    timebase = 1 # set sample rate to 50 MS/s
   
    # Get timebase information
    # handle = chandle
    # timebase
    # no_of_samples = maxSamples
    # pointer to time_interval = ctypes.byref(timeInterval)
    # pointer to time_units = ctypes.byref(timeUnits)
    # oversample = 1 = oversample
    # pointer to max_samples = ctypes.byref(maxSamplesReturn)
    timeInterval = ctypes.c_int32()
    timeUnits = ctypes.c_int32()  #pointer
    oversample = ctypes.c_int16(1)
    maxSamplesReturn = ctypes.c_int32()
    status["getTimebase"] = ps.ps2000_get_timebase(chandle, timebase, maxSamples, ctypes.byref(timeInterval), ctypes.byref(timeUnits), oversample, ctypes.byref(maxSamplesReturn))
    assert_pico2000_ok(status["getTimebase"])
   
    # Run block capture
    # handle = chandle
    # no_of_samples = maxSamples
    # timebase = timebase
    # oversample = oversample
    # pointer to time_indisposed_ms = ctypes.byref(timeIndisposedms)
    timeIndisposedms = ctypes.c_int32()
    status["runBlock"] = ps.ps2000_run_block(chandle, maxSamples, timebase, oversample, ctypes.byref(timeIndisposedms))
    assert_pico2000_ok(status["runBlock"])
   
    # Check for data collection to finish using ps2000_ready
    ready = ctypes.c_int16(0)
    check = ctypes.c_int16(0)
    while ready.value == check.value:
        status["isReady"] = ps.ps2000_ready(chandle)
        ready = ctypes.c_int16(status["isReady"])
   
    # Create buffers ready for data
    bufferA = (ctypes.c_int16 * maxSamples)()
    bufferB = (ctypes.c_int16 * maxSamples)()
   
    # Get data from scope
    # handle = chandle
    # pointer to buffer_a = ctypes.byref(bufferA)
    # pointer to buffer_b = ctypes.byref(bufferB)
    # poiner to overflow = ctypes.byref(oversample)
    # no_of_values = cmaxSamples
    cmaxSamples = ctypes.c_int32(maxSamples)
    status["getValues"] = ps.ps2000_get_values(chandle, ctypes.byref(bufferA), ctypes.byref(bufferB), None, None, ctypes.byref(oversample), cmaxSamples)
    assert_pico2000_ok(status["getValues"])
   
    # find maximum ADC count value
    maxADC = ctypes.c_int16(32767)
    madc = 32767
   
    # check to see if voltages fit nicely into vertical scale
    underflowA, highVoltageA, chARange = checkVertical(np.min(bufferA), np.max(bufferA), .2*madc, .8*madc, chARange)
    underflowB, highVoltageB, chBRange = checkVertical(np.min(bufferB), np.max(bufferB), .2*madc, .8*madc, chBRange)
       
       
    # iterate until have best vertical scale setting that works for the
    # these signals
    while highVoltageA or underflowA or highVoltageB or underflowB:
               
           # setup channels to new vertical scales
           status["setChA"] = ps.ps2000_set_channel(chandle, 0, 1, chA_DCcouple, chARange)
           assert_pico2000_ok(status["setChA"])
           status["setChB"] = ps.ps2000_set_channel(chandle, 1, 1, chB_DCcouple, chBRange)
           assert_pico2000_ok(status["setChB"])
           status["runBlock"] = ps.ps2000_run_block(chandle, maxSamples, timebase, oversample, ctypes.byref(timeIndisposedms))
           assert_pico2000_ok(status["runBlock"])
           ready = ctypes.c_int16(0)
           check = ctypes.c_int16(0)
           while ready.value == check.value:
                   status["isReady"] = ps.ps2000_ready(chandle)
                   ready = ctypes.c_int16(status["isReady"])
                   
           # get picoscope data       
           status["getValues"] = ps.ps2000_get_values(chandle, ctypes.byref(bufferA), ctypes.byref(bufferB), None, None, ctypes.byref(oversample), cmaxSamples)
           assert_pico2000_ok(status["getValues"])
           

           # check to see if voltages fit nicely into vertical scale
           underflowA, highVoltageA, chARange = checkVertical(np.min(bufferA), np.max(bufferA), .2*madc, .8*madc, chARange)
           underflowB, highVoltageB, chBRange = checkVertical(np.min(bufferB), np.max(bufferB), .2*madc, .8*madc, chBRange)

    # at this point should have data with best vertical scale setting!
   
    # convert ADC counts data to mV
    adc2mVChA =  adc2mV(bufferA, chARange, maxADC)
    adc2mVChB =  adc2mV(bufferB, chBRange, maxADC)
   
    # scale according to channel probe setting
    datA = chAprobe * np.array(adc2mVChA)
    datB = chBprobe * np.array(adc2mVChB)
       
    # Create time data
    timetag = np.linspace(0, (cmaxSamples.value -1) * timeInterval.value, cmaxSamples.value)
       
    # Use single Fourier filter to compute complex voltage estimates
    fwin = np.blackman(maxSamples)   #window
    ee = np.exp(-2j*np.pi*actualFreq[k]*timetag*1e-9)/np.sum(fwin)
    vA = 2*np.sum(fwin*ee*(datA-np.mean(datA)))   #peak amplitude in mV
    vB = 2*np.sum(fwin*ee*(datB-np.mean(datB)))   #peak amplitude in mV
    allvA[k] = vA/1000   # /1000 to get Volts peak
    allvB[k] = vB/1000   # /1000 to get Volts peak
   
    # compute gain and phase for this frequency
    pA = abs(vA)*abs(vA)
    pB = abs(vB)*abs(vB)
    pAB = vA * vB.conjugate();

    if chAoutput==1:
        sgn = 1
    else:   
        sgn = -1
    allgain_dB[k] = sgn*10*np.log10(pA/pB)
    allphase[k] = sgn*np.angle(pAB)*180/np.pi
       


# plot voltages
fig, cc = plt.subplots(2)
fig.suptitle('Voltages')
cc[0].loglog(actualFreq, abs(allvB)*2)
cc[0].set_ylabel('CH B Vpp')
cc[0].grid()
cc[1].loglog(actualFreq, abs(allvA)*2)
cc[1].set_ylabel('CH A Vpp')
cc[1].grid()
cc[1].set_xlabel('Frequency (Hz)')

# plot Bode plot
minplotgain = np.min(np.floor(allgain_dB/10)*10)
maxplotgain = np.max(np.ceil(allgain_dB/10)*10)
minplotphase = np.min(np.floor(allphase/15)*15)
maxplotphase = np.max(np.ceil(allphase/15)*15)
ng = np.round(1 + (maxplotgain-minplotgain)/10)
nph = np.round(1 + (maxplotphase-minplotphase)/15)
fig, aa = plt.subplots(2)
fig.suptitle('Bode Plot from 2204a and Arduino+AD9833FG')
aa[0].semilogx(actualFreq, allgain_dB)
aa[0].set_ylabel('Gain (dB)')
aa[0].set_yticks(np.linspace(minplotgain, maxplotgain, int(ng)))
aa[0].grid()
aa[1].semilogx(actualFreq, allphase)
aa[1].set_ylabel('Phase (deg)')
aa[1].set_xlabel('Frequency (Hz)')
aa[1].set_yticks(np.linspace(minplotphase, maxplotphase, int(nph)))
aa[1].grid()
fig

# Stop the scope
# handle = chandle
status["stop"] = ps.ps2000_stop(chandle)
assert_pico2000_ok(status["stop"])

# Close unitDisconnect the scope
# handle = chandle
status["close"] = ps.ps2000_close_unit(chandle)
assert_pico2000_ok(status["close"])

# display status returns
print(status)

# close connection to function gen
ser.close()



The script has 4 main parts:
1. parameter input and instrument initialization. In particular, you will need to setup the
   probe settings (x1 or x10), the desired frequency range, number of frequencies to
   use, and which COM port the sine-wave generator is connected to. 
2. The main loop over the different frequencies of interest.  For each frequency
   a. command the function generator to produce that frequency
   b. read the actual frequency the function generator is trying to produce.  Especially at the lower
      frequencies this can be somewhat different that what you ask for (AD9833 with 25 MHz
      oscillator has about 0.09 Hz resolution).
   c. setup the time-base of the scope channels, which is easy because we know the frequency.
      The script nominally selects the time-base so that there are 100 samples per period,
      although above 500 kHz there will be fewer (2204a max sample rate is 50 MS/s with both channels running) 
   d. adjust the vertical settings of each channel if needed.   My initial approach is crude but seems to work.
   e. Collect the measurements from the two channels.
   f. Estimate gain and phase offset, using Fourier analysis to just extract the frequency of interest
3. Make 2 plots: the first is of the voltages of the two scope channels, and hte second is the Bode plot. 
   In general you will need to muck with the plots further to make them look pretty.
4. close the connections to the instruments.   


Since the 2205a and 2204a use the same picoSDK drivers, I suspect the code will work for the 2205a as-is, although the time-base setup may need to be changed to take advantage of the higher sample rate that the 2205 supports. 

Below there are Bode plots for two different DUTs: a simple low-pass filter and a portable discrete headphone amplifier I made 10+ years ago (before I owned a scope) that has much wider bandwidth than I expected.   For the low-pass filter I include both the channel voltage plot and the Bode plot using this project.  For the headphone amplifier I include the Bode plot generated using this project, as well as one generated using the 5244B and FRA4Picoscope; since both scopes/methods yield about the same results I think I didn't screw anything up too badly!

In case it is helpful, I am also attaching a Python script that I use for easy control of the frequency when I am using the Picoscope
software for the scope
Code: [Select]
# script to send frequencies to arduino ad9833
import serial
ser = serial.Serial()
ser.baudrate = 9600
ser.port = 'COM5'
ser.timeout = 5   # timeout in seconds
ser.open()
# oldlines = ser.readlines();
# print(oldlines)
newfreq = 1000
lastline = ser.readline();
# 2020print(lastline)
# ser.close()
newfreq = input("enter a new frequency in Hz (or 0 to stop): ")

while newfreq != 0:
    ser.write(str(newfreq).encode('ascii'))
    time.sleep(0.5)    #to give time for frequency change
    tmpActFreq = str(ser.readline())
    print('   Generating '+str(tmpActFreq)+' Hz')
    newfreq = input("enter a new frequency (or 0 to stop): ")
print("done")   
ser.close()




Finally, in case some noob readers aren't familiar with how these measurements are setup, here is how you would use this:
1. connect the ouptut of the function generator to the input of the device under test (DUT)
2. If needed, add an output load to the DUT
3. connect one scope channel to the input of the DUT, and the other scope channel to the output
   of the DUT.   The scripts let you specify which channel is input and which is output
4. Make sure your probes are set to where you want (x1, x10) and modify the
   script accordingly.
5. You might want to do a few basic tests using the scope's original software to ensure that the
   voltage level you are using from the signal generator is fine with the DUT
   (doesn't saturate it somehow, or isn't a lot smaller than it needs to be, or doesn't draw too much
   current from the sine-wave generator and make it distorted, etc.)
   For this, I use either the second Python script above or the serial port monitor tool that is in the
   Arduino IDE to control the frequency.
   of the sine generator and spot check over the frequency range of interest to make sure that
   the amplitude and DC offset controls are set so that everything looks okay.  Once everything
   is set, either have the picoscope software disconnect from the scope, or close the software
   altogether. 
6. run the python script


Jason
« Last Edit: November 04, 2022, 01:31:15 am by jasonRF »
 

Offline balnazzar

  • Frequent Contributor
  • **
  • Posts: 417
  • Country: it
Thanks Jason. Interesting stuff!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf