forked from analogdevicesinc/pyadi-iio
-
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.
Merge pull request analogdevicesinc#484 from mc-so/dev/cn0565
Add Support for CN0565.
- Loading branch information
Showing
22 changed files
with
2,204 additions
and
0 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
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,120 @@ | ||
# Copyright (C) 2023-2024 Analog Devices, Inc. | ||
# | ||
# SPDX short identifier: ADIBSD | ||
# Author: Ivan Gil Mercano <[email protected]> | ||
|
||
import numpy as np | ||
from adi.ad5940 import ad5940 | ||
from adi.adg2128 import adg2128 | ||
from adi.context_manager import context_manager | ||
|
||
|
||
class cn0565(ad5940, adg2128, context_manager): | ||
|
||
"""The CN0565 class inherits features from both the AD5940 (providing high | ||
precision in impedance and electrochemical frontend) and the ADG2128 | ||
(enabling arbitrary assignment of force and sense electrodes). ' | ||
These combined functionalities are utilized for Electrical | ||
Impedance Tomography. | ||
parameters: | ||
uri: type=string | ||
URI of the platform | ||
""" | ||
|
||
_device_name = "cn0565" | ||
|
||
def __init__(self, uri=""): | ||
context_manager.__init__(self, uri, self._device_name) | ||
ad5940.__init__(self) | ||
adg2128.__init__(self) | ||
self._switch_sequence = None | ||
self.add(0x71) | ||
self.add(0x70) | ||
self._electrode_count = 8 | ||
self._force_distance = 1 | ||
self._sense_distance = 1 | ||
self.excitation_frequency = 10000 | ||
|
||
@property | ||
def electrode_count(self): | ||
"""electrode_count: Number of electrodes""" | ||
return self._electrode_count | ||
|
||
@electrode_count.setter | ||
def electrode_count(self, value): | ||
self._electrode_count = value | ||
|
||
@property | ||
def force_distance(self): | ||
"""force_distance: Number of electrodes between forcing electrodes. 1 means they are adjacent""" | ||
return self._force_distance | ||
|
||
@force_distance.setter | ||
def force_distance(self, value): | ||
self._force_distance = value | ||
|
||
@property | ||
def sense_distance(self): | ||
"""sense_distance: Number of electrodes between sensing electrodes. 1 means they are adjacent""" | ||
return self._sense_distance | ||
|
||
@sense_distance.setter | ||
def sense_distance(self, value): | ||
self._sense_distance = value | ||
|
||
@property | ||
def switch_sequence(self): | ||
"""switch_sequence: type=np.array | ||
Sequence of combinations of forcing electrodes and sensing electrodes in the form of | ||
f+, s+, s-, s+ | ||
""" | ||
seq = 0 | ||
ret = [] | ||
for i in range(self.electrode_count): | ||
f_plus = i | ||
f_minus = (i + self.force_distance) % self.electrode_count | ||
for j in range(self.electrode_count): | ||
s_plus = j % self.electrode_count | ||
if s_plus == f_plus or s_plus == f_minus: | ||
continue | ||
s_minus = (s_plus + self.sense_distance) % self.electrode_count | ||
if s_minus == f_plus or s_minus == f_minus: | ||
continue | ||
ret.append((f_plus, s_plus, s_minus, f_minus)) | ||
seq += 1 | ||
|
||
return np.array(ret) | ||
|
||
@property | ||
def all_voltages(self): | ||
"""all_voltages: type=np.array | ||
Voltage readings from different electrode combinations | ||
""" | ||
if self._switch_sequence is None: | ||
self._switch_sequence = self.switch_sequence | ||
|
||
self.impedance_mode = False | ||
ret = [] | ||
for seq in self._switch_sequence: | ||
# reset cross point switch | ||
self.gpio1_toggle = True | ||
|
||
# set new cross point switch configuration from pregenerated sequence | ||
self._xline[seq[0]][0] = True | ||
self._xline[seq[1]][1] = True | ||
self._xline[seq[2]][2] = True | ||
self._xline[seq[3]][3] = True | ||
|
||
# read impedance | ||
s = self.channel["voltage0"].raw | ||
ret.append([s.real, s.imag]) | ||
|
||
return np.array(ret).reshape(len(ret), 2) | ||
|
||
@property | ||
def electrode_count_available(self): | ||
"""electrode_count_available: type=np.array | ||
Supported Electrode Counts | ||
""" | ||
return np.array([8, 16, 32]) |
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,7 @@ | ||
cn0565 | ||
================= | ||
|
||
.. automodule:: adi.cn0565 | ||
:members: | ||
:undoc-members: | ||
:show-inheritance: |
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 |
---|---|---|
|
@@ -86,6 +86,7 @@ Supported Devices | |
adi.cn0532 | ||
adi.cn0540 | ||
adi.cn0554 | ||
adi.cn0565 | ||
adi.cn0566 | ||
adi.cn0575 | ||
adi.cn0579 | ||
|
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,54 @@ | ||
# CN0565 | ||
## 1. Install Prerequisite: | ||
|
||
```cmd | ||
pip install -r requirements.txt | ||
pip install -e . | ||
``` | ||
From the pyadi-iio main folder, install the prerequisites. | ||
```cmd | ||
pip install -r requirements.txt | ||
``` | ||
After running this command, pip will read the requirements.txt file and install the specified packages along with their dependencies. | ||
|
||
## 2. Run Example Script: | ||
### Single Query | ||
This will perform a single impedance measurement across a given electrode combinations. | ||
``` | ||
python cn0565_example_single.py <f+> <f-> <s+> <s-> | ||
``` | ||
For example: | ||
```cmd | ||
python cn0565_example_single.py 0 3 1 2 | ||
``` | ||
This will use electrodes 0 and 3 for excitation and electrodes 1 and 2 for sensing. | ||
### Running Multiple Measurements | ||
This will perform the impedance across different possible electrode combinations. | ||
```cmd | ||
python cn0565_example.py | ||
``` | ||
### Running EIT Examples | ||
These examples uses [PyEIT](https://github.com/eitcom/pyEIT) | ||
#### Back Projection | ||
```cmd | ||
python cn0565_back_projection.py | ||
``` | ||
#### Jacobian | ||
```cmd | ||
python cn0565_jacobian.py | ||
``` | ||
#### GREIT | ||
```cmd | ||
python cn0565_greit.py | ||
``` | ||
#### All EIT Plots | ||
```cmd | ||
python cn0565_sample_plot.py | ||
``` | ||
|
||
## 3. To run the GUI: | ||
```cmd | ||
python main.py | ||
``` | ||
This will start the GUI for the Electrical Impedance Tomography Measurement System. |
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,60 @@ | ||
# Copyright (C) 2022 Analog Devices, Inc. | ||
|
||
# SPDX short identifier: ADIBSD | ||
|
||
from __future__ import absolute_import, division, print_function | ||
|
||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
import pyeit.eit.bp as bp | ||
import pyeit.eit.protocol as protocol | ||
import pyeit.mesh as mesh | ||
from adi import cn0565 | ||
from pyeit.eit.fem import EITForward | ||
from pyeit.mesh.shape import thorax | ||
from pyeit.mesh.wrapper import PyEITAnomaly_Circle | ||
|
||
# variable/board declaration | ||
value_type = "re" # re, im, others -> magnitude | ||
n_el = 16 # no of electrodes | ||
port = "COM6" | ||
baudrate = 230400 | ||
|
||
# mesh and protocol creation | ||
mesh = mesh.create(n_el, h0=0.08) | ||
protocol = protocol.create(n_el, dist_exc=1, step_meas=1, parser_meas="std") | ||
|
||
# board initialization | ||
eit_board = cn0565(uri=f"serial:{port},{baudrate},8n1") | ||
eit_board.excitation_frequency = 10000 | ||
eit_board.electrode_count = n_el | ||
eit_board.force_distance = 1 | ||
eit_board.sense_distance = 1 | ||
|
||
# boundary voltage reading | ||
voltages = eit_board.all_voltages | ||
if value_type == "re": | ||
current_data = voltages[:, 0] | ||
elif value_type == "im": | ||
current_data = voltages[:, 1] | ||
else: | ||
current_data = np.sqrt((voltages ** 2).sum(axis=1)) | ||
|
||
# Resistor array board is fixed. Use this to get absolute impedance | ||
v0 = np.full_like(current_data, 1) | ||
v1 = current_data | ||
|
||
|
||
eit = bp.BP(mesh, protocol) | ||
eit.setup(weight="none") | ||
ds = 192.0 * eit.solve(v1, v0, normalize=True) | ||
points = mesh.node | ||
triangle = mesh.element | ||
|
||
# Plot | ||
fig, ax = plt.subplots() | ||
im = ax.tripcolor(points[:, 0], points[:, 1], triangle, ds) | ||
ax.set_title(r"Impedance Measurement Using Back Projection") | ||
ax.axis("equal") | ||
fig.colorbar(im, ax=ax) | ||
plt.show() |
Oops, something went wrong.