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
6 changes: 3 additions & 3 deletions db_dvc.dvc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
outs:
- md5: 107d8598bb23a151f184ead9c8593d4a.dir
nfiles: 435
- md5: e128f63a052c85b2fce480a4e9f81e5e.dir
nfiles: 441
hash: md5
path: db_dvc
size: 1500527483
size: 1540218836
246 changes: 246 additions & 0 deletions notebooks/single_pulse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
from __future__ import annotations

import logging
import os
import sys
import time
from pathlib import Path

if os.name == 'nt':
pass
else:
pass

import numpy as np

from openlifu.bf.pulse import Pulse
from openlifu.bf.sequence import Sequence
from openlifu.db import Database
from openlifu.geo import Point
from openlifu.io.LIFUInterface import LIFUInterface
from openlifu.plan.solution import Solution

# set PYTHONPATH=%cd%\src;%PYTHONPATH%
# python notebooks/test_watertank.py

"""
Test script to automate:
1. Connect to the device.
2. Test HVController: Turn HV on/off and check voltage.
3. Test Device functionality.
"""

# Configure logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# Prevent duplicate handlers and cluttered terminal output
if not logger.hasHandlers():
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
logger.addHandler(handler)
logger.propagate = False

log_interval = 1 # seconds; you can adjust this variable as needed

# set focus
xInput = 0
yInput = 0
zInput = 50

frequency_kHz = 400 # Frequency in kHz
voltage = 20.0 # Voltage in Volts
duration_msec = 5/400 # Pulse Duration in milliseconds
interval_msec = 20 # Pulse Repetition Interval in milliseconds
num_modules = 2 # Number of modules in the system

use_external_power_supply = False # Select whether to use console or power supply

console_shutoff_temp_C = 70.0 # Console shutoff temperature in Celsius
tx_shutoff_temp_C = 70.0 # TX device shutoff temperature in Celsius
ambient_shutoff_temp_C = 70.0 # Ambient shutoff temperature in Celsius

#TODO: script_timeout_minutes = 30 # Prevent unintentionally leaving unit on for too long
#TODO: log_temp_to_csv_file = True # Log readings to only terminal or both terminal and CSV file

# Fail-safe parameters if the temperature jumps too fast
rapid_temp_shutoff_C = 40 # Cutoff temperature in Celsius if it jumps too fast
rapid_temp_shutoff_seconds = 5 # Time in seconds to reach rapid temperature shutoff
rapid_temp_increase_per_second_shutoff_C = 3 # Rapid temperature climbing shutoff in Celsius

peak_to_peak_voltage = voltage * 2 # Peak to peak voltage for the pulse

here = Path(__file__).parent.resolve()
db_path = here / ".." / "db_dvc"
db = Database(db_path)
arr = db.load_transducer(f"openlifu_{num_modules}x400_evt1_005")
arr.sort_by_pin()

target = Point(position=(xInput,yInput,zInput), units="mm")
focus = target.get_position(units="mm")
distances = np.sqrt(np.sum((focus - arr.get_positions(units="mm"))**2, 1)).reshape(1,-1)
tof = distances*1e-3 / 1500
delays = tof.max() - tof
print(f"TOF Max = {tof.max()*1e6} us")

apodizations = np.ones((1, arr.numelements()))
#active_element = 25
#active_element = np.arange(65,128)
#apodizations = np.zeros((1, arr.numelements()))
#apodizations[:, active_element-1] = 1

logger.info("Starting LIFU Test Script...")
interface = LIFUInterface(ext_power_supply=use_external_power_supply)
tx_connected, hv_connected = interface.is_device_connected()

if not use_external_power_supply and not tx_connected:
logger.warning("TX device not connected. Attempting to turn on 12V...")
interface.hvcontroller.turn_12v_on()

# Give time for the TX device to power up and enumerate over USB
time.sleep(2)

# Cleanup and recreate interface to reinitialize USB devices
interface.stop_monitoring()
del interface
time.sleep(1) # Short delay before recreating

logger.info("Reinitializing LIFU interface after powering 12V...")
interface = LIFUInterface(ext_power_supply=use_external_power_supply)

# Re-check connection
tx_connected, hv_connected = interface.is_device_connected()

if not use_external_power_supply:
if hv_connected:
logger.info(f" HV Connected: {hv_connected}")
else:
logger.error("❌ HV NOT fully connected.")
sys.exit(1)
else:
logger.info(" Using external power supply")

if tx_connected:
logger.info(f" TX Connected: {tx_connected}")
logger.info("✅ LIFU Device fully connected.")
else:
logger.error("❌ TX NOT fully connected.")
sys.exit(1)

stop_logging = False # flag to signal the logging thread to stop

# Verify communication with the devices
if not interface.txdevice.ping():
logger.error("Failed to ping the transmitter device.")
sys.exit(1)

if not use_external_power_supply and not interface.hvcontroller.ping():
logger.error("Failed to ping the console device.")
sys.exit(1)

