Commit: 4264df96ac72f7082e07ca3295954a470179f07c
Parent: 3fb13d375d5ed70351d03c75862ea717e64d371a
Author: Randy Palamar
Date: Tue, 13 Oct 2026 11:06:54 -0600
tests: common: basic support for HeaderV3
Diffstat:
| M | tests/test_common.c | | | 264 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
1 file changed, 163 insertions(+), 101 deletions(-)
diff --git a/tests/test_common.c b/tests/test_common.c
@@ -38,6 +38,130 @@ die_(char *function_name, char *format, ...)
os_exit(1);
}
+function void
+beamformer_simple_parameters_equip_channel_mapping(BeamformerSimpleParameters *bp, u8 *raw, u32 channel_count, i32 channel_mapping_offset)
+{
+ if (channel_mapping_offset != -1) {
+ memory_copy(bp->channel_mapping, raw + channel_mapping_offset, sizeof(*bp->channel_mapping) * channel_count);
+ } else {
+ for EachIndex(channel_count, it)
+ bp->channel_mapping[it] = it;
+ }
+}
+
+function void
+beamformer_simple_parameters_equip_emission(BeamformerSimpleParameters *bp, u8 *raw, i32 emission_descriptors_offset)
+{
+ // NOTE/TODO(rnp): only considering the first data frame right now
+ ZBP_EmissionDescriptor *ed = (ZBP_EmissionDescriptor *)(raw + emission_descriptors_offset);
+ switch (ed->emission_kind) {
+
+ case ZBP_EmissionKind_Sine:{
+ ZBP_EmissionSineParameters *ep = (ZBP_EmissionSineParameters *)(raw + ed->parameters_offset);
+ bp->emission_parameters.kind = BeamformerEmissionKind_Sine;
+ bp->emission_parameters.sine.cycles = ep->cycles;
+ bp->emission_parameters.sine.frequency = ep->frequency;
+ }break;
+
+ case ZBP_EmissionKind_Chirp:{
+ ZBP_EmissionChirpParameters *ep = (ZBP_EmissionChirpParameters *)(raw + ed->parameters_offset);
+ bp->emission_parameters.kind = BeamformerEmissionKind_Chirp;
+ bp->emission_parameters.chirp.duration = ep->duration;
+ bp->emission_parameters.chirp.min_frequency = ep->min_frequency;
+ bp->emission_parameters.chirp.max_frequency = ep->max_frequency;
+ }break;
+
+ InvalidDefaultCase;
+ static_assert(ZBP_EmissionKind_Count == (ZBP_EmissionKind_Chirp + 1), "");
+ }
+}
+
+function void
+beamformer_simple_parameters_equip_acquisition(BeamformerSimpleParameters *bp, u8 *raw,
+ BeamformerAcquisitionKind acquisition_kind,
+ i32 acquisition_parameters_offset)
+{
+ switch (acquisition_kind) {
+ case ZBP_AcquisitionKind_FORCES:{
+ ZBP_FORCESParameters *p = (ZBP_FORCESParameters *)(raw + acquisition_parameters_offset);
+ bp->transmit_receive_orientation = p->transmit_focus.transmit_receive_orientation;
+ bp->focal_vector.E[0] = p->transmit_focus.steering_angle;
+ bp->focal_vector.E[1] = p->transmit_focus.focal_depth;
+
+ bp->single_focus = 1;
+ bp->single_orientation = 1;
+ }break;
+
+ case ZBP_AcquisitionKind_HERCULES:{
+ ZBP_HERCULESParameters *p = (ZBP_HERCULESParameters *)(raw + acquisition_parameters_offset);
+ bp->transmit_receive_orientation = p->transmit_focus.transmit_receive_orientation;
+ bp->focal_vector.E[0] = p->transmit_focus.steering_angle;
+ bp->focal_vector.E[1] = p->transmit_focus.focal_depth;
+
+ bp->single_focus = 1;
+ bp->single_orientation = 1;
+ }break;
+
+ case ZBP_AcquisitionKind_UFORCES:{
+ ZBP_uFORCESParameters *p = (ZBP_uFORCESParameters *)(raw + acquisition_parameters_offset);
+ bp->transmit_receive_orientation = p->transmit_focus.transmit_receive_orientation;
+ bp->focal_vector.E[0] = p->transmit_focus.steering_angle;
+ bp->focal_vector.E[1] = p->transmit_focus.focal_depth;
+
+ bp->single_focus = 1;
+ bp->single_orientation = 1;
+
+ memory_copy(bp->sparse_elements, raw + p->sparse_elements_offset,
+ sizeof(*bp->sparse_elements) * bp->acquisition_count);
+ }break;
+
+ case ZBP_AcquisitionKind_UHERCULES:{
+ ZBP_uHERCULESParameters *p = (ZBP_uHERCULESParameters *)(raw + acquisition_parameters_offset);
+ bp->transmit_receive_orientation = p->transmit_focus.transmit_receive_orientation;
+ bp->focal_vector.E[0] = p->transmit_focus.steering_angle;
+ bp->focal_vector.E[1] = p->transmit_focus.focal_depth;
+
+ bp->single_focus = 1;
+ bp->single_orientation = 1;
+
+ memory_copy(bp->sparse_elements, raw + p->sparse_elements_offset,
+ sizeof(*bp->sparse_elements) * bp->acquisition_count);
+ }break;
+
+ case ZBP_AcquisitionKind_RCA_TPW:{
+ ZBP_TPWParameters *p = (ZBP_TPWParameters *)(raw + acquisition_parameters_offset);
+
+ memory_copy(bp->transmit_receive_orientations, raw + p->transmit_receive_orientations_offset,
+ sizeof(*bp->transmit_receive_orientations) * bp->acquisition_count);
+ memory_copy(bp->steering_angles, raw + p->tilting_angles_offset,
+ sizeof(*bp->steering_angles) * bp->acquisition_count);
+
+ for EachIndex(bp->acquisition_count, it)
+ bp->focal_depths[it] = inf32();
+ }break;
+
+ case ZBP_AcquisitionKind_RCA_VLS:{
+ ZBP_VLSParameters *p = (ZBP_VLSParameters *)(raw + acquisition_parameters_offset);
+
+ memory_copy(bp->transmit_receive_orientations, raw + p->transmit_receive_orientations_offset,
+ sizeof(*bp->transmit_receive_orientations) * bp->acquisition_count);
+
+ f32 *focal_depths = (f32 *)(raw + p->focal_depths_offset);
+ f32 *origin_offsets = (f32 *)(raw + p->origin_offsets_offset);
+
+ for EachIndex(bp->acquisition_count, it) {
+ f32 sign = Sign(focal_depths[it]);
+ f32 depth = focal_depths[it];
+ f32 origin = origin_offsets[it];
+ bp->steering_angles[it] = atan2_f32(origin, -depth) * 180.0f / PI;
+ bp->focal_depths[it] = sign * sqrt_f32(depth * depth + origin * origin);
+ }
+ }break;
+
+ InvalidDefaultCase;
+ }
+}
+
function b32
beamformer_simple_parameters_from_zbp_file(Arena *arena, BeamformerSimpleParameters *bp, char *path, ZBP_Data *raw_data, u32 *data_frame_count)
{
@@ -45,6 +169,11 @@ beamformer_simple_parameters_from_zbp_file(Arena *arena, BeamformerSimpleParamet
if (raw.length < (i64)sizeof(ZBP_BaseHeader) || ((ZBP_BaseHeader *)raw.data)->magic != ZBP_HeaderMagic)
return 0;
+ read_only BeamformerSamplingMode zbp_sampling_mode_to_beamformer[] = {
+ [ZBP_SamplingMode_Standard] = BeamformerSamplingMode_4X,
+ [ZBP_SamplingMode_Bandpass] = BeamformerSamplingMode_2X,
+ };
+
switch (((ZBP_BaseHeader *)raw.data)->major) {
case 1:{
@@ -119,33 +248,22 @@ beamformer_simple_parameters_from_zbp_file(Arena *arena, BeamformerSimpleParamet
case 2:{
ZBP_HeaderV2 *header = (ZBP_HeaderV2 *)raw.data;
-
bp->sample_count = header->sample_count;
bp->channel_count = header->channel_count;
bp->acquisition_count = header->receive_event_count;
-
- read_only BeamformerSamplingMode zbp_sampling_mode_to_beamformer[] = {
- [ZBP_SamplingMode_Standard] = BeamformerSamplingMode_4X,
- [ZBP_SamplingMode_Bandpass] = BeamformerSamplingMode_2X,
- };
- bp->sampling_mode = zbp_sampling_mode_to_beamformer[header->sampling_mode];
-
+ bp->sampling_mode = zbp_sampling_mode_to_beamformer[header->sampling_mode];
bp->acquisition_kind = (BeamformerAcquisitionKind)header->acquisition_mode;
bp->decode_mode = (BeamformerDecodeMode)header->decode_mode;
bp->sampling_frequency = header->sampling_frequency;
bp->demodulation_frequency = header->demodulation_frequency;
bp->speed_of_sound = header->speed_of_sound;
bp->time_offset = header->time_offset;
-
bp->contrast_mode = (BeamformerContrastMode)header->contrast_mode;
+ bp->data_kind = (BeamformerDataKind)header->raw_data_kind;
- if (header->channel_mapping_offset != -1) {
- memory_copy(bp->channel_mapping, raw.data + header->channel_mapping_offset,
- sizeof(*bp->channel_mapping) * bp->channel_count);
- } else {
- for EachIndex(bp->channel_count, it)
- bp->channel_mapping[it] = it;
- }
+ beamformer_simple_parameters_equip_channel_mapping(bp, raw.data, bp->channel_count, header->channel_mapping_offset);
+ beamformer_simple_parameters_equip_emission(bp, raw.data, header->emission_descriptors_offset);
+ beamformer_simple_parameters_equip_acquisition(bp, raw.data, bp->acquisition_kind, header->acquisition_parameters_offset);
memory_copy(bp->xdc_transform.E, header->transducer_transform_matrix, sizeof(bp->xdc_transform));
memory_copy(bp->xdc_element_pitch.E, header->transducer_element_pitch, sizeof(bp->xdc_element_pitch));
@@ -154,7 +272,6 @@ beamformer_simple_parameters_from_zbp_file(Arena *arena, BeamformerSimpleParamet
if (data_frame_count) *data_frame_count = header->raw_data_dimension[2];
//if (data_frame_count) *data_frame_count = header->raw_data_dimension[3];
- bp->data_kind = (BeamformerDataKind)header->raw_data_kind;
raw_data->kind = header->raw_data_kind;
raw_data->compression_kind = header->raw_data_compression_kind;
@@ -169,97 +286,42 @@ beamformer_simple_parameters_from_zbp_file(Arena *arena, BeamformerSimpleParamet
raw_data->bytes.length *= beamformer_data_kind_byte_size[header->raw_data_kind];
}
}
+ }break;
- // NOTE(rnp): only look at the first emission descriptor, other cases aren't currently relevant
- {
- ZBP_EmissionDescriptor *ed = (ZBP_EmissionDescriptor *)(raw.data + header->emission_descriptors_offset);
- switch (ed->emission_kind) {
-
- case ZBP_EmissionKind_Sine:{
- ZBP_EmissionSineParameters *ep = (ZBP_EmissionSineParameters *)(raw.data + ed->parameters_offset);
- bp->emission_parameters.kind = BeamformerEmissionKind_Sine;
- bp->emission_parameters.sine.cycles = ep->cycles;
- bp->emission_parameters.sine.frequency = ep->frequency;
- }break;
-
- case ZBP_EmissionKind_Chirp:{
- ZBP_EmissionChirpParameters *ep = (ZBP_EmissionChirpParameters *)(raw.data + ed->parameters_offset);
- bp->emission_parameters.kind = BeamformerEmissionKind_Chirp;
- bp->emission_parameters.chirp.duration = ep->duration;
- bp->emission_parameters.chirp.min_frequency = ep->min_frequency;
- bp->emission_parameters.chirp.max_frequency = ep->max_frequency;
- }break;
-
- InvalidDefaultCase;
- static_assert(ZBP_EmissionKind_Count == (ZBP_EmissionKind_Chirp + 1), "");
- }
- }
-
- switch (header->acquisition_mode) {
- case ZBP_AcquisitionKind_FORCES:{}break;
-
- case ZBP_AcquisitionKind_HERCULES:{
- ZBP_HERCULESParameters *p = (ZBP_HERCULESParameters *)(raw.data + header->acquisition_parameters_offset);
- bp->transmit_receive_orientation = p->transmit_focus.transmit_receive_orientation;
- bp->focal_vector.E[0] = p->transmit_focus.steering_angle;
- bp->focal_vector.E[1] = p->transmit_focus.focal_depth;
-
- bp->single_focus = 1;
- bp->single_orientation = 1;
- }break;
-
- case ZBP_AcquisitionKind_UFORCES:{
- ZBP_uFORCESParameters *p = (ZBP_uFORCESParameters *)(raw.data + header->acquisition_parameters_offset);
- memory_copy(bp->sparse_elements, raw.data + p->sparse_elements_offset,
- sizeof(*bp->sparse_elements) * bp->acquisition_count);
- }break;
-
- case ZBP_AcquisitionKind_UHERCULES:{
- ZBP_uHERCULESParameters *p = (ZBP_uHERCULESParameters *)(raw.data + header->acquisition_parameters_offset);
- bp->transmit_receive_orientation = p->transmit_focus.transmit_receive_orientation;
- bp->focal_vector.E[0] = p->transmit_focus.steering_angle;
- bp->focal_vector.E[1] = p->transmit_focus.focal_depth;
-
- bp->single_focus = 1;
- bp->single_orientation = 1;
-
- memory_copy(bp->sparse_elements, raw.data + p->sparse_elements_offset,
- sizeof(*bp->sparse_elements) * bp->acquisition_count);
- }break;
-
- case ZBP_AcquisitionKind_RCA_TPW:{
- ZBP_TPWParameters *p = (ZBP_TPWParameters *)(raw.data + header->acquisition_parameters_offset);
-
- memory_copy(bp->transmit_receive_orientations, raw.data + p->transmit_receive_orientations_offset,
- sizeof(*bp->transmit_receive_orientations) * bp->acquisition_count);
- memory_copy(bp->steering_angles, raw.data + p->tilting_angles_offset,
- sizeof(*bp->steering_angles) * bp->acquisition_count);
-
- for EachIndex(bp->acquisition_count, it)
- bp->focal_depths[it] = inf32();
- }break;
+ case 3:{
+ ZBP_HeaderV3 *header = (ZBP_HeaderV3 *)raw.data;
+ bp->sample_count = header->sample_count;
+ bp->channel_count = header->channel_count;
+ bp->acquisition_count = header->receive_event_count;
+ bp->sampling_mode = zbp_sampling_mode_to_beamformer[header->sampling_mode];
+ bp->acquisition_kind = (BeamformerAcquisitionKind)header->acquisition_mode;
+ bp->decode_mode = (BeamformerDecodeMode)header->decode_mode;
+ bp->sampling_frequency = header->sampling_frequency;
+ bp->speed_of_sound = header->speed_of_sound;
+ bp->contrast_mode = (BeamformerContrastMode)header->contrast_mode;
+ bp->data_kind = (BeamformerDataKind)header->raw_data_kind;
- case ZBP_AcquisitionKind_RCA_VLS:{
- ZBP_VLSParameters *p = (ZBP_VLSParameters *)(raw.data + header->acquisition_parameters_offset);
+ memory_copy(bp->xdc_element_pitch.E, header->transducer_element_pitch, sizeof(bp->xdc_element_pitch));
+ memory_copy(bp->raw_data_dimensions.E, header->raw_data_dimension, sizeof(bp->raw_data_dimensions));
+ if (data_frame_count) *data_frame_count = header->raw_data_dimension[2];
- memory_copy(bp->transmit_receive_orientations, raw.data + p->transmit_receive_orientations_offset,
- sizeof(*bp->transmit_receive_orientations) * bp->acquisition_count);
+ beamformer_simple_parameters_equip_channel_mapping(bp, raw.data, bp->channel_count, header->channel_mapping_offset);
+ beamformer_simple_parameters_equip_emission(bp, raw.data, header->emission_descriptors_offset);
+ beamformer_simple_parameters_equip_acquisition(bp, raw.data, bp->acquisition_kind, header->acquisition_parameters_offset);
- f32 *focal_depths = (f32 *)(raw.data + p->focal_depths_offset);
- f32 *origin_offsets = (f32 *)(raw.data + p->origin_offsets_offset);
+ // TODO(rnp): for now we only consider first data frame
+ memory_copy(&bp->time_offset, raw.data + header->time_delays_offset, sizeof(f32));
+ memory_copy(&bp->demodulation_frequency , raw.data + header->demodulation_frequencies_offset, sizeof(f32));
- for EachIndex(bp->acquisition_count, it) {
- f32 sign = Sign(focal_depths[it]);
- f32 depth = focal_depths[it];
- f32 origin = origin_offsets[it];
- bp->steering_angles[it] = atan2_f32(origin, -depth) * 180.0f / PI;
- bp->focal_depths[it] = sign * sqrt_f32(depth * depth + origin * origin);
- }
- }break;
+ // TODO(rnp): for now we only consider first tile
+ memory_copy(&bp->xdc_transform, raw.data + header->transducer_transforms_offset, sizeof(m4));
- InvalidDefaultCase;
+ raw_data->kind = header->raw_data_kind;
+ raw_data->compression_kind = header->raw_data_compression_kind;
+ if (header->raw_data_offset != -1) {
+ raw_data->bytes.length = header->raw_data_size;
+ raw_data->bytes.data = raw.data + header->raw_data_offset;
}
-
}break;
default:{return 0;}break;