-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSignalControl.py
More file actions
99 lines (82 loc) · 4.33 KB
/
SignalControl.py
File metadata and controls
99 lines (82 loc) · 4.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import numpy as np
import nidaqmx
from nidaqmx.constants import AcquisitionType
# Edit by Sam Kang Aug 2024
# This script predefine signals in signalinstruction.txt file, see txt for detailed instruction
# The galvo has a voltage range of +-10V, only voltage signal within the range will be send from the DAQ
def limit_voltage_range(wave, min_voltage=-10, max_voltage=10):
return np.clip(wave, min_voltage, max_voltage)
# Generate constant curve
def get_constant_curve(duration, desired_optical_angle, scaling_factor=0.8, sampling_rate=1000):
desired_mechanical_angle = desired_optical_angle / 2
required_voltage = desired_mechanical_angle * scaling_factor
constant_curve = np.full(int(sampling_rate * duration), required_voltage)
return limit_voltage_range(constant_curve)
# Generate sine/cosine wave
def get_sine_wave(duration, frequency, amplitude, phase_shift, vertical_shift, scaling_factor=0.8, sampling_rate=1000):
t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)
angle_wave = amplitude * np.sin(frequency * t + phase_shift) + vertical_shift
voltage_wave = (angle_wave / 2) * scaling_factor
return limit_voltage_range(voltage_wave)
# Generate square wave
def get_square_wave(duration, amplitude, period, scaling_factor=0.8, sampling_rate=1000):
t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)
square_wave = amplitude * np.sign(np.sin(2 * np.pi * t / period))
voltage_wave = (square_wave / 2) * scaling_factor
return limit_voltage_range(voltage_wave)
# Generate linear curve
def get_linear_curve(duration, slope, intercept, scaling_factor=0.8, sampling_rate=1000):
t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)
linear_curve = slope * t + intercept
voltage_curve = (linear_curve / 2) * scaling_factor
return limit_voltage_range(voltage_curve)
# Set continuous wave voltage from DAQ
def set_wave_voltages(channels, waves, rate):
with nidaqmx.Task() as task:
for channel in channels:
task.ao_channels.add_ao_voltage_chan(channel)
task.timing.cfg_samp_clk_timing(rate, sample_mode=AcquisitionType.CONTINUOUS)
task.write(waves, auto_start=True)
input("Press Enter to stop...")
# Main function to control the galvo
def control_galvo_from_file(filename, sampling_rate=1000):
with open(filename, 'r') as file:
lines = file.read().splitlines()
# Get the device label
device = (lines[14].split())[0]
# Skip header lines
signal_lines = lines[17:]
channels = []
signal_types = []
durations = []
parameters = []
for line in signal_lines:
parts = line.split()
channels.append(parts[0])
signal_types.append(parts[1])
durations.append(float(parts[2]))
parameters.append([float(p) for p in parts[3:]])
max_duration = max(durations)
waveforms = []
for signal_type, duration, params in zip(signal_types, durations, parameters):
if signal_type == 'Const':
desired_optical_angle = params[0]
waveform = get_constant_curve(duration, desired_optical_angle, sampling_rate=sampling_rate)
elif signal_type == 'Sine':
frequency, amplitude, phase_shift, vertical_shift = params
waveform = get_sine_wave(duration, frequency, amplitude, phase_shift, vertical_shift, sampling_rate=sampling_rate)
elif signal_type == 'SquWav':
amplitude, period = params
waveform = get_square_wave(duration, amplitude, period, sampling_rate=sampling_rate)
elif signal_type == 'Linear':
slope, intercept = params
waveform = get_linear_curve(duration, slope, intercept, sampling_rate=sampling_rate)
else:
raise ValueError("Unsupported signal type")
padded_waveform = np.pad(waveform, (0, int(sampling_rate * (max_duration - duration))), 'constant')
waveforms.append(padded_waveform)
channels_with_device = [f"{device}/{channel}" for channel in channels]
waves = np.vstack(waveforms)
set_wave_voltages(channels_with_device, waves, sampling_rate)
if __name__ == "__main__":
control_galvo_from_file('signalinstruction.txt', sampling_rate=1000)