diff --git a/include/aare/decode.hpp b/include/aare/decode.hpp index 96a5645..c339709 100644 --- a/include/aare/decode.hpp +++ b/include/aare/decode.hpp @@ -6,12 +6,11 @@ #include 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 input, - NDView output); + NDView output); void adc_sar_05_decode64to16(NDView input, NDView output); void adc_sar_04_decode64to16(NDView input, @@ -22,19 +21,29 @@ void adc_sar_04_decode64to16(NDView 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 input, NDView output, BitOffset offset={}); +void expand24to32bit(NDView input, NDView 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 input, NDView output); /** * @brief Apply custom weights to a 16-bit input value. Will sum up diff --git a/python/aare/transform.py b/python/aare/transform.py index 2813045..199a74e 100644 --- a/python/aare/transform.py +++ b/python/aare/transform.py @@ -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() \ No newline at end of file diff --git a/python/src/ctb_raw_file.hpp b/python/src/ctb_raw_file.hpp index d9691d4..6deff4d 100644 --- a/python/src/ctb_raw_file.hpp +++ b/python/src/ctb_raw_file.hpp @@ -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 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 - &input, uint32_t offset){ + [](py::array_t + &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 output(buf.size / bytes_per_channel); - constexpr uint32_t bytes_per_channel = 3; //24 bit - py::array_t output(buf.size/bytes_per_channel); + NDView input_view(input.mutable_data(), + {input.size()}); + NDView output_view(output.mutable_data(), + {output.size()}); - NDView input_view(input.mutable_data(), - {input.size()}); - NDView 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 + &input) { + py::buffer_info buf = input.request(); - }); + py::array_t output(buf.size * 2); + + NDView input_view(input.mutable_data(), + {input.size()}); + NDView output_view(output.mutable_data(), + {output.size()}); + + aare::expand4to8bit(input_view, output_view); + return output; + }); m.def("decode_my302", - [](py::array_t - &input, uint32_t offset){ + [](py::array_t + &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 output(channels * counters); - py::buffer_info buf = input.request(); - py::array_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 input_view(input.mutable_data() + step * i, + {input.size() / n_outputs}); + NDView 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 input_view(input.mutable_data()+step*i, - {input.size()/n_outputs}); - NDView 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_(m, "CtbRawFile") .def(py::init()) diff --git a/src/PixelMap.cpp b/src/PixelMap.cpp index 17b30c6..5a1e6e1 100644 --- a/src/PixelMap.cpp +++ b/src/PixelMap.cpp @@ -196,8 +196,8 @@ NDArray 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; } } diff --git a/src/decode.cpp b/src/decode.cpp index 34b9033..41c2e3f 100644 --- a/src/decode.cpp +++ b/src/decode.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 #include "aare/decode.hpp" -#include #include +#include 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 input, - NDView output) { + NDView 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 input, NDView 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 input, NDView output, BitOffset bit_offset){ +void expand4to8bit(NDView input, NDView 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 input, NDView 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