-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Get arbitrary waveform generation working
- Loading branch information
1 parent
07f1c6e
commit c39e3cb
Showing
3 changed files
with
138 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import os | ||
import sys | ||
import time | ||
import matplotlib.pyplot as plt | ||
import redpitaya_scpi as scpi | ||
import numpy as np | ||
import math | ||
import util | ||
from datetime import datetime | ||
|
||
IP = 'rp-f0c04a.local' | ||
rp_s = scpi.scpi(IP) | ||
print('Connected to ' + IP) | ||
|
||
# Set up waveform | ||
wave_form = "ARBITRARY" | ||
freq = 100 # good range 10-200Hz | ||
ampl = 0.3 # good range 0-0.6V | ||
|
||
N = 16384 # Number of samples in buffer | ||
decimation = 85 | ||
smpl_rate = 125e6//decimation | ||
# t, y from exampled RP arbitrary wavegen: | ||
# t = np.linspace(0, 1, N)*2*math.pi | ||
# y = np.sin(t) + 1/3*np.sin(3*t) # same overall period as regular sin wave | ||
t, y = util.bounded_frequency_waveform(20, 1000, length=N, sample_rate=smpl_rate) | ||
y = util.linear_convert(y) # convert range of waveform to [-1, 1] to properly set ampl | ||
plt.plot(t, y) | ||
plt.show() | ||
|
||
# Reset Generation and Acquisition | ||
rp_s.tx_txt('GEN:RST') | ||
rp_s.tx_txt('ACQ:RST') | ||
|
||
##### Generation ##### | ||
# Function for configuring Source | ||
rp_s.sour_set(1, wave_form, ampl, freq, data=y) | ||
|
||
# Enable output | ||
rp_s.tx_txt('OUTPUT1:STATE ON') | ||
rp_s.tx_txt('SOUR1:TRig:INT') | ||
|
||
##### Acqusition ##### | ||
# Function for configuring Acquisition | ||
rp_s.acq_set(dec=decimation, trig_delay=0) | ||
# print(rp_s.get_settings()) | ||
rp_s.tx_txt('ACQ:START') | ||
time.sleep(1) | ||
rp_s.tx_txt('ACQ:TRig NOW') | ||
# print(rp_s.get_settings()) | ||
time.sleep(1) | ||
|
||
# Wait for trigger | ||
while 1: | ||
rp_s.tx_txt('ACQ:TRig:STAT?') # Get Trigger Status | ||
if rp_s.rx_txt() == 'TD': # Triggered? | ||
break | ||
|
||
## ! OS 2.00 or higher only ! ## | ||
while 1: | ||
rp_s.tx_txt('ACQ:TRig:FILL?') | ||
if rp_s.rx_txt() == '1': | ||
break | ||
|
||
# Read data and plot | ||
# function for Data Acquisition | ||
print(rp_s.get_settings()) | ||
pd_data = rp_s.acq_data(chan=1, convert=True) # Volts | ||
speaker_data = rp_s.acq_data(chan=2, convert=True) # Volts | ||
print("data shape:", np.array(pd_data).shape) | ||
print(rp_s.get_settings()) | ||
|
||
plt.plot(speaker_data, color="black", label="Speaker") | ||
plt.plot(pd_data, color="blue", label="PD") | ||
plt.legend() | ||
plt.ylabel('Amplitude [V]') | ||
plt.xlabel('Samples') | ||
plt.show() | ||
|
||
# Store data in txt file | ||
path = "/Users/angelajia/Code/College/SMI/data/" | ||
filename = f"{datetime.now()}.txt" | ||
file_path = os.path.join(path, filename) | ||
|
||
with open(file_path, 'x') as f: | ||
# f.write(np.array2string(t, threshold=N+1)) | ||
# f.write("\n" + np.array2string(y, threshold=N+1)) | ||
f.write("\n") | ||
for x in pd_data: | ||
f.write(str(x)) | ||
f.write("\n") | ||
f.write("STARTING SPEAKER DATA\n") | ||
for y in speaker_data: | ||
f.write(str(y)) | ||
f.write("\n") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import numpy as np | ||
from scipy.fftpack import fft, ifft, fftfreq | ||
|
||
''' | ||
Generates a random waveform within the given frequency range of a given length. | ||
''' | ||
def bounded_frequency_waveform(start_frequency, end_frequency, length=1000, sample_rate=1000): | ||
# Create an evenly spaced time array | ||
t = np.linspace(0, 1.0, length, False) # 1 second | ||
|
||
# Generate a random frequency spectrum between the start and end frequencies | ||
freq = np.linspace(0, sample_rate/2, length//2, False) | ||
spectrum = np.random.uniform(0, 1, len(freq)) | ||
spectrum = np.where((freq >= start_frequency) & (freq <= end_frequency), spectrum, 0) | ||
c = np.random.rayleigh(np.sqrt(4*spectrum*(freq[1]-freq[0]))) | ||
# See Jiang 2023 ref 28 for why we use the Rayleigh distribution here | ||
# Unless we use this distribution, the random noise will not be Gaussian distributed | ||
phase = np.random.uniform(-np.pi, np.pi, len(freq)) | ||
|
||
# Use the inverse Fourier transform to convert the frequency domain signal back to the time domain | ||
# Also include a zero phase component | ||
spectrum = np.hstack([spectrum*np.exp(1j*phase), np.zeros_like(spectrum)]) | ||
y = np.real(ifft(spectrum)) | ||
y = np.fft.fftshift(y) | ||
|
||
return t, y | ||
|
||
''' | ||
Linearly scales data to a new range. | ||
@param data: assumed to be 1D array | ||
''' | ||
def linear_convert(data, new_min=-1, new_max=1): | ||
old_min = np.min(data) | ||
old_max = np.max(data) | ||
old_range = old_max - old_min | ||
new_range = new_max - new_min | ||
return new_min + new_range * (data - old_min) / old_range |