TX array compact descriptor

tx_element_array_descriptor_a

Introduction

the tx_element_array_descriptor_a data structure is intended to be a compact description of a set of point-like monopole radiators to be placed in the world for purpose of energising the acoustic field.

It is used primarily in the handybeam.tx_array.TxArray, and for benefit of handybeam.solver.Solver and handybeam.samplers - propagators.

From python’s point of view, the data set is a numpy array of size tx_count x 16 and type numpy.float32

From OpenCL’s point of view, it is a buffer of size sizeof(float)*16*tx_count

tx_element_array_descriptor_a = np.zeros((tx_count, 16), np.float32)

The 1st dimension corresponds to each new transducer; the 2nd dimension are the fields.

The data could be shortly described as xyznnnddddap____ where:

  • xyz - xyz location of the radiator. Naturally, (0,0,0) is the origin.
  • nnn - xyz vector of normal of the radiator. set to (0,0,1) for z-oriented
  • dddd - 4 components for the transducer directivity model. set to (0,1,0,0) for omini-directional behaviour.
  • a - the amplitude ratio setting. By convention, goes from zero to unity, but negative and large values will also work. it is called “ratio” because the directivity model should contain the absolute scaling of the transducer output capability.
  • p - phase setting in radians.
  • ____ - 4x NaNs. They are these mostly for data chunk alignment, but could also be used in the future for something.

The fields are best described by looking at the source of the handybeam.tx_array.TxArray.generate_tx_array_element() below:

Usage in the source code

Python side

in tx_array.py :

tx_single_element_descriptor = np.zeros((1, 16), dtype=np.float32)
tx_single_element_descriptor.fill(np.float32(np.NaN))
tx_single_element_descriptor[0, 0] = np.float32(x)
tx_single_element_descriptor[0, 1] = np.float32(y)
tx_single_element_descriptor[0, 2] = np.float32(z)
tx_single_element_descriptor[0, 3] = np.float32(xnormal)
tx_single_element_descriptor[0, 4] = np.float32(ynormal)
tx_single_element_descriptor[0, 5] = np.float32(znormal)
tx_single_element_descriptor[0, 6] = np.float32(directivity_phase_poly1_c1)
tx_single_element_descriptor[0, 7] = np.float32(directivity_amplitude_poly2_c0)
tx_single_element_descriptor[0, 8] = np.float32(directivity_amplitude_poly2_c1)
tx_single_element_descriptor[0, 9] = np.float32(directivity_amplitude_poly2_c2)
tx_single_element_descriptor[0, 10] = np.float32(amplitude_ratio_setting)
tx_single_element_descriptor[0, 11] = np.float32(phase_setting)
tx_single_element_descriptor[0, 12] = np.float32(np.NaN)
tx_single_element_descriptor[0, 13] = np.float32(np.NaN)
tx_single_element_descriptor[0, 14] = np.float32(np.NaN)
tx_single_element_descriptor[0, 15] = np.float32(np.NaN)

Note

Historical note:

In the version 1.0, the kernel launcher assembles the tx_element_array_descriptor_a from handybeam.tx_element.TxElement. Note that this approach was refactored for performance considerations. tx_element_array_descriptor_a will be a property of a handybeam.tx_array.TxArray instance, and that will become the primary authority. The handybeam.tx_element.TxElement will become a browser-editor-visualizer only for the data.

Warning

A typical problem – if the computed field is full of NaNs – check that the data passed is of the correct shape (n,16) and type numpy.float32

OpenCL side

in _handybeam1kernel_clist.cl :

unsigned int tx_pointer_base = 16 * tx_idx;
float tx_x = cl_tx_element_array_descriptor_a[tx_pointer_base + 0];
float tx_y = cl_tx_element_array_descriptor_a[tx_pointer_base + 1];
float tx_z = cl_tx_element_array_descriptor_a[tx_pointer_base + 2];

float tx_xnormal = cl_tx_element_array_descriptor_a[tx_pointer_base + 3];
float tx_ynormal = cl_tx_element_array_descriptor_a[tx_pointer_base + 4];
float tx_znormal = cl_tx_element_array_descriptor_a[tx_pointer_base + 5];

float directivity_phase_poly1_c1 = cl_tx_element_array_descriptor_a[tx_pointer_base + 6];

float directivity_amplitude_poly2_c0 = cl_tx_element_array_descriptor_a[tx_pointer_base + 7];
float directivity_amplitude_poly2_c1 = cl_tx_element_array_descriptor_a[tx_pointer_base + 8];
float directivity_amplitude_poly2_c2 = cl_tx_element_array_descriptor_a[tx_pointer_base + 9];

float tx_amp = cl_tx_element_array_descriptor_a[tx_pointer_base + 10];
float tx_phase = cl_tx_element_array_descriptor_a[tx_pointer_base + 11];