if not use_external_power_supply:
try:
console_firmware_version = interface.hvcontroller.get_version()
logger.info(f"Console Firmware Version: {console_firmware_version}")
except Exception as e:
logger.error(f"Error querying console firmware version: {e}")
try:
tx_firmware_version = interface.txdevice.get_version()
logger.info(f"TX Firmware Version: {tx_firmware_version}")
except Exception as e:
logger.error(f"Error querying TX firmware version: {e}")

logger.info("Enumerate TX7332 chips")
num_tx_devices = interface.txdevice.enum_tx7332_devices()
if num_tx_devices == 0:
raise ValueError("No TX7332 devices found.")
elif num_tx_devices == num_modules*2:
logger.info(f"Number of TX7332 devices found: {num_tx_devices}")
numelements = 32*num_tx_devices
else:
raise Exception(f"Number of TX7332 devices found: {num_tx_devices} != 2x{num_modules}")

logger.info(f'Apodizations: {apodizations}')
logger.info(f'Delays: {delays}')

pulse = Pulse(frequency=frequency_kHz*1e3, duration=duration_msec*1e-3)

sequence = Sequence(
pulse_interval=interval_msec*1e-3,
pulse_count=int(60/(interval_msec*1e-3)),
pulse_train_interval=0,
pulse_train_count=1
)

pin_order = np.argsort([el.pin for el in arr.elements])
solution = Solution(
delays = delays[:, pin_order],
apodizations = apodizations[:, pin_order],
transducer=arr,
pulse = pulse,
voltage=voltage,
sequence = sequence
)
profile_index = 1
profile_increment = True
trigger_mode = "single"

if use_external_power_supply:
logger.info(f"Using external power supply. Ensure HV is turned on and set to {voltage}V before starting the trigger.")

interface.set_solution(
solution=solution,
profile_index=profile_index,
profile_increment=profile_increment,
trigger_mode=trigger_mode)

logger.info("Get Trigger")
trigger_setting = interface.txdevice.get_trigger_json()
if trigger_setting:
logger.info(f"Trigger Setting: {trigger_setting}")
else:
logger.error("Failed to get trigger setting.")
sys.exit(1)

duty_cycle = int((duration_msec/interval_msec) * 100)
if duty_cycle > 50:
logger.warning("❗❗ Duty cycle is above 50% ❗❗")

logger.info(f"User parameters set: \n\
Module Invert: {arr.module_invert}\n\
Frequency: {frequency_kHz}kHz\n\
Voltage Per Rail: {voltage}V\n\
Voltage Peak to Peak: {peak_to_peak_voltage}V\n\
Duration: {duration_msec}ms\n\
Interval: {interval_msec}ms\n\
Duty Cycle: {duty_cycle}%\n\
Use External Power Supply: {use_external_power_supply}\n\
Initial Temp Safety Shutoff: Increase to {rapid_temp_shutoff_C}°C within {rapid_temp_shutoff_seconds}s of starting.\n\
General Temp Safety Shutoff: Increase of {rapid_temp_increase_per_second_shutoff_C}°C within {log_interval}s at any point.\n")

def turn_off_console_and_tx():
if not use_external_power_supply:
logger.info("Attempting to turn off High Voltage...")
interface.hvcontroller.turn_hv_off()
if interface.hvcontroller.get_hv_status():
logger.error("High Voltage is still on.")
else:
logger.info("High Voltage successfully turned off.")

logger.info("Attempting to turn off 12V...")
interface.hvcontroller.turn_12v_off()
if interface.hvcontroller.get_12v_status():
logger.error("12V is still on.")
else:
logger.info("12V successfully turned off.")

logger.info("turning HV ON")
interface.hvcontroller.turn_hv_on()
s = input("Press any key to start")
logger.info("Sending Single Trigger...")
interface.txdevice.start_trigger()
time.sleep(0.1)
interface.txdevice.stop_trigger()
interface.hvcontroller.turn_hv_off()
turn_off_console_and_tx()
logger.info("Finished")
2 changes: 1 addition & 1 deletion notebooks/test_first.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
# We'll start by generating a transducer and drawing it using some vtk-based methods

# %%
arr = openlifu.Transducer.gen_matrix_array(nx=8, ny=8, pitch=4, kerf=.5, units="mm", impulse_response=1e5)
arr = openlifu.Transducer.gen_matrix_array(nx=8, ny=8, pitch=4, kerf=.5, units="mm", sensitivity=1e5)
arr.draw()

# %% [markdown]
Expand Down
2 changes: 1 addition & 1 deletion notebooks/test_nifti.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

# %%

