YorkUphysLabV2 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. yorkuphyslabv2-2.0.0/LICENSE +21 -0
  2. yorkuphyslabv2-2.0.0/PKG-INFO +43 -0
  3. yorkuphyslabv2-2.0.0/README.md +24 -0
  4. yorkuphyslabv2-2.0.0/YorkUphysLab/Actuator/Actuator.py +133 -0
  5. yorkuphyslabv2-2.0.0/YorkUphysLab/Actuator/__init__.py +0 -0
  6. yorkuphyslabv2-2.0.0/YorkUphysLab/GwINSTEK/AFG2000.py +164 -0
  7. yorkuphyslabv2-2.0.0/YorkUphysLab/GwINSTEK/GPD3303D.py +218 -0
  8. yorkuphyslabv2-2.0.0/YorkUphysLab/GwINSTEK/__init__.py +0 -0
  9. yorkuphyslabv2-2.0.0/YorkUphysLab/HVcontrol/HV_control.py +133 -0
  10. yorkuphyslabv2-2.0.0/YorkUphysLab/HVcontrol/__init__.py +0 -0
  11. yorkuphyslabv2-2.0.0/YorkUphysLab/ScoutScale/ScoutSTX.py +131 -0
  12. yorkuphyslabv2-2.0.0/YorkUphysLab/ScoutScale/__init__.py +0 -0
  13. yorkuphyslabv2-2.0.0/YorkUphysLab/Tektronix/TBS1000.py +456 -0
  14. yorkuphyslabv2-2.0.0/YorkUphysLab/Tektronix/__init__.py +0 -0
  15. yorkuphyslabv2-2.0.0/YorkUphysLab/Utility/Utility.py +56 -0
  16. yorkuphyslabv2-2.0.0/YorkUphysLab/Utility/__init__.py +0 -0
  17. yorkuphyslabv2-2.0.0/YorkUphysLab/__init__.py +1 -0
  18. yorkuphyslabv2-2.0.0/YorkUphysLab/__version__.py +1 -0
  19. yorkuphyslabv2-2.0.0/YorkUphysLabV2.egg-info/PKG-INFO +43 -0
  20. yorkuphyslabv2-2.0.0/YorkUphysLabV2.egg-info/SOURCES.txt +24 -0
  21. yorkuphyslabv2-2.0.0/YorkUphysLabV2.egg-info/dependency_links.txt +1 -0
  22. yorkuphyslabv2-2.0.0/YorkUphysLabV2.egg-info/requires.txt +4 -0
  23. yorkuphyslabv2-2.0.0/YorkUphysLabV2.egg-info/top_level.txt +3 -0
  24. yorkuphyslabv2-2.0.0/example/YorkUphysLab_example.py +50 -0
  25. yorkuphyslabv2-2.0.0/pyproject.toml +33 -0
  26. yorkuphyslabv2-2.0.0/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Mohammad Kareem
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: YorkUphysLabV2
3
+ Version: 2.0.0
4
+ Summary: A Python package to control YU physics labs equipment. V2 updated to work with new versions of setup.
5
+ Author-email: "Bruce Howard (maintainer)" <blhoward@yorku.ca>, "Mohammad Kareem (original author)" <mkareem@yorku.ca>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/brucehoward-physics/YorkUphysLab
8
+ Project-URL: Issues, https://github.com/m-kareem/YorkUphysLab/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.7
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: nidaqmx
15
+ Requires-Dist: pyserial
16
+ Requires-Dist: pyvisa-py
17
+ Requires-Dist: numpy
18
+ Dynamic: license-file
19
+
20
+ # York University physics lab
21
+
22
+ This package includes the required drivers to control some of the hardwares in physics labs at York University.
23
+
24
+ ## How to install
25
+
26
+ ```pip install --no-cache-dir --upgrade YorkUphysLabV2```
27
+
28
+ ## How to use
29
+
30
+ See the examples script: YorkUphysLab_example.py
31
+
32
+
33
+ ## Developed by:
34
+
35
+ Mohammad Kareem, Ph.D.
36
+ Laboratory Technologist
37
+ Department of Physics & Astronomy
38
+ Faculty of Science | YORK UNIVERSITY
39
+ 4700 Keele Street, Toronto, Ontario, Canada M3J 1P3
40
+
41
+ ## Maintained in V2 by:
42
+
43
+ Bruce Howard, Ph.D.
@@ -0,0 +1,24 @@
1
+ # York University physics lab
2
+
3
+ This package includes the required drivers to control some of the hardwares in physics labs at York University.
4
+
5
+ ## How to install
6
+
7
+ ```pip install --no-cache-dir --upgrade YorkUphysLabV2```
8
+
9
+ ## How to use
10
+
11
+ See the examples script: YorkUphysLab_example.py
12
+
13
+
14
+ ## Developed by:
15
+
16
+ Mohammad Kareem, Ph.D.
17
+ Laboratory Technologist
18
+ Department of Physics & Astronomy
19
+ Faculty of Science | YORK UNIVERSITY
20
+ 4700 Keele Street, Toronto, Ontario, Canada M3J 1P3
21
+
22
+ ## Maintained in V2 by:
23
+
24
+ Bruce Howard, Ph.D.
@@ -0,0 +1,133 @@
1
+ import nidaqmx
2
+ from YorkUphysLab.GwINSTEK import GPD3303D as PSU
3
+ import time
4
+
5
+
6
+ class Actuator:
7
+ def __init__(self, _DAQ_mame, _psu, emul=False, _max_time= 12) -> None:
8
+ self.sdaq = _DAQ_mame
9
+ self.psu = _psu
10
+ self.max_time = _max_time
11
+ self.max_pos = 100 # mm
12
+ self.actuator_on = False
13
+ self.emul = emul
14
+ self.current_pos = 0
15
+ if self.emul:
16
+ self.emul_str = "[Emulation mode]:"
17
+ else:
18
+ self.emul_str = ""
19
+
20
+
21
+ def set_position(self, pos):
22
+ if not self.actuator_on:
23
+ print(f'{self.emul_str} Actuator is switched OFF. Switch it ON first!')
24
+ return None
25
+
26
+ # when PSU connection is closed by another device:
27
+ if not self.psu.is_connected():
28
+ print("PSU Connection is not established. Switching off other devise sharing same PSU might have caused this. Switch on this decive and try again.")
29
+ return None
30
+
31
+
32
+ if 0 <= pos <= self.max_pos:
33
+ Vctrl = -0.00004*pos*pos + 0.0528*pos + 0.1
34
+ else:
35
+ print(f'{self.emul_str} position ({pos} mm) out of range. use 0-{self.max_pos} mm')
36
+ return None
37
+
38
+ #if self.actuator_on:
39
+ self.current_pos = self.get_position()
40
+ required_time = abs(pos - self.current_pos)*self.max_time/self.max_pos + 1
41
+
42
+ if not self.emul:
43
+ with nidaqmx.Task() as task:
44
+ task.ao_channels.add_ao_voltage_chan(f'{self.sdaq}/ao0','mychannel',0,5)
45
+ task.write(Vctrl)
46
+ task.stop()
47
+
48
+ time.sleep(required_time)
49
+ print(f'{self.emul_str} position set to {pos} mm')
50
+ self.current_pos = pos
51
+
52
+ def get_position(self):
53
+ if not self.actuator_on:
54
+ print(f'{self.emul_str} Actuator is switched OFF! Switch it ON first!')
55
+ return None
56
+
57
+ # when PSU connection is closed by another device:
58
+ if not self.psu.is_connected():
59
+ print("PSU Connection is not established. Switching off other devise sharing same PSU might have caused this. Switch on this decive and try again.")
60
+ return None
61
+
62
+ #if self.actuator_on:
63
+ if not self.emul:
64
+ with nidaqmx.Task() as task:
65
+ task.ai_channels.add_ai_voltage_chan(f'{self.sdaq}/ai0')
66
+ Vadc = task.read()
67
+ pos = 55.33223 - 31.31889*Vadc + 0.5730428*Vadc*Vadc
68
+ else:
69
+ pos = self.current_pos
70
+
71
+ return round(pos,1)
72
+
73
+ def switch_on(self):
74
+ try:
75
+ if not self.psu.is_connected():
76
+ self.psu.connect()
77
+
78
+ if self.psu.is_connected():
79
+ self.psu.set_voltage(1, 12)
80
+ self.psu.set_current(1, 0.5)
81
+ self.psu.enable_output()
82
+ self.actuator_on = True
83
+ message = f'{self.emul_str} Actuator switched ON.'
84
+ else:
85
+ message = f'{self.emul_str} PSU Connection is not established.'
86
+
87
+ except Exception as e:
88
+ message = f'{self.emul_str} An error occurred: {str(e)}'
89
+
90
+ print(message)
91
+
92
+ return self.actuator_on
93
+
94
+ def switch_off(self):
95
+ self.psu.disable_output()
96
+ #self.psu.close_connection()
97
+ print(f'{self.emul_str} Actuator switched OFF.')
98
+ self.actuator_on = False
99
+ return True
100
+ #==============================================================================
101
+
102
+ # how to use this class
103
+ if __name__ == "__main__":
104
+
105
+ DAQ_mame = 'SDAQ-25'
106
+ # create power-supply and actuator objects
107
+ psu = PSU.GPD3303D(emul=False)
108
+ actuator = Actuator(DAQ_mame, psu, emul=False)
109
+
110
+ #psu.connect()
111
+ actuator.switch_on()
112
+ actuator.set_position(100)
113
+ print(f'position moved to = {actuator.get_position()} mm')
114
+
115
+ time.sleep(2)
116
+
117
+ #actuator.switch_off()
118
+
119
+ '''
120
+ SenorDAQ terminals:
121
+ 1: p0.0
122
+ 2: p0.1
123
+ 3: p0.2
124
+ 4: p0.3
125
+ 5: GND
126
+ 6: +5V
127
+ 7: PFIO
128
+ 8: GND
129
+ 9: AO0 ---->
130
+ 10: GND
131
+ 11: AI0 ---->
132
+ 12: AI1
133
+ '''
File without changes
@@ -0,0 +1,164 @@
1
+ import serial
2
+ import time
3
+ import serial.tools.list_ports
4
+ import logging
5
+
6
+ #----------------------------------------------
7
+ logging.getLogger().setLevel(logging.INFO)
8
+
9
+ class AFG2000:
10
+
11
+ def __init__(self, emul=False, keyword='AFG', baudrate=9600, timeout=1, port=None) -> None:
12
+ self.port = port
13
+ self.keyword = keyword
14
+ self.timeout = timeout
15
+ self.baudrate = baudrate
16
+ self.inst = None
17
+ #---------------------------------------------------
18
+
19
+ def connect(self):
20
+ if self.inst is not None and self.inst.is_open:
21
+ logging.info('AFG Connection is already established.')
22
+ return True
23
+ if self.port:
24
+ self.inst = serial.Serial(self.port, self.baudrate, timeout=self.timeout)
25
+ else:
26
+ self.inst = self.port_search(self.keyword)
27
+
28
+ if self.inst is not None:
29
+ logging.info(f'Connected to {self.get_idn()}')
30
+ return True
31
+ else:
32
+ logging.error('AFG Connection failed.')
33
+ return False
34
+ #---------------------------------------------------
35
+
36
+ def port_search(self, keyword):
37
+ logging.info('Searching for the device...')
38
+ ports = serial.tools.list_ports.comports()
39
+ for port, desc, hwid in sorted(ports):
40
+ ser = serial.Serial(port, self.baudrate, timeout=self.timeout)
41
+ ser.write(b'*IDN?\r\n')
42
+ idn = ser.readline().strip().decode('ascii')
43
+
44
+ if keyword in idn:
45
+ logging.info(f'"{keyword}" found in: {port}')
46
+ return ser
47
+ else:
48
+ ser.close()
49
+
50
+ logging.info(f'"{keyword}" is not found on any port')
51
+ return None
52
+ #---------------------------------------------------
53
+
54
+ def close(self):
55
+ if self.inst is not None and self.inst.is_open:
56
+ self.inst.close()
57
+ logging.info('AFG Connection closed.')
58
+ else:
59
+ logging.info('No active AFG connection to close.')
60
+ #---------------------------------------------------
61
+
62
+ def is_connected(self):
63
+ if self.inst is None:
64
+ return False
65
+ return self.inst.is_open
66
+ #---------------------------------------------------
67
+
68
+ def send_cmd(self, cmd):
69
+ if self.is_connected():
70
+ self.inst.write(cmd.encode('ascii') + b'\r\n')
71
+ resp = self.inst.readline().strip().decode('ascii')
72
+ return resp
73
+ else:
74
+ logging.info('AFG Connection is not established.')
75
+ return None
76
+ #---------------------------------------------------
77
+
78
+ def get_idn(self):
79
+ return self.send_cmd('*IDN?')
80
+ #---------------------------------------------------
81
+
82
+ def set_frequency(self, freq):
83
+ """
84
+ Sets the frequency of the AFG2000 function generator.
85
+
86
+ Parameters:
87
+ freq (float): The desired frequency in Hz.
88
+
89
+ Returns:
90
+ bool: True if the frequency is set successfully, False otherwise.
91
+ """
92
+ if self.is_connected():
93
+ self.send_cmd(f'SOUR1:FREQ {freq}')
94
+ return True
95
+ else:
96
+ logging.info('AFG2000 function generator is not connected!')
97
+ return False
98
+ #---------------------------------------------------
99
+
100
+ def set_waveform(self, waveform='SIN'):
101
+ if self.is_connected():
102
+ if waveform in ['SIN', 'SQU', 'RAMP', 'NOIS', 'ARB']:
103
+ self.send_cmd(f'SOUR1:FUNC {waveform}')
104
+ return True
105
+ else:
106
+ logging.error(f'Invalid waveform: {waveform}. Valid waveforms are "SIN", "SQU", "RAMP", "NOIS", and "ARB".')
107
+ return None
108
+ else:
109
+ logging.info('AFG2000 function generator is not connected!')
110
+ return False
111
+ #---------------------------------------------------
112
+
113
+ def set_amplitude(self, amplitude, unit='VPP'):
114
+ if self.is_connected():
115
+ if unit in ['VPP', 'VRMS', 'DBM']:
116
+ self.send_cmd(f'SOUR1:VOLT:UNIT {unit}')
117
+ else:
118
+ logging.error(f'Invalid unit: {unit}. Valid units are "VPP", "VRMS", and "DBM".')
119
+ return None
120
+ self.send_cmd(f'SOUR1:AMPL {amplitude}')
121
+ return True
122
+ else:
123
+ logging.info('AFG2000 function generator is not connected!')
124
+ return False
125
+ #---------------------------------------------------
126
+
127
+ def set_DCoffset(self, offset):
128
+ if self.is_connected():
129
+ self.send_cmd(f'SOUR1:DCO {offset}')
130
+ return True
131
+ else:
132
+ logging.info('AFG2000 function generator is not connected!')
133
+ return False
134
+ #---------------------------------------------------
135
+
136
+ def set_output(self, state):
137
+ if self.is_connected():
138
+ if state in ['ON', 'OFF']:
139
+ self.send_cmd(f'OUTP {state}')
140
+ return True
141
+ else:
142
+ logging.error(f'Invalid output state: {state}. Valid states are "ON" and "OFF".')
143
+ return None
144
+ else:
145
+ logging.info('AFG2000 function generator is not connected!')
146
+ return False
147
+ #==============================================================================
148
+
149
+ # how to use this class
150
+ if __name__ == '__main__':
151
+ afg = AFG2000()
152
+ afg.connect()
153
+ afg.set_waveform('SIN')
154
+ afg.set_frequency('70')
155
+ afg.set_amplitude('0.2', 'VPP')
156
+ afg.set_DCoffset('0.0')
157
+ afg.set_output('ON')
158
+ time.sleep(10)
159
+
160
+ afg.set_amplitude('0.35')
161
+ afg.set_frequency('90')
162
+ time.sleep(10)
163
+ afg.set_output('OFF')
164
+ afg.close()
@@ -0,0 +1,218 @@
1
+ import serial
2
+ import time
3
+ import serial.tools.list_ports
4
+
5
+ class GPD3303D:
6
+ """
7
+ Represents the GPD3303D Programmable Power Supply Unit (PSU).
8
+
9
+ Args:
10
+ emul (bool): Whether to enable emulation mode. Default is False.
11
+ keyword (str): The keyword to search for in the device identification string. Default is 'GPD'.
12
+ baudrate (int): The baud rate for serial communication. Default is 9600.
13
+ timeout (float): The timeout duration for serial communication in seconds. Default is 1.
14
+ port (str): The specific port to connect to. If not provided, the port will be searched automatically.
15
+
16
+ Attributes:
17
+ port (str): The port used for communication.
18
+ keyword (str): The keyword used for device identification.
19
+ timeout (float): The timeout duration for serial communication.
20
+ baudrate (int): The baud rate for serial communication.
21
+ inst (serial.Serial or str): The serial connection instance or a string indicating emulation mode.
22
+ emul (bool): Whether emulation mode is enabled.
23
+ inst_is_open (bool): Whether the serial connection is open.
24
+ voltage (dict): A dictionary to store the voltage values for each channel.
25
+ current (dict): A dictionary to store the current values for each channel.
26
+ emul_str (str): A string indicating the emulation mode.
27
+
28
+ Methods:
29
+ connect(): Establishes a connection to the PSU.
30
+ port_search(keyword): Searches for the PSU on available ports.
31
+ send_cmd(cmd): Sends a command to the PSU and returns the response.
32
+ get_idn(): Retrieves the identification string of the PSU.
33
+ set_voltage(channel, voltage): Sets the voltage for a specific channel.
34
+ set_current(channel, current): Sets the current for a specific channel.
35
+ enable_output(): Enables the output of the PSU.
36
+ disable_output(): Disables the output of the PSU.
37
+ enable_beep(): Enables the beep sound of the PSU.
38
+ disable_beep(): Disables the beep sound of the PSU.
39
+ get_voltage(channel): Retrieves the voltage value for a specific channel.
40
+ get_current(channel): Retrieves the current value for a specific channel.
41
+ close_connection(): Closes the connection to the PSU.
42
+ is_connected(): Checks if the connection to the PSU is established.
43
+ """
44
+ def __init__(self, emul=False, keyword='GPD', baudrate=9600, timeout=1, port=None) -> None:
45
+ self.port = port
46
+ self.keyword = keyword
47
+ self.timeout = timeout
48
+ self.baudrate = baudrate
49
+ self.inst = None
50
+ self.emul = emul
51
+ self.inst_is_open = False
52
+ self.voltage ={}
53
+ self.current ={}
54
+ if self.emul:
55
+ self.emul_str = "[Emulation mode]:"
56
+ else:
57
+ self.emul_str = ""
58
+
59
+ def connect(self):
60
+ if not self.emul:
61
+ if self.port:
62
+ self.inst = serial.Serial(self.port, self.baudrate, timeout=self.timeout)
63
+ else:
64
+ self.inst = self.port_search(self.keyword)
65
+
66
+ if self.inst is not None:
67
+ print(f'Connected to {self.get_idn()}')
68
+ return True
69
+ else:
70
+ print('PSU Connection failed.')
71
+ return False
72
+ else:
73
+ print(f'{self.emul_str} Connected to GPD3303D PSU.')
74
+ self.inst = 'emulated psu'
75
+ self.inst_is_open = True
76
+ return True
77
+
78
+
79
+ def port_search(self, keyword):
80
+ print('Searching for the device...')
81
+ ports = serial.tools.list_ports.comports()
82
+ for port, desc, hwid in sorted(ports):
83
+ ser = serial.Serial(port, self.baudrate, timeout=self.timeout)
84
+ ser.write(b'*IDN?\r\n')
85
+ idn = ser.readline().strip().decode('ascii')
86
+
87
+ if keyword in idn:
88
+ print(f'"{keyword}" found in: {port}')
89
+ return ser
90
+ else:
91
+ ser.close()
92
+
93
+ print(f'"{keyword}" is not found on any port')
94
+ return None
95
+
96
+
97
+ def send_cmd(self, cmd):
98
+ if self.is_connected():
99
+ self.inst.write(cmd.encode('ascii') + b'\r\n')
100
+ resp = self.inst.readline().strip().decode('ascii')
101
+ return resp
102
+ else:
103
+ print('PSU Connection is not established.')
104
+ return None
105
+
106
+
107
+ def get_idn(self):
108
+ if self.emul:
109
+ return 'Emulated GPD3303D PSU'
110
+ else:
111
+ return self.send_cmd('*IDN?')
112
+
113
+ def set_voltage(self, channel, voltage):
114
+ if not self.emul:
115
+ cmd = f'VSET{channel}:{voltage:.1f}'
116
+ return self.send_cmd(cmd)
117
+ else:
118
+ self.voltage[channel] = voltage
119
+ return True
120
+
121
+ def set_current(self, channel, current):
122
+ if not self.emul:
123
+ cmd = f'ISET{channel}:{current:.2f}'
124
+ return self.send_cmd(cmd)
125
+ else:
126
+ self.current[channel] = current
127
+ return True
128
+
129
+ def enable_output(self):
130
+ if not self.emul: return self.send_cmd('OUT1')
131
+ else:
132
+ print(f'{self.emul_str} PSU output enabled.')
133
+ return True
134
+
135
+
136
+ def disable_output(self):
137
+ if not self.emul: return self.send_cmd('OUT0')
138
+ else:
139
+ print(f'{self.emul_str} PSU output disabled.')
140
+ return True
141
+
142
+ def enable_beep(self):
143
+ if not self.emul: return self.send_cmd('BEEP1')
144
+
145
+ def disable_beep(self):
146
+ if not self.emul: return self.send_cmd('BEEP0')
147
+
148
+ def get_voltage(self, channel):
149
+ if not self.emul:
150
+ response = self.send_cmd(f'VOUT{channel}?')
151
+ if response is not None:
152
+ voltage_str, unit_str = response.strip().split("V")
153
+ return float(voltage_str)
154
+ else:
155
+ return float(self.voltage[channel])
156
+
157
+
158
+ def get_current(self, channel):
159
+ if not self.emul:
160
+ response = self.send_cmd(f'IOUT{channel}?')
161
+ if response is not None:
162
+ current_str, unit_str = response.strip().split("A")
163
+ return float(current_str)
164
+ else:
165
+ return float(self.current[channel])
166
+
167
+ def close_connection(self):
168
+ if not self.emul:
169
+ if self.inst is not None and self.inst.is_open:
170
+ self.inst.close()
171
+ print('PSU Connection closed.')
172
+ else:
173
+ print('No active PSU connection to close.')
174
+ else:
175
+ if self.inst is not None and self.inst_is_open:
176
+ self.inst_is_open = False
177
+ print(f'{self.emul_str} PSU Connection closed.')
178
+ else:
179
+ print(f'{self.emul_str} No active PSU connection to close.')
180
+
181
+ def is_connected(self):
182
+ if self.inst is None:
183
+ return False
184
+ if not self.emul: return self.inst.is_open
185
+ else: return self.inst_is_open
186
+ #==============================================================================
187
+
188
+ # how to use this class
189
+ if __name__ == '__main__':
190
+ # create a power-supply object
191
+ psu = GPD3303D(emul=True)
192
+ #psu = GPD3303D(port='COM8')
193
+
194
+ # connect to the device
195
+ psu.connect()
196
+
197
+ # Set the output voltage and current for channel 1
198
+ psu.set_voltage(1, 12)
199
+ psu.set_current(1, 0.01)
200
+
201
+ # Set the output voltage and current for channel 2
202
+ psu.set_voltage(2, 4.7)
203
+ psu.set_current(2, 0.05)
204
+
205
+ # Enable the output
206
+ psu.enable_output()
207
+
208
+ time.sleep(2)
209
+ #print(f'voltage - CH1: {psu.get_voltage(1)} V')
210
+ #print(f'current - CH1: {psu.get_current(1)} A')
211
+ print(f'voltage - CH2: {psu.get_voltage(2)} V')
212
+ #print(f'current - CH2: {psu.get_current(2)} A')
213
+
214
+ # Disable the output
215
+ psu.disable_output()
216
+
217
+ # close the connection
218
+ psu.close_connection()
File without changes