Skip to main content

Python

The Python interface to SENSUS is provided entirely by the SENSUS SDK package.

When you install the SENSUS SDK Python wheel (.whl), you are installing:

  • The Python bindings
  • The native sensus-sdk runtime libraries
    • CPU support (always included)
    • CUDA support (if using the CUDA build)

The remainder of this page assumes you have followed all steps on the Installation page and have the following ready:

Virtual Environments

Installation inside a virtual environment is strongly recommended and assumed throughout this page. The sensus-sdk package must be installed separately in each virtual environment where SENSUS is used. You can verify installation in the active environment with:

pip list | grep sensus

Integrating the Wrapper

Once the SENSUS SDK is installed, you can access the Python interface through the sensus module.

  1. Create a new Python script.
  2. Import the SensusST class and any helper functions you need.
  3. Initialise a SensusST instance with your desired configuration and backend ('CUDA' if GPU acceleration is available, otherwise 'CPU').
from sensus import SensusST, load_yaml_as_string
config = load_yaml_as_string("<path-to-config.yaml>")
pulse = SensusST(config, 'CUDA') # init with 'CPU' if GPU not available

See the examples below for typical usage patterns with the SENSUS Python integration.

tip

SensusST stands for 'Single Threaded'. There is a multi-threaded version, SensusMT, which can provide asynchronous functionality without blocking the calling thread.

Examples

The following examples demonstrate common uses of the SENSUS SDK. Some examples require additional Python packages such as numpy and matplotlib, so ensure these are installed in your environment before continuing:

pip install numpy matplotlib

2D Intensity Map

This example demonstrates how to capture a live PULSE frame, convert the data into Python structures, and visualise it as a 2D intensity map.

Create a YAML file in your Python project called sensuspython-2dexample.yaml containing the following configuration:

Click to view sensuspython-2dexample.yaml
sensuspython-2dexample.yaml
type: calyosensus
pipelines:
- id: imager_2d
reader:
type: DeviceReader
serial_number: any
num_cycles: 20
max_distance: 8
writer:
type: FrameBufferWriter
processor:
type:
stage: log_conversion
imaging_options:
algorithm: resolution
dimensions: 2
runtime_parameters:
roi:
coordinateSystem: 0 # cartesian
cartesian:
xMin: -2.5
xMax: 2.5
zMin: 0
zMax: 8
pixelSize: 0.015
polar:
rMin: 0
rMax: 8
azMinRads: -1.5707
azMaxRads: 1.5707
threshold:
db:
enabled: true
scale: -15

Then create a Python script in the same directory with the following:

pulse-2dintensitymap-example.py
from sensus import SensusST, load_yaml_as_string
from pathlib import Path
import numpy as np
import matplotlib.pyplot as plt


# Load the config file from the script directory, extract the YAML,
# and initialise a SensusST object, setting the backend to 'CUDA'
path = Path(__file__).parent / "sensuspython-2dexample.yaml"
pulse = SensusST(load_yaml_as_string(path), 'CUDA')

# Finished early indicates failure to initialise
if pulse.finished():
print(pulse.flush_logs())
raise RuntimeError("Failed to initialise")

# Flush logs to find out what's going on
print(pulse.flush_logs())

# Run the sensor for one frame and flushing out the packets
# from the frame buffer to a list
packets = pulse.acquire_single_frame()

print(f"Received {len(packets)} packets!")

# Based on the config, a single pipeline should output a single packet of type 'Mat2'
if (len(packets) == 1):
p = packets[0]
print(p['type'])

# get image dimensions from the packet
row = p['rows']
cols = p['cols']

# cast the data to a numpy array
intensity_map_packet = np.array(p['data'])

# plot the image with matplotlib
fig = plt.figure(figsize=(12,7))
ax = fig.add_subplot()
image = np.reshape(intensity_map_packet, (row, cols))
im = ax.imshow(image)
plt.show()
View expected output

SENSUS Python 2D Example Image

Capture raw signal data (XML)

In many applications, storing the raw bytes from the sensor can be beneficial, as it enables refinement of the SENSUS parameters after data capture, as if the sensor were operating live.

This approach allows for post-capture analysis and calibration of the PULSE sensor, while keeping the overall data footprint relatively small. It also opens the door to advanced use cases, such as direct analysis of the raw acoustic signals by reconstructing them from the stored bytes.

To achieve this, create a YAML file in your Python project called sensuspython-signalcapture-example.yaml containing the following configuration:

Click to view sensuspython-signalcapture-example.yaml
sensuspython-signalcapture-example.yaml
type: calyosensus
pipelines:
- id: datacapture_xml
reader:
type: DeviceReader
serial_number: any
num_cycles: 20
max_distance: 8

writer:
type: XMLWriter
output_path: ./sensuspython-signalcapture-example-data

processor:
type:
stage: passthrough

Please replace output_path: ./sensuspython-signalcapture-example-data with your desired path to store your dataset.

Then create a Python script in the same directory with the following:

sensuspython-signalcapture-example.py
from sensus import SensusST, load_yaml_as_string
from pathlib import Path

# Load the config file from the script directory, extract the YAML,
# and initialise a SensusST object, setting the backend to 'CPU'
path = Path(__file__).parent / "sensuspython-signalcapture-example.yaml"
pulse = SensusST(load_yaml_as_string(path), "CPU")

# Finished early indicates failure to initialise
if pulse.finished():
print(pulse.flush_logs())
raise RuntimeError("Failed to initialise")

# Flush logs to find out what's going on
print(pulse.flush_logs())

# Capture 20 frames
for i in range(20):
pulse.acquire_single_frame()
print(f"Captured frame {i+1}")

print("Capture complete")

Example CLI App

Coming soon