Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ Every commit must reference a relevant GitHub issue number in the title or body
(e.g. `Fix target placement crash (#42)` or `Fixes #42` in the body). CI
enforces this on PRs.

Commits should also be signed off (`git commit -s`).

## Architecture

### Subpackages
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ io = [
"crc",
"crcmod",
"pyserial",
"openlifu-sdk>=2.0.12"
"openlifu-sdk>=2.0.14"
]
sim = [
"k-wave-python==0.4.0",
Expand Down
10 changes: 9 additions & 1 deletion src/openlifu/xdc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

from .element import Element
from .transducer import Transducer, TransformedTransducer
from .transducerarray import TransducerArray, get_angle_from_gap, get_roc_from_angle
from .transducerarray import (
DeviceConfigMismatchError,
TransducerArray,
arrays_structurally_equal,
get_angle_from_gap,
get_roc_from_angle,
)

__all__ = [
"element",
Expand All @@ -11,6 +17,8 @@
"Transducer",
"TransformedTransducer",
"TransducerArray",
"DeviceConfigMismatchError",
"arrays_structurally_equal",
"get_angle_from_gap",
"get_roc_from_angle"
]
30 changes: 29 additions & 1 deletion src/openlifu/xdc/transducer.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,16 @@ class Transducer:
module_invert: Annotated[List[bool], OpenLIFUFieldData("Invert polarity", "Whether to invert the polarity of the transducer output, per module")] = field(default_factory=lambda: [False])
"""Whether to invert the polarity of the transducer output"""

def _normalize_standoff_transform(self) -> None:
self.standoff_transform = np.array(self.standoff_transform, dtype=float)
if self.standoff_transform.shape != (4, 4):
raise ValueError("standoff_transform must be a 4x4 matrix.")

def __post_init__(self):
logging.info("Initializing transducer array")
if self.name == "":
self.name = self.id
self._normalize_standoff_transform()
for element in self.elements:
element.rescale(self.units)
if self.sensitivity is None:
Expand Down Expand Up @@ -288,6 +294,7 @@ def merge(list_of_transducers:List[Transducer], offset_pins:bool=False, offset_i
merged_array.module_invert += xform_array.module_invert
for k, v in merged_attrs.items():
merged_array.__setattr__(k, v)
merged_array._normalize_standoff_transform() # pylint: disable=protected-access
return merged_array

def numelements(self):
Expand All @@ -312,7 +319,7 @@ def sort_by_pin(self):
def to_dict(self):
d = self.__dict__.copy()
d["elements"] = [element.to_dict() for element in d["elements"]]
d["standoff_transform"] = d["standoff_transform"].tolist()
d["standoff_transform"] = np.array(d["standoff_transform"], dtype=float).tolist()
return d

def to_file(self, filename):
Expand Down Expand Up @@ -393,6 +400,27 @@ def to_json(self, compact:bool=False) -> str:
else:
return json.dumps(self.to_dict(), indent=4)

@classmethod
def from_module_user_config(cls, user_config: dict) -> Transducer:
"""Build a module from its SDK user configuration.

The nonempty ``module`` dictionary supplies the geometry and calibration
arguments to :py:meth:`gen_matrix_array`. The top-level ``hwid`` is
preserved in the resulting transducer's ``attrs``. Mutable configuration
values are copied so the module can be edited independently.

A template supplied to :py:meth:`TransducerArray.from_module_user_configs`
provides array placement and mesh metadata.
"""
module_cfg = user_config.get("module")
if not isinstance(module_cfg, dict) or not module_cfg:
raise ValueError("user_config has no 'module' sub-dict (expected a nonempty dictionary)")
transducer = cls.gen_matrix_array(**copy.deepcopy(module_cfg))
hwid = user_config.get("hwid")
if hwid is not None:
transducer.attrs["hwid"] = copy.deepcopy(hwid)
return transducer

@staticmethod
def gen_matrix_array(nx=2, ny=2, pitch=1, kerf=0, units="mm", **kwargs):
"""Generate a 2D flat matrix array
Expand Down
Loading
Loading