信号发生器:汉泰克1025G
SDK开发资料:http://www.hantek.com.cn/products/detail/48
1.python接口
网上已经有大神制作了python的封装接口:https://github.com/AIMAtlanta/Hantek_1025G
这里为了方便查找就再张贴一遍:
# -*- coding: utf-8 -*-
"""
origin source: https://github.com/AIMAtlanta/Hantek_1025G
Python wrapper providing access to C-language API provided by HTDDSDll.h.
Example usage:
ht = HantekDDS()
ht.drive_periodic(amplitude=2.0, frequency=12000., function = 'sine')
"""
import ctypes
import os
import numpy as np
import threading
import time
import matplotlib.pyplot as plt
this_dir = os.path.dirname(os.path.realpath(__file__))
HTDLL = ctypes.windll.LoadLibrary(this_dir + '/HTDDSDll')
FMAX = 200e6 # Maximum DAC sample rate
class HantekDDS():
""" Interface to Hantek 1025G function generator."""
def __init__(self, dev=0):
""" Default constructor."""
self.idVendor = '0x0483'
self.idProduct = '0x5726'
self.revNumber = '0200'
self.dev_id = None
self.connect(dev)
self.param_dict = {
'square_duty': 0.5,
'triangle_duty': 0.5,
'trap_rise': 0.2,
'trap_high': 0.3,
'trap_fall': 0.2,
'exp_mode': 'decay',
'exp_time': 0.001,
}
self.halt = False
def connect(self, dev=0):
""" Verify existence of device and get device id."""
for attempt in range(10):
n_devices = search()
if n_devices:
if bool(check(dev)):
self.dev_id = dev
print('Connected as device {:d}'.format(dev))
return
print('ERROR: Failed to establish connection with HantekDDS.')
def set_divisor(self, div):
""" Set the DAC sample rate divisor."""
setDivNum(self.dev_id, div)
def set_waveform(self, data):
""" Set the waveform buffer."""
data = np.array(data) # Ensure data is in ndarray
dlen = len(data)
if dlen > 4096:
print('WARNING: Hantek 1025G buffer limited to 4096 samples -- ' +
'Truncating data to 4096 elements')
data = data[:4096]
if download(self.dev_id, data.tobytes(), dlen):
pass
else:
print('HantekDDS method set_waveform() returned failure code.')
def drive_periodic(self, amplitude=1.0, frequency=1000.0,
offset=0, phase=0, function='sine', **kwargs):
""" Direct the device to drive a periodic function.
Args:
amplitude: Amplitude of signal in Volts (1/2 V_pp)
frequency: Frequency of signal in Hertz
offset: Offset of signal in Volts.
phase: Offset of phase in periods (phase = 0 is equivalent to
phase=1, phase = 0.5 is 180 degrees out of phase from phase = 0.
function: Type of periodic function to drive.
Valid Types
-----------
'sine': Sine wave
'square': Square wave, param 'square_duty' for high duty cycle
specified as float in range (0,1)
'triangle': Triangle wave, param 'duty' for rise duty cycle
specified as float in range (0,1)
'ramp': Synonym for 'triangle'
'sawtooth': Synonym for 'triangle'
'trap': Trapezoidal wave, params 'trap_rise', 'trap_high',
and 'trap_fall' for duty cycle for rise, high, and fall
segments specified as floats > 0 with sum <= 1.
'exp': Exponential wave, params 'exp_mode' (may be 'rise' or
'saturate') and 'exp_time' (time constant in seconds).
"""
for key,val in kwargs.items():
if key in self.param_dict:
self.param_dict[key] = val
frequency = validate_frequency(frequency)
phase = phase % 1
if (amplitude + abs(offset)) > 3.5:
print('WARNING: amplitude and offset specified will cause ' +
'the signal to be clipped. Consider confining the range ' +
'to ±3.5 volts.')
if function not in periodic_functions.keys():
print('WARNING: function type for periodic function not found. ' +
'Valid values are ' +
'Defaulting to sine wave.')
function = 'sine'
div, length = get_freq_settings(frequency)
print(f'freq:{
frequency}, div:{
div}, length:{
length}')
f = periodic_functions[function]
signal = f(amplitude, frequency, offset, phase,
length, **(self.param_dict))
digital = np.short(voltage_adc(signal))
print(digital)
self.set_waveform(digital)
self.set_divisor(div)
def frequency_scan(self, f_start, f_end, nsteps=10, delta=0, dwell=5,
ltype='linear', n_repeats=1, amplitude=1.0, offset=0.0):
""" Scan through a range of frequencies.
Args:
f_start: Scan starting frequency in Hertz
f_end: Scan ending frequency in Hertz
nsteps: The number of steps to take between f_start and f_end.
delta: The arithmetic or geometric difference between steps.
If non-zero, this setting will override nsteps.
Additionally, the frequency sweep may go past f_end.
n_repeats: The number of times to loop through the entire frequency
scan. Set to -1 to make continuous.
"""
f_start = validate_frequency(f_start)
f_end = validate_frequency(f_end)
if ltype in ['log', 'logarithmic']:
if delta > 0:
nsteps = np.ceil(np.log(f_end / f_start) / np.log(delta))
fspace = np.product(np.append(f_start, delta*np.ones(nsteps)))
else:
fspace = np.logspace(np.log10(f_start),
np.log10(f_end), nsteps)
if ltype in ['lin', 'linear']:
if delta != 0:
fspace = np.arange(f_start, f_end + delta, delta)
else:
fspace = np.linspace(f_start, f_end, nsteps)
fspace = np.linspace(f_start, f_end, nsteps)
self.scanner = threading.Thread(target=self.freq_scan_threaded,
args=(fspace, amplitude,
offset, dwell, n_repeats))
self.halt = False
self.scanner.start()
# self.freq_scan_threaded(fspace, amplitude, offset, dwell, n_repeats)
def freq_scan_threaded(self, fspace, amp, offset, dwell, n_repeats):
""" Frequency scan to be started in non-blocking threaded process."""
queue = int(n_repeats)
while queue != 0:
queue -= 1
for f in fspace:
if self.halt:
return None
self.drive_periodic(amplitude=amp, frequency=f, offset=offset)
time.sleep(dwell)
def stop(self):
""" Halt the threaded scan process."""
self.halt = True
def search():
""" Search for connected Hantek DDS devices.
Will not return identity of devices, only the number connected.
"""
fh = HTDLL[7] # function handle for DDSSearch()
return fh()
def setFrequency(dev, f, npoints, nperiods):
""" Set parameters appropriate for a particular frequency.
Args:
f: frequency to be set
"""
fh = HTDLL[11]
return fh(dev, f, npoints, nperiods)
def getMeasure():
""" Retrie