-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDigitizerOutputTriggerSample.py
More file actions
183 lines (149 loc) · 8.49 KB
/
Copy pathDigitizerOutputTriggerSample.py
File metadata and controls
183 lines (149 loc) · 8.49 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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# Goal:
# Demonstrate using the Digitizer Output Trigger as an input trigger to the SpikeSafe or an external instrument
#
# Expectation:
# The digitizer will output a trigger signal, the SpikeSafe will run a 3-pulse Multi Pulse sequence, and the voltages will be measured by the Digitizer and graphed
import sys
import time
import logging
import spikesafe_python
from matplotlib import pyplot as plt
### set these before starting application
# SpikeSafe IP address and port number
ip_address: str = '10.0.0.220'
port_number: int = 8282
### setting up sequence log
log = logging.getLogger(__name__)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s.%(msecs)03d, %(levelname)s, %(message)s',
datefmt='%m/%d/%Y %I:%M:%S',
handlers=[
logging.FileHandler("SpikeSafePythonSamples.log"),
logging.StreamHandler(sys.stdout)
]
)
### start of main program
try:
log.info("DigitizerOutputTriggerSample.py started.")
log.info("Python version: {}".format(sys.version))
# instantiate new TcpSocket to connect to SpikeSafe
tcp_socket = spikesafe_python.TcpSocket(enable_logging=False)
tcp_socket.open_socket(ip_address, port_number)
# reset to default state and check for all events, this will automatically abort digitizer in order get it into a known state. This is good practice when connecting to a SpikeSafe PSMU
# it is best practice to check for errors after sending each command
tcp_socket.send_scpi_command('*RST')
spikesafe_python.ReadAllEvents.read_all_events(tcp_socket, enable_logging=True)
# parse the SpikeSafe information
spikesafe_info = spikesafe_python.SpikeSafeInfoParser.parse_spikesafe_info(tcp_socket)
# set up Channel 1 for Multi Pulse output. To find more explanation, see run_spikesafe_operation_modes/run_multi_pulse
tcp_socket.send_scpi_command('SOUR1:FUNC:SHAP MULTIPULSE')
set_current: float = 0.1
tcp_socket.send_scpi_command(f'SOUR1:CURR {spikesafe_python.Precision.get_precise_current_command_argument(set_current)}')
compliance_voltage: float = 20
tcp_socket.send_scpi_command(f'SOUR1:VOLT {spikesafe_python.Precision.get_precise_compliance_voltage_command_argument(compliance_voltage)}')
pulse_on_time_seconds: float = 1
tcp_socket.send_scpi_command(f'SOUR1:PULS:TON {spikesafe_python.Precision.get_precise_time_command_argument(pulse_on_time_seconds)}')
pulse_off_time_seconds: float = 1
tcp_socket.send_scpi_command(f'SOUR1:PULS:TOFF {spikesafe_python.Precision.get_precise_time_command_argument(pulse_off_time_seconds)}')
tcp_socket.send_scpi_command('SOUR1:PULS:COUN 3')
tcp_socket.send_scpi_command('SOUR1:CURR:PROT 50')
tcp_socket.send_scpi_command('SOUR1:CURR? MAX')
spikesafe_model_max_current = float(tcp_socket.read_data())
load_impedance, rise_time = spikesafe_python.Compensation.get_optimum_compensation(spikesafe_model_max_current, set_current, pulse_on_time_seconds)
tcp_socket.send_scpi_command(f'SOUR1:PULS:CCOM {load_impedance}')
tcp_socket.send_scpi_command(f'SOUR1:PULS:RCOM {rise_time}')
tcp_socket.send_scpi_command('OUTP1:RAMP FAST')
# set Channel 1's Input Trigger Source to External so an external trigger signal will start SpikeSafe current output
tcp_socket.send_scpi_command('OUTP1:TRIG:SOUR EXT')
# set Channel 1's Input Trigger Delay to 10µs (the minimum value). The SpikeSafe will output current 10µs after receiving the input trigger signal
tcp_socket.send_scpi_command('OUTP1:TRIG:DEL 10')
# set Channel 1's Input Trigger Polarity to rising. This should match the expected polarity of the trigger signal
tcp_socket.send_scpi_command('OUTP1:TRIG:POL RISING')
# set typical Digitizer settings to match SpikeSafe settings. For more explanation, see making_integrated_voltage_measurements
tcp_socket.send_scpi_command('VOLT:RANG 10')
aperture: int = 400000
tcp_socket.send_scpi_command(f'VOLT:APER {spikesafe_python.Precision.get_precise_time_microseconds_command_argument(aperture)}')
hardware_trigger_delay: int = 200000
tcp_socket.send_scpi_command(f'VOLT:TRIG:DEL {spikesafe_python.Precision.get_precise_time_microseconds_command_argument(hardware_trigger_delay)}')
tcp_socket.send_scpi_command('VOLT:TRIG:SOUR HARDWARE')
tcp_socket.send_scpi_command('VOLT:TRIG:EDGE RISING')
hardware_trigger_count: int = 6
tcp_socket.send_scpi_command(f'VOLT:TRIG:COUN {hardware_trigger_count}') # two 3-pulse Multi Pulse sequences will output
reading_count: int = 1
tcp_socket.send_scpi_command(f'VOLT:READ:COUN {reading_count}')
# set the Digitizer Hardware Trigger polarity to rising
tcp_socket.send_scpi_command('VOLT:OUTP:TRIG:EDGE RISING')
# check all SpikeSafe event since all settings have been sent
spikesafe_python.ReadAllEvents.read_all_events(tcp_socket, enable_logging=True)
# initialize the digitizer. Measurements will be taken once a current pulse is outputted
tcp_socket.send_scpi_command('VOLT:INIT')
# turn on Channel 1
tcp_socket.send_scpi_command('OUTP1 1')
# wait until Channel 1 is ready to pulse
spikesafe_python.ReadAllEvents.read_until_event(tcp_socket, spikesafe_python.SpikeSafeEvents.CHANNEL_READY) # event 100 is "Channel Ready"
# output the Digitizer hardware output trigger. 10µs after this signal is outputted, the Multi Pulse sequence will start
tcp_socket.send_scpi_command('VOLT:OUTP:TRIG')
# check that the Multi Pulse output has ended
has_multi_pulse_ended = ''
while has_multi_pulse_ended != 'TRUE':
tcp_socket.send_scpi_command('SOUR1:PULS:END?')
has_multi_pulse_ended = tcp_socket.read_data()
spikesafe_python.Threading.wait(0.5)
# output the Digitizer hardware output trigger. As long as the SpikeSafe is ready to pulse, this can be done continuously
tcp_socket.send_scpi_command('VOLT:OUTP:TRIG')
# check that the Multi Pulse output has ended
has_multi_pulse_ended = ''
while has_multi_pulse_ended != 'TRUE':
tcp_socket.send_scpi_command('SOUR1:PULS:END?')
has_multi_pulse_ended = tcp_socket.read_data()
spikesafe_python.Threading.wait(0.5)
# wait for the Digitizer measurements to complete
estimated_complete_time_seconds = spikesafe_python.DigitizerDataFetch.get_new_voltage_data_estimated_complete_time(
aperture_microseconds = aperture,
reading_count = reading_count,
hardware_trigger_count = hardware_trigger_count,
hardware_trigger_delay_microseconds = hardware_trigger_delay,
pulse_period_seconds = pulse_on_time_seconds + pulse_off_time_seconds
)
spikesafe_python.DigitizerDataFetch.wait_for_new_voltage_data(tcp_socket, wait_time = estimated_complete_time_seconds, timeout = 10)
# fetch the Digitizer voltage readings using VOLT:FETC? query
digitizerData = []
digitizerData = spikesafe_python.DigitizerDataFetch.fetch_voltage_data(tcp_socket)
# turn off Channel 1 after routine is complete
tcp_socket.send_scpi_command('OUTP1 0')
# wait until the channel is fully discharged
spikesafe_python.Discharge.wait_for_spikesafe_channel_discharge(
spikesafe_socket=tcp_socket,
spikesafe_info=spikesafe_info,
compliance_voltage=compliance_voltage,
channel_number=1)
# prepare digitizer voltage data to plot
samples = []
voltage_readings = []
for dd in digitizerData:
samples.append(dd.sample_number)
voltage_readings.append(dd.voltage_reading)
# plot the pulse shape using the fetched voltage readings
plt.plot(samples, voltage_readings)
plt.ylabel('Voltage (V)')
plt.xlabel('Sample Number (#)')
plt.title('Digitizer Voltage Readings - two 3-pulse Multi-Pulse outputs')
plt.axis([0, 7, min(voltage_readings) - 0.1, max(voltage_readings) + 0.1])
plt.grid()
plt.show()
# disconnect from SpikeSafe
tcp_socket.close_socket()
log.info("DigitizerOutputTriggerSample.py completed.\n")
except spikesafe_python.SpikeSafeError as ssErr:
# print any SpikeSafe-specific error to both the terminal and the log file, then exit the application
error_message = 'SpikeSafe error: {}\n'.format(ssErr)
log.error(error_message)
print(error_message)
sys.exit(1)
except Exception as err:
# print any general exception to both the terminal and the log file, then exit the application
error_message = 'Program error: {}\n'.format(err)
log.error(error_message)
print(error_message)
sys.exit(1)