|
2 | 2 | "cells": [ |
3 | 3 | { |
4 | 4 | "cell_type": "markdown", |
5 | | - "id": "2727ee29", |
| 5 | + "id": "intro", |
6 | 6 | "metadata": {}, |
7 | 7 | "source": [ |
8 | | - "# Example code for connecting the Sciospec ISX-3 device" |
| 8 | + "# ISX-3 / ISX-3mini example\n", |
| 9 | + "\n", |
| 10 | + "This notebook configures and measures one impedance spectrum using the USB full-speed serial interface. Connect the instrument, close the official Sciospec software, and select the correct serial port below. On Windows, make sure the USB driver described in the project README is installed." |
9 | 11 | ] |
10 | 12 | }, |
11 | 13 | { |
12 | 14 | "cell_type": "code", |
13 | | - "execution_count": 1, |
14 | | - "id": "18bd09f0", |
| 15 | + "execution_count": null, |
| 16 | + "id": "imports", |
15 | 17 | "metadata": {}, |
16 | 18 | "outputs": [], |
17 | 19 | "source": [ |
18 | 20 | "import matplotlib.pyplot as plt\n", |
19 | | - "import numpy as np\n", |
| 21 | + "from serial.tools import list_ports\n", |
20 | 22 | "\n", |
21 | | - "from sciopy import ISX_3, EisMeasurementSetup" |
| 23 | + "from sciopy import EisMeasurementSetup, ISX_3" |
22 | 24 | ] |
23 | 25 | }, |
24 | 26 | { |
25 | | - "cell_type": "code", |
26 | | - "execution_count": 2, |
27 | | - "id": "88778348", |
| 27 | + "cell_type": "markdown", |
| 28 | + "id": "port-help", |
28 | 29 | "metadata": {}, |
29 | | - "outputs": [], |
30 | 30 | "source": [ |
31 | | - "isx = ISX_3()" |
| 31 | + "## Select and connect the device\n", |
| 32 | + "\n", |
| 33 | + "Run the next cell to display available ports. Then set `PORT` to the ISX-3 port, for example `\"COM3\"` on Windows or `\"/dev/ttyUSB0\"` on Linux." |
32 | 34 | ] |
33 | 35 | }, |
34 | 36 | { |
35 | 37 | "cell_type": "code", |
36 | | - "execution_count": 3, |
37 | | - "id": "c21b7642", |
| 38 | + "execution_count": null, |
| 39 | + "id": "ports", |
38 | 40 | "metadata": {}, |
39 | | - "outputs": [ |
40 | | - { |
41 | | - "ename": "SerialException", |
42 | | - "evalue": "[Errno 2] could not open port COM1: [Errno 2] No such file or directory: 'COM1'", |
43 | | - "output_type": "error", |
44 | | - "traceback": [ |
45 | | - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", |
46 | | - "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", |
47 | | - "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/serial/serialposix.py:322\u001b[0m, in \u001b[0;36mSerial.open\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 322\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfd \u001b[38;5;241m=\u001b[39m \u001b[43mos\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mopen\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mportstr\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mos\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mO_RDWR\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m|\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mos\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mO_NOCTTY\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m|\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mos\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mO_NONBLOCK\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mOSError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m msg:\n", |
48 | | - "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'COM1'", |
49 | | - "\nDuring handling of the above exception, another exception occurred:\n", |
50 | | - "\u001b[0;31mSerialException\u001b[0m Traceback (most recent call last)", |
51 | | - "Cell \u001b[0;32mIn[3], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# connect to the device (adjust the port as necessary)\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[43misx\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect_device_USB2\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mCOM1\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", |
52 | | - "File \u001b[0;32m~/Schreibtisch/Uni/Forschung/PyPI_Packages/sciopy/sciopy/ISX_3.py:63\u001b[0m, in \u001b[0;36mISX_3.connect_device_USB2\u001b[0;34m(self, port, baudrate, timeout)\u001b[0m\n\u001b[1;32m 61\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 62\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mserial_protocol \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUSB-FS\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m---> 63\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdevice \u001b[38;5;241m=\u001b[39m \u001b[43mserial\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mSerial\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 64\u001b[0m \u001b[43m \u001b[49m\u001b[43mport\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mport\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 65\u001b[0m \u001b[43m \u001b[49m\u001b[43mbaudrate\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbaudrate\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 66\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 67\u001b[0m \u001b[43m \u001b[49m\u001b[43mparity\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mserial\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPARITY_NONE\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 68\u001b[0m \u001b[43m \u001b[49m\u001b[43mstopbits\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mserial\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mSTOPBITS_ONE\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 69\u001b[0m \u001b[43m \u001b[49m\u001b[43mbytesize\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mserial\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mEIGHTBITS\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 70\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 71\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mConnection to\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdevice\u001b[38;5;241m.\u001b[39mname, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mis established.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", |
53 | | - "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/serial/serialutil.py:244\u001b[0m, in \u001b[0;36mSerialBase.__init__\u001b[0;34m(self, port, baudrate, bytesize, parity, stopbits, timeout, xonxoff, rtscts, write_timeout, dsrdtr, inter_byte_timeout, exclusive, **kwargs)\u001b[0m\n\u001b[1;32m 241\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124munexpected keyword arguments: \u001b[39m\u001b[38;5;132;01m{!r}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mformat(kwargs))\n\u001b[1;32m 243\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m port \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 244\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", |
54 | | - "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/serial/serialposix.py:325\u001b[0m, in \u001b[0;36mSerial.open\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 323\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mOSError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m msg:\n\u001b[1;32m 324\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfd \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m--> 325\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m SerialException(msg\u001b[38;5;241m.\u001b[39merrno, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcould not open port \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m: \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mformat(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_port, msg))\n\u001b[1;32m 326\u001b[0m \u001b[38;5;66;03m#~ fcntl.fcntl(self.fd, fcntl.F_SETFL, 0) # set blocking\u001b[39;00m\n\u001b[1;32m 328\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpipe_abort_read_r, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpipe_abort_read_w \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;28;01mNone\u001b[39;00m\n", |
55 | | - "\u001b[0;31mSerialException\u001b[0m: [Errno 2] could not open port COM1: [Errno 2] No such file or directory: 'COM1'" |
56 | | - ] |
57 | | - } |
58 | | - ], |
| 41 | + "outputs": [], |
59 | 42 | "source": [ |
60 | | - "# connect to the device (adjust the port as necessary)\n", |
61 | | - "isx.connect_device_USB2(\"COM1\")" |
| 43 | + "ports = list(list_ports.comports())\n", |
| 44 | + "if ports:\n", |
| 45 | + " for port in ports:\n", |
| 46 | + " print(f\"{port.device}: {port.description}\")\n", |
| 47 | + "else:\n", |
| 48 | + " print(\"No serial ports found. Check the connection and USB driver.\")" |
62 | 49 | ] |
63 | 50 | }, |
64 | 51 | { |
65 | 52 | "cell_type": "code", |
66 | 53 | "execution_count": null, |
67 | | - "id": "fa54e5a6", |
| 54 | + "id": "connect", |
68 | 55 | "metadata": {}, |
69 | 56 | "outputs": [], |
70 | 57 | "source": [ |
71 | | - "# reset the system (clear previous settings)\n", |
72 | | - "isx.ResetSystem()" |
| 58 | + "PORT = \"COM3\" # Change this to the port shown above.\n", |
| 59 | + "\n", |
| 60 | + "isx = ISX_3()\n", |
| 61 | + "isx.connect_device_USB2(PORT, timeout=1)\n", |
| 62 | + "print(f\"Connected to {PORT}\")" |
| 63 | + ] |
| 64 | + }, |
| 65 | + { |
| 66 | + "cell_type": "markdown", |
| 67 | + "id": "configuration-help", |
| 68 | + "metadata": {}, |
| 69 | + "source": [ |
| 70 | + "## Configure the sweep\n", |
| 71 | + "\n", |
| 72 | + "Amplitude is specified as peak amplitude in millivolts. The example uses a four-point measurement on the BNC port with automatic current ranging." |
73 | 73 | ] |
74 | 74 | }, |
75 | 75 | { |
76 | 76 | "cell_type": "code", |
77 | | - "execution_count": 4, |
78 | | - "id": "28c54b12", |
| 77 | + "execution_count": null, |
| 78 | + "id": "setup", |
79 | 79 | "metadata": {}, |
80 | 80 | "outputs": [], |
81 | 81 | "source": [ |
82 | 82 | "setup = EisMeasurementSetup(\n", |
83 | | - " start=10,\n", |
84 | | - " stop=100000,\n", |
85 | | - " step=20,\n", |
86 | | - " stepmode=\"log\",\n", |
87 | | - " avg=1,\n", |
88 | | - " amplitude=100,\n", |
| 83 | + " start=10, # Hz\n", |
| 84 | + " stop=100_000, # Hz\n", |
| 85 | + " step=20, # number of frequency points\n", |
| 86 | + " stepmode=\"log\", # \"lin\" or \"log\"\n", |
| 87 | + " avg=1, # spectra acquired by StartMeasure()\n", |
| 88 | + " amplitude=100, # mV peak amplitude\n", |
89 | 89 | " precision=1,\n", |
90 | | - " measurement_time=1,\n", |
91 | | - ")" |
| 90 | + " measurement_time=1, # reserved for API compatibility\n", |
| 91 | + ")\n", |
| 92 | + "\n", |
| 93 | + "isx.SetMeasurementSetup(setup)\n", |
| 94 | + "isx.ClearFE_Settings()\n", |
| 95 | + "isx.SetFE_Settings(\n", |
| 96 | + " PP=0x02, # four-point configuration\n", |
| 97 | + " CH=0x01, # BNC port / ISX-3mini port 1\n", |
| 98 | + " RA=0x00, # automatic current range\n", |
| 99 | + ")\n", |
| 100 | + "\n", |
| 101 | + "print(\"Frontend:\", isx.GetFE_Settings())\n", |
| 102 | + "print(\"Frequencies [Hz]:\", isx.GetSetup())" |
92 | 103 | ] |
93 | 104 | }, |
94 | 105 | { |
95 | | - "cell_type": "code", |
96 | | - "execution_count": null, |
97 | | - "id": "e8cf6f6b", |
| 106 | + "cell_type": "markdown", |
| 107 | + "id": "measurement-help", |
98 | 108 | "metadata": {}, |
99 | | - "outputs": [], |
100 | 109 | "source": [ |
101 | | - "isx.SetMeasurementSetup(setup)" |
| 110 | + "## Measure and plot one spectrum\n", |
| 111 | + "\n", |
| 112 | + "`StartMeasure()` uses `setup.avg` when no spectrum count is passed explicitly. Each result contains the frequency-row ID and the complex impedance in ohms." |
102 | 113 | ] |
103 | 114 | }, |
104 | 115 | { |
105 | 116 | "cell_type": "code", |
106 | 117 | "execution_count": null, |
107 | | - "id": "2a8c956e", |
| 118 | + "id": "measure", |
108 | 119 | "metadata": {}, |
109 | 120 | "outputs": [], |
110 | 121 | "source": [ |
111 | | - "# disconnect device from serial port\n", |
112 | | - "isx.disconnect_device_USB2()" |
| 122 | + "points = isx.StartMeasure()\n", |
| 123 | + "if not points:\n", |
| 124 | + " raise RuntimeError(\n", |
| 125 | + " \"No measurement points received. Check the frontend, sample, and serial timeout.\"\n", |
| 126 | + " )\n", |
| 127 | + "\n", |
| 128 | + "row_ids = [point.frequency_id for point in points]\n", |
| 129 | + "impedances = [point.impedance for point in points]\n", |
| 130 | + "\n", |
| 131 | + "for point in points:\n", |
| 132 | + " print(\n", |
| 133 | + " f\"row={point.frequency_id:3d}, \"\n", |
| 134 | + " f\"Z={point.impedance.real:.6g} {point.impedance.imag:+.6g}j ohm\"\n", |
| 135 | + " )\n", |
| 136 | + "\n", |
| 137 | + "fig, ax = plt.subplots()\n", |
| 138 | + "ax.plot(row_ids, [abs(value) for value in impedances], \"o-\")\n", |
| 139 | + "ax.set(\n", |
| 140 | + " xlabel=\"Frequency-row ID\",\n", |
| 141 | + " ylabel=\"|Z| [ohm]\",\n", |
| 142 | + " title=\"ISX-3 impedance spectrum\",\n", |
| 143 | + ")\n", |
| 144 | + "ax.grid(True)\n", |
| 145 | + "plt.show()" |
| 146 | + ] |
| 147 | + }, |
| 148 | + { |
| 149 | + "cell_type": "markdown", |
| 150 | + "id": "disconnect-help", |
| 151 | + "metadata": {}, |
| 152 | + "source": [ |
| 153 | + "## Disconnect\n", |
| 154 | + "\n", |
| 155 | + "Always close the connection before reconnecting with this notebook or the official software." |
113 | 156 | ] |
114 | 157 | }, |
115 | 158 | { |
116 | 159 | "cell_type": "code", |
117 | 160 | "execution_count": null, |
118 | | - "id": "1cf1c447", |
| 161 | + "id": "disconnect", |
119 | 162 | "metadata": {}, |
120 | 163 | "outputs": [], |
121 | | - "source": [] |
| 164 | + "source": [ |
| 165 | + "isx.disconnect_device_USB2()\n", |
| 166 | + "print(\"Disconnected\")" |
| 167 | + ] |
122 | 168 | } |
123 | 169 | ], |
124 | 170 | "metadata": { |
125 | 171 | "kernelspec": { |
126 | | - "display_name": "base", |
| 172 | + "display_name": "Python 3", |
127 | 173 | "language": "python", |
128 | 174 | "name": "python3" |
129 | 175 | }, |
130 | 176 | "language_info": { |
131 | | - "codemirror_mode": { |
132 | | - "name": "ipython", |
133 | | - "version": 3 |
134 | | - }, |
135 | | - "file_extension": ".py", |
136 | | - "mimetype": "text/x-python", |
137 | 177 | "name": "python", |
138 | | - "nbconvert_exporter": "python", |
139 | | - "pygments_lexer": "ipython3", |
140 | | - "version": "3.12.2" |
| 178 | + "version": "3.10" |
141 | 179 | } |
142 | 180 | }, |
143 | 181 | "nbformat": 4, |
|
0 commit comments