arr = openlifu.Transducer.gen_matrix_array(nx=8, ny=8, pitch=4, kerf=.5, units="mm", impulse_response=1e5)
arr = openlifu.Transducer.gen_matrix_array(nx=8, ny=8, pitch=4, kerf=.5, units="mm", sensitivity=1e5)
trans_matrix = np.array(
[[-1, 0, 0, 0],
[0, .05, np.sqrt(1-.05**2), -105],
Expand Down
3 changes: 2 additions & 1 deletion notebooks/test_solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

pulse = openlifu.Pulse(frequency=500e3, duration=2e-5)
pt = openlifu.Point(position=(0,0,30), units="mm")
example_transducer = openlifu.Transducer.gen_matrix_array(nx=8, ny=8, pitch=4, kerf=0.5, id="example_transducer")
sequence = openlifu.Sequence(
pulse_interval=0.1,
pulse_count=10,
Expand All @@ -32,7 +33,7 @@
id="solution",
name="Solution",
protocol_id="example_protocol",
transducer_id="example_transducer",
transducer=example_transducer,
delays = np.zeros((1,64)),
apodizations = np.ones((1,64)),
pulse = pulse,
Expand Down
2 changes: 1 addition & 1 deletion notebooks/test_solution_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
sim_setup=sim_setup)

target = Point(position=np.array([0, 0, 50]), units="mm", radius=2)
trans = Transducer.gen_matrix_array(nx=8, ny=8, pitch=4, kerf=0.5, id="m3", name="openlifu", impulse_response=1e6/10)
trans = Transducer.gen_matrix_array(nx=8, ny=8, pitch=4, kerf=0.5, id="m3", name="openlifu", sensitivity=1e6/10)
# -

solution, sim_res, scaled_analysis = protocol.calc_solution(
Expand Down
36 changes: 13 additions & 23 deletions notebooks/test_watertank.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
arr = db.load_transducer(f"openlifu_{num_modules}x400_evt1")
arr.sort_by_pin()


target = Point(position=(xInput,yInput,zInput), units="mm")
focus = target.get_position(units="mm")
distances = np.sqrt(np.sum((focus - arr.get_positions(units="mm"))**2, 1)).reshape(1,-1)
Expand All @@ -92,7 +93,7 @@


logger.info("Starting LIFU Test Script...")
interface = LIFUInterface()
interface = LIFUInterface(ext_power_supply=use_external_power_supply)
tx_connected, hv_connected = interface.is_device_connected()

if not use_external_power_supply and not tx_connected:
Expand All @@ -108,7 +109,7 @@
time.sleep(1) # Short delay before recreating

logger.info("Reinitializing LIFU interface after powering 12V...")
interface = LIFUInterface()
interface = LIFUInterface(ext_power_supply=use_external_power_supply)

# Re-check connection
tx_connected, hv_connected = interface.is_device_connected()
Expand Down Expand Up @@ -291,6 +292,7 @@ def log_temperature():
solution = Solution(
delays = delays[:, pin_order],
apodizations = apodizations[:, pin_order],
transducer=arr,
pulse = pulse,
voltage=voltage,
sequence = sequence
Expand All @@ -300,32 +302,19 @@ def log_temperature():
trigger_mode = "continuous"

if use_external_power_supply:
interface.check_solution(solution)
sol_dict = solution.to_dict()
interface.txdevice.set_solution(
pulse = sol_dict['pulse'],
delays = sol_dict['delays'],
apodizations= sol_dict['apodizations'],
sequence= sol_dict['sequence'],
trigger_mode=trigger_mode,
profile_index=profile_index,
profile_increment=profile_increment
)
logger.info(f"Using external power supply. Ensure HV is turned on and set to {voltage}V before starting the trigger.")
else:
interface.set_solution(
solution=solution,
profile_index=profile_index,
profile_increment=profile_increment,
trigger_mode=trigger_mode,
turn_hv_on=True)
interface.set_solution(
solution=solution,
profile_index=profile_index,
profile_increment=profile_increment,
trigger_mode=trigger_mode)

logger.info("Get Trigger")
trigger_setting = interface.txdevice.get_trigger_json()
if trigger_setting:
logger.info(f"Trigger Setting: {trigger_setting}")
else:
logger.error("Failed to sgt trigger setting.")
logger.error("Failed to get trigger setting.")
sys.exit(1)


Expand All @@ -334,6 +323,7 @@ def log_temperature():
logger.warning("❗❗ Duty cycle is above 50% ❗❗")

logger.info(f"User parameters set: \n\
Module Invert: {arr.module_invert}\n\
Frequency: {frequency_kHz}kHz\n\
Voltage Per Rail: {voltage}V\n\
Voltage Peak to Peak: {peak_to_peak_voltage}V\n\
Expand Down Expand Up @@ -385,7 +375,7 @@ def input_wrapper():
user_input = threading.Thread(target=input_wrapper)

logger.info("Starting Trigger...")
if interface.start_sonication(use_external_power_supply):
if interface.start_sonication():
logger.info("Trigger Running...")
logger.info("Press enter to STOP trigger:")

Expand All @@ -408,7 +398,7 @@ def input_wrapper():
user_input.join()

time.sleep(0.5) # Give the logging thread time to finish
if interface.stop_sonication(use_external_power_supply):
if interface.stop_sonication():
logger.info("Trigger stopped successfully.")
else:
logger.error("Failed to stop trigger.")
Expand Down
Loading
Loading