Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • whuie2/awg-control
  • xiyehu2/awg-control
2 results
Show changes
Commits on Source (26)
......@@ -34,7 +34,7 @@ class AWG:
self.ch_amp = [0,0,0,0] # channel output amplitude
self.mode = "" # current mode AWG is running on
def open(self, remote=False):
def open(self, remote=False, id=b'/dev/spcm0'):
"""
opens and initializes instance variables
:param remote: flag to determine remote connection, default is False
......@@ -42,7 +42,7 @@ class AWG:
if remote:
self.card = spcm_hOpen(create_string_buffer(b'TCPIP::192.168.1.10::inst0::INSTR'))
else:
self.card = spcm_hOpen(create_string_buffer(b'/dev/spcm0'))
self.card = spcm_hOpen(create_string_buffer(id))
if self.card is None:
sys.stdout.write("no card found...\n")
else:
......@@ -54,13 +54,14 @@ class AWG:
spcm_dwGetParam_i32(self.card, SPC_MIINST_MAXADCVALUE,
byref(self.full_scale)) # full scale value for data generation purpose
name = szTypeToName(self.card_type.value)
sys.stdout.write("Found: {0} sn {1:05d}\n".format(name, self.serial_number.value))
sys.stdout.write("Sample Rate: {:.1f} MHz\n".format(self.sample_rate.value / 1000000))
sys.stdout.write("Memory size: {:.0f} MBytes\n".format(self.mem_size.value / 1024 / 1024))
self.check_error()
sys.stdout.write("Card: {0} sn {1:05d}\n".format(name, self.serial_number.value))
sys.stdout.write("Max sample Rate: {:.1f} MHz\n".format(self.sample_rate.value / 1000000))
sys.stdout.write("Memory size: {:.0f} MBytes\n\n".format(self.mem_size.value / 1024 / 1024))
# self.check_error()
def close(self):
spcm_vClose(self.card)
print("AWG is closed")
def check_error(self, message="") -> bool:
"""
......@@ -68,23 +69,21 @@ class AWG:
:param message: caller defined string for debugging purposes
:return: 1 if error is found, 0 otherwise
"""
flag = 0
msg = "Checking error at " + message + " ... "
if message != "":
flag = 1
sys.stdout.write(msg)
err_reg = uint32(0)
err_val = int32(0)
err_text = ''
err_text = ""
err_code = spcm_dwGetErrorInfo_i32(self.card, byref(err_reg), byref(err_val), err_text)
if err_code:
if flag:
sys.stdout.write(err_text)
else:
sys.stdout.write(msg + err_text)
print(
f"{message}\n"
f"error code (see spcerr.py): {hex(err_code)}\n"
# f"error text: {err_text}"
f"error register: {err_reg.value}\n"
f"error val: {err_val.value}\n"
)
self.close()
exit(0)
return True
elif flag:
sys.stdout.write("no error\n")
return False
def run(self):
......@@ -93,27 +92,28 @@ class AWG:
"""
spcm_dwSetParam_i32(self.card, SPC_M2CMD,
M2CMD_CARD_START | M2CMD_CARD_ENABLETRIGGER)
self.check_error()
# self.check_error("Checking error at run")
def stop(self):
"""
stop the card, this is different from closing the card
"""
spcm_dwSetParam_i32(self.card, SPC_M2CMD, M2CMD_CARD_STOP)
self.check_error()
# self.check_error("Checking error at stop")
def reset(self):
"""
resets the board, this clears all onboard memory and settings
"""
spcm_dwSetParam_i32(self.card, SPC_M2CMD, M2CMD_CARD_RESET)
# self.check_error("Checking error at reset")
def force_trigger(self):
"""
force a trigger event, this completely mimics an actual trigger event
"""
spcm_dwSetParam_i32(self.card, SPC_M2CMD, M2CMD_CARD_FORCETRIGGER)
self.check_error()
# self.check_error("Checking error at force_trigger")
def set_sampling_rate(self, sr: int):
"""
......@@ -122,9 +122,10 @@ class AWG:
"""
self.sample_rate = int64(sr)
spcm_dwSetParam_i64(self.card, SPC_SAMPLERATE, sr)
self.check_error()
# self.check_error("Checking error at set_sampling_rate")
print(f"Setting sampling rate to {self.sample_rate.value / 1e6} MHz")
def enable_channel(self, ch: int, amplitude: int=1000, stoplvl: str="ZERO"):
def toggle_channel(self, ch: int, amplitude: int=1000, stoplvl: str="ZERO"):
"""
enable/disable individual channel and set its parameters
:param ch: enables channel 0-3.
......@@ -142,37 +143,12 @@ class AWG:
spcm_dwSetParam_i64(self.card, SPC_CHENABLE, int64(2**ch)) # see CHANNEL0-3 in regs.py for detail
spcm_dwSetParam_i32(self.card, SPC_ENABLEOUT0 + ch * (SPC_ENABLEOUT1 - SPC_ENABLEOUT0), 1)
spcm_dwSetParam_i32(self.card, SPC_AMP0 + ch * (SPC_AMP1 - SPC_AMP0), amplitude)
spcm_dwSetParam_i32(self.card, SPC_CH0_STOPLEVEL + ch * (SPC_CH1_STOPLEVEL - SPC_CH0_STOPLEVEL),
stopmask[stoplvl])
spcm_dwSetParam_i32(self.card, SPC_CH0_STOPLEVEL + ch * (SPC_CH1_STOPLEVEL - SPC_CH0_STOPLEVEL), stopmask[stoplvl])
else:
self.channel[ch] = 0
spcm_dwSetParam_i32(self.card, SPC_ENABLEOUT0 + ch * (SPC_ENABLEOUT1 - SPC_ENABLEOUT0), 0)
self.check_error()
# Deprecated
# def set_channel(self, ch: list, amplitude: list=(1000,1000,1000,1000), stoplvl: list=(16,16,16,16)):
# """
# set and enable channel outputs, max number of channel is 4
# :param ch: enables channel 0-3.
# Example: [0,1,0,1] enables channel 1 and 3.
# :param amplitude: sets output amplitude of each channel between 80-2500mV, default level is 1000mV.
# Example: [80,1000,0,0] sets output level for channel 0 and 1 to be 80 and 1000 mV.
# :param stoplvl: sets channels pause behavior, ZERO = 16, LOW = 2, HIGH = 4, HOLDLAST = 8.
# Example: [16, 2, 8, 8]
# """
# self.channel = ch
# mask = (CHANNEL0 & 1 * ch[0]) | \
# (CHANNEL1 & 2 * ch[1]) | \
# (CHANNEL2 & 4 * ch[2]) | \
# (CHANNEL3 & 8 * ch[3]) # create channel mask
# spcm_dwSetParam_i64(self.card, SPC_CHENABLE, int64(mask)) # activate channels
# for i in range(4):
# # enable channel outputs, set output amplitudes and pause behavior
# if ch[i] == 0: continue
# spcm_dwSetParam_i32(self.card, SPC_ENABLEOUT0 + i * (SPC_ENABLEOUT1 - SPC_ENABLEOUT0), 1)
# spcm_dwSetParam_i32(self.card, SPC_AMP0 + i * (SPC_AMP1 - SPC_AMP0), amplitude[i])
# spcm_dwSetParam_i32(self.card, SPC_CH0_STOPLEVEL + i * (SPC_CH1_STOPLEVEL - SPC_CH0_STOPLEVEL), stoplvl[i])
# self.check_error()
# self.check_error("Checking error at enable_channel")
print("Channels enabled: ", self.channel)
def set_trigger(self, **kwargs):
"""
......@@ -188,19 +164,19 @@ class AWG:
if key == "EXT1":
spcm_dwSetParam_i32(self.card, SPC_TRIG_ORMASK, SPC_TMASK_EXT1) # using external channel 1 as trigger
spcm_dwSetParam_i32(self.card, SPC_TRIG_EXT1_MODE, value)
self.check_error()
# self.check_error("Checking error at set_trigger")
def get_aligned_array(self, size):
def get_aligned_buf(self, size):
"""
returns a numpy array at a page-aligned memory location
:param size: number of samples used for data calculation
:return: numpy array starting at the correct location
:return:
"""
data_length_bytes = uint32(size * 2 * np.sum(self.channel))
data_length_bytes = int(size * 2 * np.sum(self.channel))
buffer = pvAllocMemPageAligned(data_length_bytes) # buffer now holds a page-aligned location
buffer_data = cast(addressof(buffer), ptr16) # cast it to int16 array
array = np.frombuffer(buffer_data, dtype=int16)
return array
# array = np.frombuffer(buffer_data, dtype=int16)
return buffer, buffer_data
def set_sequence_mode(self, nseg: int):
"""
......@@ -208,35 +184,42 @@ class AWG:
:param nseg: number of segments the memory is divided into, must be powers of 2.
"""
self.mode = "Sequence Replay"
spcm_dwSetParam_i32(self.card, SPC_CARDMODE, SPC_REP_STD_SEQUENCE) # Sequence replay mode
spcm_dwSetParam_i32(self.card, SPC_SEQMODE_MAXSEGMENTS,nseg) # set number of sequences the memory is divided into
self.check_error()
spcm_dwSetParam_i32(self.card, SPC_CARDMODE, SPC_REP_STD_SEQUENCE) # Sequence replay mode
spcm_dwSetParam_i32(self.card, SPC_SEQMODE_MAXSEGMENTS, nseg) # set number of sequences the memory is divided into
spcm_dwSetParam_i32(self.card, SPC_SEQMODE_STARTSTEP, 0) # set starting step to be 0
# self.check_error("Checking error at set_sequence_mode")
def write_segment(self, data: np.ndarray, segment: int):
"""
write data onto a specified segment.
write data onto a specified segment in sequence replay mode
:param data: numpy array containing waveform data
:param segment: the segment to write on
:return:
"""
if self.mode != "Sequence Replay":
print("Wrong method, current mode is: " + self.mode)
return
nch = np.sum(self.channel) # number of activated channels
if data.dtype != int:
sys.stdout.write("data must be in int type\n")
return
if data.size > self.mem_size.value / np.sum(self.channel) / SPC_SEQMODE_MAXSEGMENTS:
sys.stdout.write("data is big")
# if data.dtype != int:
# sys.stdout.write("data must be in int type\n")
# return
if data.size > self.mem_size.value / np.sum(self.channel) / 2:
sys.stdout.write("data is too big")
return
spcm_dwSetParam_i32(self.card, SPC_SEQMODE_WRITESEGMENT, segment) # set current segment to write on
spcm_dwSetParam_i32(self.card, SPC_SEQMODE_SEGMENTSIZE, data.size) # set size of segment in unit of samples
# data transfer
ptr = data.ctypes.data_as(POINTER(int16))
buflength = data.size * 2 * nch # samples * (2 bytes/sample) * number of activated channels
spcm_dwDefTransfer_i64(self.card, SPCM_BUF_DATA, SPCM_DIR_PCTOCARD, int32(0), ptr, int64(0), buflength)
sample_len = data.size
buflength = uint32(sample_len * 2 * nch) # samples * (2 bytes/sample) * number of activated channels
data_ptr = data.ctypes.data_as(ptr16) # cast data array into a c-like array
buffer = pvAllocMemPageAligned(sample_len * 2) # buffer now holds a page-aligned location
buffer_data = cast(addressof(buffer), ptr16) # cast it to int16 array
memmove(buffer_data, data_ptr, sample_len * 2) # moving data into the page-aligned block
spcm_dwDefTransfer_i64(self.card, SPCM_BUF_DATA, SPCM_DIR_PCTOCARD, int32(0), buffer, int64(0), buflength)
spcm_dwSetParam_i32(self.card, SPC_M2CMD, M2CMD_DATA_STARTDMA | M2CMD_DATA_WAITDMA)
self.check_error()
# self.check_error("Checking error at write_segment")
def configure_step(self, step: int, segment: int, nextstep: int, loop: int, condition: int):
"""
......@@ -253,5 +236,5 @@ class AWG:
return
mask = (condition << 32) | (loop << 32) | (nextstep << 16) | segment # 64-bit mask
spcm_dwSetParam_i64(self.card, SPC_SEQMODE_STEPMEM0 + step, mask)
self.check_error()
# self.check_error("Checking error at configure_step")
from waveform import *
import cupy as cp
from cupyx.profiler import benchmark
# data = np.load("data/rearrange_table_11.npz", allow_pickle=True)
# table = data['path_table']
# twzr = data['wfm'].item()
# t = np.zeros(11)
# t[:5] = 1
# t_idx = np.nonzero(t)[0]
# f = np.zeros(11)
# f[:6] = 1
# table_cp = cp.array(table)
# for i in range(1000):
# np.random.shuffle(f)
# f_idx = np.nonzero(f)[0]
# paths = cp.array(get_rearrange_paths(t_idx, f_idx))
# b = benchmark(create_moving_array_gpu, (table_cp, paths), n_repeat=1)
# print(b.gpu_times)
t = np.array([1,1,0,1,0])
f = np.array([0,1,0,1,1])
t = np.nonzero(t)[0]
f = np.nonzero(f)[0]
print(get_rearrange_paths(t, f))
from AWG import *
import code
import readline
import rlcompleter
def trigger():
global awg
awg.force_trigger()
print("forcing a trigger...")
def stop():
global awg
awg.stop()
print("stopping awg output...")
def start():
global awg
awg.run()
awg.force_trigger()
print("starting awg output...")
def close():
global awg
awg.close()
print("closing awg and quitting...")
exit(0)
# load waveform data
wfm_data = np.load("data/single.npz", allow_pickle=True)
static_sig = wfm_data['signal']
empty = np.zeros(static_sig.shape)
wfm = wfm_data['wfm'].item()
sampling_rate = wfm.sample_rate
# AWG stuff
awg = AWG()
awg.open(id=b'/dev/spcm1') # change this to b'/dev/spcm0' for top AWG
awg.set_sampling_rate(sampling_rate)
awg.toggle_channel(0, amplitude=2500)
awg.set_trigger(EXT0=SPC_TM_POS)
awg.set_sequence_mode(2)
awg.write_segment(static_sig, segment=0)
awg.write_segment(empty, segment=1)
awg.configure_step(step=0, segment=0, nextstep=1, loop=1, condition=SPCSEQ_ENDLOOPONTRIG)
awg.configure_step(step=1, segment=1, nextstep=0, loop=1, condition=SPCSEQ_ENDLOOPONTRIG)
# console
vars = globals()
vars.update(locals())
readline.set_completer(rlcompleter.Completer(vars).complete)
readline.parse_and_bind("tab: complete")
code.InteractiveConsole(vars).interact()
import numpy as np
from waveform import *
from waveform_plots import *
np.random.seed(0)
cf = MEGA(105) # center frequency
df = MEGA(2.5) # delta frequency
n = 2 # number of tones to generate in either direction of cf, total number of tweezer is 2*n+1
nt = 2*n+1 # total number of tweezers
fr = KILO(10)
# # sampling_rate and sample_len must follow some relationship explained in the wiki page.
sampling_rate = int(614.4e6) # sampling rate
# sample_len = 512 * 600 # sample_len
twzr = Waveform(cf, df, n, sampling_rate, fr)
# amplitude uniformity adjustments, just make sure its called amps at the end
# scale = 2**12
# ampMax = scale/np.sqrt(nt)
# amps = ampMax * np.ones(nt)
# corr = np.array([1.53312825, 1.35073669, 1.252971, 1.06263741, 1.])
# amps *= np.sqrt(corr)
# phase adjustments
# phase = np.load("array_phase.npz")['phase'][:nt] # phase table from Caltech
# twzr.amplitude = amps
# twzr.phi = phase
# static_sig = create_static_array(twzr, sample_len)
# empty = np.zeros(sample_len)
# table = create_path_table(twzr, save=True)
# data = np.load("data/rearrange_table_11.npz", allow_pickle=True)
# table = data['path_table']
# twzr = data['wfm'].item()
# target = np.array([1,1,1,1,0,0,0,0,0,0,0])
# filled = np.array([1,1,0,0,1,0,1,1,1,0,0])
# target = np.array([1,0,1,1,0])
# filled = np.array([1,1,0,1,1])
# target = np.nonzero(target)[0]
# filled = np.nonzero(filled)[0]
# path = get_rearrange_paths(target, filled)
target = np.array([1,1,1,0,0])
filled = np.array([1,0,0,1,1])
t_idx = np.nonzero(target)[0]
f_idx = np.nonzero(filled)[0]
table, sig = create_path_table_reduced(twzr, t_idx)
# np.savez(
# "data/reduced_path_table.npz",
# path_table=table,
# static_sig=sig,
# wfm=twzr,
# target=target
# )
# data = np.load("data/reduced_path_table_5.npz", allow_pickle=True)
# table = data['path_table'].item()
# sig = data['static_sig']
# twzr = data['wfm'].item()
# target = data['target']
paths, off = get_rearrange_paths(f_idx, t_idx)
# #################################
# # end = 1930345 # dw = 1
# # end = 2730325 # dw = 2
# # end = 2729906 # dw = 2'
# end = 3343227 # dw = 3
# # end = 3343612 # dw = 3'
# # end = 3860640 # dw = 4
# # move = table[(1,0)] % (np.pi)
# # static = table[(0,0)] % (np.pi)
# move = np.sin(table[(3,0)])
# static = np.sin(table[(0,0)])
# r = 20
# m = np.arcsin(move[end-r:end+r])
# # s = np.arcsin(static[end-r:end+r])
# s = np.zeros(r*2)
# s[r:] = static[:r]
# # m = move[end-r:end+r]
# # s = static[end-r:end+r]
# # diff = move[end-10:end+10]-static[end-10:end+10]
# import matplotlib.pyplot as plt
# x = np.arange(20)
# plt.figure()
# plt.plot(m, '.-', label='move')
# plt.plot(s, '.-', label='static')
# plt.legend()
# plt.show()
#########################
create_moving_array_reduced(sig, table, paths, off)
fname = "data/reduced_move_sig.npz"
np.savez(fname, signal=sig, wfm=twzr)
plot_main(fname)
from waveform import *
np.random.seed(0)
# parameters to play around
# ----------------------------------------------------------------------------
cf = MEGA(105) # center frequency
df = MEGA(2.5) # delta frequency
n = 2 # number of tones to generate in either direction of cf, total number of tweezer is 2*n+1
nt = 2*n+1 # total number of tweezers
# sampling_rate and sample_len must follow some relationship explained in the wiki page.
sampling_rate = int(614.4e6) # sampling rate
sample_len = 512 * 600 # sample_len
# amplitude uniformity adjustments, just make sure its called amps at the end
scale = 2**11
ampMax = scale/np.sqrt(nt)
amps = ampMax * np.ones(nt)
corr = np.array([1.53312825, 1.35073669, 1.252971, 1.06263741, 1.])
amps *= np.sqrt(corr)
# phase adjustments
phase = np.load("array_phase.npz")['phase'][:nt] # phase table from Caltech
# ----------------------------------------------------------------------------
# MAGIC DO NOT CHANGE. one day i will understand, maybe
# ----------------------------------------------------------------------------
pvAllocMemPageAligned(sample_len * 2)
# ----------------------------------------------------------------------------
# setting up awg sequence, explained in wiki
# ----------------------------------------------------------------------------
awg = AWG()
awg.open(id=b'/dev/spcm1') # change this to b'/dev/spcm0' for top AWG
awg.set_sampling_rate(sampling_rate)
awg.toggle_channel(0, amplitude=2500)
awg.set_trigger(EXT0=SPC_TM_POS)
awg.set_sequence_mode(2)
twzr = Waveform(cf, df, n, sampling_rate)
twzr.amplitude = amps
twzr.phi = phase
static_sig = create_static_array(twzr, sample_len)
empty = np.zeros(sample_len)
awg.write_segment(static_sig, segment=0)
awg.write_segment(empty, segment=1)
awg.configure_step(step=0, segment=0, nextstep=1, loop=1, condition=SPCSEQ_ENDLOOPONTRIG)
awg.configure_step(step=1, segment=1, nextstep=0, loop=1, condition=SPCSEQ_ENDLOOPONTRIG)
# ----------------------------------------------------------------------------
# running the awg
# ----------------------------------------------------------------------------
awg.run()
awg.force_trigger() # this is equivalement to an actual hardware trigger
print("Outputing...")
while True:
command = input("enter c to stop, s to switch sequence step: ")
if command == 'c':
awg.stop()
print("stopping")
break
elif command == 's':
awg.force_trigger()
print("switching sequence step")
awg.stop()
# ----------------------------------------------------------------------------
awg.close()
This diff is collapsed.
import scipy.signal as scisig
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
import os
from mpl_toolkits.axes_grid1 import make_axes_locatable
def plot_main(fname):
file = np.load(fname, allow_pickle=True)
signal = file['signal']
wfm = file['wfm'].item()
sr = wfm.sample_rate
f, t, Sxx = scisig.stft(signal, fs=sr, nperseg=256*100)
f /= 1e6
t *= 1e3
Sxx[abs(Sxx) < 0.001] = 0
step = int(f.size/18)
i = 4000
j = i + step
fig, ax = plt.subplots()
im = ax.pcolormesh(t, f[i:j], np.abs(Sxx[i:j, :]), shading='gouraud')
plt.title("Signal Spectrogram Frequency")
plt.ylabel('Frequency [MHz]')
plt.xlabel('Time [ms]')
# plt.ylim(95,115)
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
fig.colorbar(im, cax=cax)
if True:
plt.savefig("data/Spectrogram-frequency.png", dpi=1200)
fig, ax = plt.subplots()
im = ax.pcolormesh(t, f[i:j], np.angle(Sxx[i:j, :]), shading='gouraud')
plt.title("Signal Spectrogram Phase")
plt.ylabel('Frequency [MHz]')
plt.xlabel('Time [ms]')
plt.ylim(95,115)
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
fig.colorbar(im, cax=cax)
if True:
plt.savefig("data/Spectrogram-phase.png", dpi=1200)
\ No newline at end of file