implemented matterhorn transformer for 4 bit dynamic range

This commit is contained in:
2026-02-02 20:30:53 +01:00
parent ca03ff7e6b
commit 6604b733dc
5 changed files with 142 additions and 87 deletions

View File

@@ -6,12 +6,11 @@
#include <vector>
namespace aare {
uint16_t adc_sar_05_06_07_08decode64to16(uint64_t input);
uint16_t adc_sar_05_decode64to16(uint64_t input);
uint16_t adc_sar_04_decode64to16(uint64_t input);
void adc_sar_05_06_07_08decode64to16(NDView<uint64_t, 2> input,
NDView<uint16_t, 2> output);
NDView<uint16_t, 2> output);
void adc_sar_05_decode64to16(NDView<uint64_t, 2> input,
NDView<uint16_t, 2> output);
void adc_sar_04_decode64to16(NDView<uint64_t, 2> input,
@@ -22,19 +21,29 @@ void adc_sar_04_decode64to16(NDView<uint64_t, 2> input,
* and then return the lower 24 bits as an 32 bit integer
* @param input 32-ibt input value
* @param offset (should be in range 0-7 to allow for full 24 bits)
* @return uint32_t
* @return uint32_t
*/
uint32_t mask32to24bits(uint32_t input, BitOffset offset={});
uint32_t mask32to24bits(uint32_t input, BitOffset offset = {});
/**
* @brief Expand 24 bit values in a 8bit buffer to 32bit unsigned integers
* Used for detectors with 24bit counters in combination with CTB
*
* @param input View of the 24 bit data as uint8_t (no 24bit native data type exists)
* @param output Destination of the expanded data (32bit, unsigned)
* @param offset Offset within the first byte to where the data starts (0-7 bits)
*
* @param input View of the 24 bit data as uint8_t (no 24bit native data type
* exists)
* @param output Destination of the expanded data (32bit, unsigned)
* @param offset Offset within the first byte to where the data starts (0-7
* bits)
*/
void expand24to32bit(NDView<uint8_t,1> input, NDView<uint32_t,1> output, BitOffset offset={});
void expand24to32bit(NDView<uint8_t, 1> input, NDView<uint32_t, 1> output,
BitOffset offset = {});
/**
* @brief expands the two 4 bit values of an 8 bit buffer into two 8 bit values
* @param input input buffer with 4 bit values packed into 8 bit
* @param output output buffer with 8 bit values
*/
void expand4to8bit(NDView<uint8_t, 1> input, NDView<uint8_t, 1> output);
/**
* @brief Apply custom weights to a 16-bit input value. Will sum up

View File

@@ -24,6 +24,14 @@ class Moench05Transform:
return np.take(data.view(np.uint16), self.pixel_map)
class Moench03Transform:
def __init__(self):
self.pixel_map = _aare.GenerateMoench03PixelMap()
def __call__(self, data):
return np.take(data.view(np.uint16), self.pixel_map)
class Moench05Transform1g:
#Could be moved to C++ without changing the interface
def __init__(self):
@@ -41,6 +49,14 @@ class Moench05TransformOld:
def __call__(self, data):
return np.take(data.view(np.uint16), self.pixel_map)
class Moench04AnalogTransform:
#Could be moved to C++ without changing the interface
def __init__(self):
self.pixel_map = _aare.GenerateMoench04AnalogPixelMap()
def __call__(self, data):
return np.take(data.view(np.uint16), self.pixel_map)
class Matterhorn02TransceiverTransform:
#Could be moved to C++ without changing the interface
def __init__(self):
@@ -49,10 +65,9 @@ class Matterhorn02TransceiverTransform:
def __call__(self, data):
return np.take(data.view(np.uint16), self.pixel_map)
# TODO: give a reasonable name
class Matterhorn02Transform:
class Matterhorn10Transform:
def __init__(self, dynamic_range : int, num_counters : int):
self.pixel_map = _aare.GenerateMatterhorn2PixelMap(dynamic_range, num_counters)
self.pixel_map = _aare.GenerateMatterhorn10PixelMap(dynamic_range, num_counters)
self.dynamic_range = dynamic_range
self.num_counters = num_counters
@@ -61,9 +76,8 @@ class Matterhorn02Transform:
return np.take(data.view(np.uint16), self.pixel_map)
elif self.dynamic_range == 8:
return np.take(data.view(np.uint8), self.pixel_map)
else:
return 0
#return np.take(data.view()) # TODO need to expand to 8 bits
else: #dynamic range 4
return np.take(_aare.expand4to8bit(data.view(np.uint8)), self.pixel_map)
class Mythen302Transform:
"""
@@ -107,7 +121,7 @@ class Mythen302Transform:
moench05 = Moench05Transform()
moench05_1g = Moench05Transform1g()
moench05_old = Moench05TransformOld()
matterhorn02 = Matterhorn02Transform()
matterhorn02 = Matterhorn02TransceiverTransform()
adc_sar_04_64to16 = AdcSar04Transform64to16()
adc_sar_05_64to16 = AdcSar05Transform64to16()
adc_sar_05_06_07_08_64to16 = AdcSar05060708Transform64to16()

View File

@@ -50,7 +50,7 @@ void define_ctb_raw_file_io_bindings(py::module &m) {
return output;
});
m.def("adc_sar_05_decode64to16", [](py::array_t<uint8_t> input) {
if (input.ndim() != 2) {
throw std::runtime_error(
@@ -121,67 +121,81 @@ void define_ctb_raw_file_io_bindings(py::module &m) {
});
m.def("expand24to32bit",
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
&input, uint32_t offset){
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
&input,
uint32_t offset) {
aare::BitOffset bitoff(offset);
py::buffer_info buf = input.request();
aare::BitOffset bitoff(offset);
py::buffer_info buf = input.request();
constexpr uint32_t bytes_per_channel = 3; // 24 bit
py::array_t<uint32_t> output(buf.size / bytes_per_channel);
constexpr uint32_t bytes_per_channel = 3; //24 bit
py::array_t<uint32_t> output(buf.size/bytes_per_channel);
NDView<uint8_t, 1> input_view(input.mutable_data(),
{input.size()});
NDView<uint32_t, 1> output_view(output.mutable_data(),
{output.size()});
NDView<uint8_t, 1> input_view(input.mutable_data(),
{input.size()});
NDView<uint32_t, 1> output_view(output.mutable_data(),
{output.size()});
aare::expand24to32bit(input_view, output_view, bitoff);
return output;
});
aare::expand24to32bit(input_view, output_view, bitoff);
return output;
m.def("expand4to8bit",
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
&input) {
py::buffer_info buf = input.request();
});
py::array_t<uint8_t> output(buf.size * 2);
NDView<uint8_t, 1> input_view(input.mutable_data(),
{input.size()});
NDView<uint8_t, 1> output_view(output.mutable_data(),
{output.size()});
aare::expand4to8bit(input_view, output_view);
return output;
});
m.def("decode_my302",
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
&input, uint32_t offset){
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
&input,
uint32_t offset) {
// Physical layout of the chip
constexpr size_t channels = 64;
constexpr size_t counters = 3;
constexpr size_t bytes_per_channel = 3; // 24 bit
constexpr int n_outputs = 2;
// Physical layout of the chip
constexpr size_t channels = 64;
constexpr size_t counters = 3;
constexpr size_t bytes_per_channel = 3; //24 bit
constexpr int n_outputs = 2;
ssize_t expected_size = channels * counters * bytes_per_channel;
ssize_t expected_size = channels*counters*bytes_per_channel;
// If whe have an offset we need one extra byte per output
aare::BitOffset bitoff(offset);
if (bitoff.value())
expected_size += n_outputs;
//If whe have an offset we need one extra byte per output
aare::BitOffset bitoff(offset);
if(bitoff.value())
expected_size += n_outputs;
if (input.size() != expected_size) {
throw std::runtime_error(fmt::format(
"{} Expected an input size of {} bytes. Called "
"with input size of {}",
LOCATION, expected_size, input.size()));
}
if (input.size() != expected_size) {
throw std::runtime_error(
fmt::format("{} Expected an input size of {} bytes. Called "
"with input size of {}",
LOCATION, expected_size, input.size()));
}
py::buffer_info buf = input.request();
py::array_t<uint32_t> output(channels * counters);
py::buffer_info buf = input.request();
py::array_t<uint32_t> output(channels * counters);
for (int i = 0; i != n_outputs; ++i) {
auto step = input.size() / n_outputs;
auto out_step = output.size() / n_outputs;
NDView<uint8_t, 1> input_view(input.mutable_data() + step * i,
{input.size() / n_outputs});
NDView<uint32_t, 1> output_view(output.mutable_data() +
out_step * i,
{output.size() / n_outputs});
for (int i = 0; i!=n_outputs; ++i){
auto step = input.size()/n_outputs;
auto out_step = output.size()/n_outputs;
NDView<uint8_t, 1> input_view(input.mutable_data()+step*i,
{input.size()/n_outputs});
NDView<uint32_t, 1> output_view(output.mutable_data()+out_step*i,
{output.size()/n_outputs});
aare::expand24to32bit(input_view, output_view, bitoff);
}
aare::expand24to32bit(input_view, output_view, bitoff);
}
return output;
});
return output;
});
py::class_<CtbRawFile>(m, "CtbRawFile")
.def(py::init<const std::filesystem::path &>())

View File

@@ -196,8 +196,8 @@ NDArray<ssize_t, 2> GenerateMatterhorn10PixelMap(const size_t dynamic_range,
for (size_t pixel = 0; pixel < num_consecutive_pixels;
++pixel) {
pixel_map(row + counter * n_rows, col) =
pkg + pixel +
counter * n_rows * n_cols * n_counters;
pkg + pixel + row * n_cols * n_counters +
n_cols * counter;
++col;
}
}

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
#include "aare/decode.hpp"
#include <fmt/format.h>
#include <cmath>
#include <fmt/format.h>
namespace aare {
uint16_t adc_sar_05_06_07_08decode64to16(uint64_t input) {
@@ -24,7 +24,7 @@ uint16_t adc_sar_05_06_07_08decode64to16(uint64_t input) {
}
void adc_sar_05_06_07_08decode64to16(NDView<uint64_t, 2> input,
NDView<uint16_t, 2> output) {
NDView<uint16_t, 2> output) {
if (input.shape() != output.shape()) {
throw std::invalid_argument(LOCATION +
" input and output shapes must match");
@@ -139,49 +139,67 @@ void apply_custom_weights(NDView<uint16_t, 1> input, NDView<double, 1> output,
}
}
uint32_t mask32to24bits(uint32_t input, BitOffset offset){
uint32_t mask32to24bits(uint32_t input, BitOffset offset) {
constexpr uint32_t mask24bits{0xFFFFFF};
return (input >> offset.value()) & mask24bits;
}
void expand24to32bit(NDView<uint8_t,1> input, NDView<uint32_t,1> output, BitOffset bit_offset){
void expand4to8bit(NDView<uint8_t, 1> input, NDView<uint8_t, 1> output) {
ssize_t bytes_per_channel = 3; //24bit
ssize_t min_input_size = output.size()*bytes_per_channel;
if (2 * input.size() != output.size())
throw std::runtime_error(
fmt::format("Mismatch between input and output size. Input "
"size of {} requires an output of at least {} "
"bytes. Called with input size: {} output size: {}",
LOCATION, input.size(), 2 * input.size(), input.size(),
output.size()));
//if we have an offset we need one more byte in the input data
for (ssize_t i = 0; i < input.size(); ++i) {
uint8_t val = input(i);
output[2 * i] = (val & 0x0F);
output[2 * i + 1] = val & 0xF0 >> 4;
}
}
void expand24to32bit(NDView<uint8_t, 1> input, NDView<uint32_t, 1> output,
BitOffset bit_offset) {
ssize_t bytes_per_channel = 3; // 24bit
ssize_t min_input_size = output.size() * bytes_per_channel;
// if we have an offset we need one more byte in the input data
if (bit_offset.value())
min_input_size += 1;
min_input_size += 1;
if (input.size() < min_input_size)
throw std::runtime_error(fmt::format(
"{} Mismatch between input and output size. Output "
"size of {} with bit offset {} requires an input of at least {} "
"bytes. Called with input size: {} output size: {}",
LOCATION, output.size(), bit_offset.value(), min_input_size, input.size(), output.size()));
LOCATION, output.size(), bit_offset.value(), min_input_size,
input.size(), output.size()));
auto* in = input.data();
auto *in = input.data();
if(bit_offset.value()){
//If there is a bit_offset we copy 4 bytes and then
//mask out the correct ones.
for (auto& v : output){
if (bit_offset.value()) {
// If there is a bit_offset we copy 4 bytes and then
// mask out the correct ones.
for (auto &v : output) {
uint32_t val{};
std::memcpy(&val, in, sizeof(val));
v = mask32to24bits(val, bit_offset);
in += bytes_per_channel;
}
}else{
//If there is no offset we can directly copy the bits
//without masking
for (auto& v : output){
}
} else {
// If there is no offset we can directly copy the bits
// without masking
for (auto &v : output) {
uint32_t val{};
std::memcpy(&val, in, 3);
v = val;
in += bytes_per_channel;
}
}
}
}
} // namespace aare