From 149f4142465baa1fa145d5a0e05ac84856b62bea Mon Sep 17 00:00:00 2001 From: lkct Date: Thu, 30 Jun 2022 01:03:34 +0100 Subject: [PATCH 01/11] cpp mode --- tests/cpp_mode/Makefile | 46 ++++ tests/cpp_mode/main.cpp | 541 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 587 insertions(+) create mode 100644 tests/cpp_mode/Makefile create mode 100644 tests/cpp_mode/main.cpp diff --git a/tests/cpp_mode/Makefile b/tests/cpp_mode/Makefile new file mode 100644 index 0000000..b6b7596 --- /dev/null +++ b/tests/cpp_mode/Makefile @@ -0,0 +1,46 @@ +SOURCE_DIR = ../../hs_detection/detect +OBJECT_DIR = build + +# CXX = default +CPPFLAGS = -DNDEBUG -D_FORTIFY_SOURCE=2 -I$(SOURCE_DIR) +CXXFLAGS = -std=c++17 \ + -Wall -Wextra \ + -O3 -fwrapv -fstack-protector-strong -fopenmp \ + -march=native -mtune=native \ + -g +LDFLAGS = -fstack-protector-strong -fopenmp +LOADLIBES = +LDLIBS = + +HEADERS = $(wildcard $(SOURCE_DIR)/*.h) $(wildcard $(SOURCE_DIR)/*/*.h) +SOURCES = main.cpp $(wildcard $(SOURCE_DIR)/[^d]*.cpp) $(wildcard $(SOURCE_DIR)/*/*.cpp) +OBJECTS = $(addprefix $(OBJECT_DIR)/,$(notdir $(SOURCES:.cpp=.o))) +ifeq ($(OS),Windows_NT) + TARGET = main.exe +else + TARGET = main +endif + +VPATH = $(sort $(dir $(SOURCES))) + +.PHONY: all clean asm + +all: $(OBJECT_DIR)/$(TARGET) + +clean: + rm -f $(OBJECT_DIR)/*.o + rm -f $(OBJECT_DIR)/$(TARGET) + +$(OBJECT_DIR)/$(TARGET): $(OBJECTS) | $(OBJECT_DIR) + $(CXX) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +$(OBJECT_DIR)/%.o: %.cpp $(HEADERS) Makefile | $(OBJECT_DIR) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ + +$(OBJECT_DIR): + mkdir -p $(OBJECT_DIR) + +asm: $(OBJECT_DIR)/Detection.s + +$(OBJECT_DIR)/Detection.s: $(OBJECT_DIR)/Detection.o + objdump -S -r -M intel --insn-width 8 $< > $@ diff --git a/tests/cpp_mode/main.cpp b/tests/cpp_mode/main.cpp new file mode 100644 index 0000000..2add8dc --- /dev/null +++ b/tests/cpp_mode/main.cpp @@ -0,0 +1,541 @@ +#include +#include +#include +#include + +#include "Detection.h" + +using namespace std; +using namespace std::filesystem; +using namespace HSDetection; + +static constexpr char dataFn[] = "../../data/sub-MEAREC-250neuron-Neuropixels_ecephys.mda/raw.mda"; +static constexpr int dataOffset = 20; +static constexpr int dataLen = 19200000; + +static constexpr int numChannels = 384; +static constexpr int chunkSize = 100000; +static constexpr int chunkLeftMargin = 75; +static constexpr bool rescale = true; +static constexpr unsigned char scale[] = { + 0xB1, 0xAF, 0xCF, 0xC1, 0xA5, 0xF4, 0xCF, 0xC1, 0x3F, 0x64, 0xCE, 0xC1, 0x1C, 0x11, 0xC1, 0xC1, + 0x12, 0xF8, 0xBD, 0xC1, 0xC5, 0x02, 0xC7, 0xC1, 0x98, 0x04, 0xC9, 0xC1, 0xC0, 0x5B, 0xC0, 0xC1, + 0xC3, 0x69, 0xBE, 0xC1, 0xB4, 0xBE, 0xBD, 0xC1, 0xED, 0xD5, 0xBA, 0xC1, 0xC5, 0x5D, 0xBC, 0xC1, + 0x1E, 0x8B, 0xBC, 0xC1, 0x75, 0xF9, 0xBB, 0xC1, 0x9D, 0x44, 0xBD, 0xC1, 0x1D, 0xD9, 0xC4, 0xC1, + 0xDB, 0xE6, 0xC1, 0xC1, 0xC8, 0xBC, 0xA7, 0xC1, 0x4F, 0x1C, 0xB3, 0xC1, 0x09, 0xEE, 0xBB, 0xC1, + 0xD1, 0x31, 0xBD, 0xC1, 0xFD, 0x06, 0xBA, 0xC1, 0xC2, 0xB5, 0xB6, 0xC1, 0xFB, 0x79, 0xBE, 0xC1, + 0x44, 0x8B, 0xC1, 0xC1, 0xE4, 0x86, 0xBC, 0xC1, 0x3D, 0x39, 0xB4, 0xC1, 0x84, 0x9D, 0xC2, 0xC1, + 0x4A, 0x4E, 0xCA, 0xC1, 0x7B, 0x9B, 0xC9, 0xC1, 0x17, 0xCE, 0xBD, 0xC1, 0x55, 0x6D, 0xBC, 0xC1, + 0x2C, 0xB2, 0xCB, 0xC1, 0x9C, 0x57, 0xCB, 0xC1, 0x62, 0x02, 0xC5, 0xC1, 0x08, 0xAC, 0xBA, 0xC1, + 0xCA, 0xCF, 0xAD, 0xC1, 0x41, 0xB0, 0xAC, 0xC1, 0xEB, 0xE7, 0xAC, 0xC1, 0xCC, 0x7A, 0xB8, 0xC1, + 0xBF, 0x0B, 0xBB, 0xC1, 0x19, 0x0B, 0xAE, 0xC1, 0xEA, 0xC8, 0xBA, 0xC1, 0xF4, 0x88, 0xC1, 0xC1, + 0x50, 0xEB, 0xC7, 0xC1, 0xEE, 0x1A, 0xC8, 0xC1, 0xCB, 0xFE, 0xC9, 0xC1, 0x57, 0x86, 0xC9, 0xC1, + 0xF3, 0x83, 0xC1, 0xC1, 0xDE, 0x81, 0xBF, 0xC1, 0xC6, 0x2A, 0xBA, 0xC1, 0x7B, 0x9D, 0xB8, 0xC1, + 0xD3, 0x1E, 0xBB, 0xC1, 0x9F, 0x3E, 0xB3, 0xC1, 0x1A, 0x90, 0xB1, 0xC1, 0x7C, 0xC0, 0xB1, 0xC1, + 0xBE, 0xB5, 0xBA, 0xC1, 0x80, 0x97, 0xBC, 0xC1, 0x63, 0x0D, 0xB2, 0xC1, 0x4E, 0x63, 0xB4, 0xC1, + 0x9C, 0x8F, 0xB4, 0xC1, 0xB5, 0xF7, 0xAA, 0xC1, 0x32, 0xAC, 0xB2, 0xC1, 0xED, 0x7B, 0xB7, 0xC1, + 0x7B, 0x13, 0xB5, 0xC1, 0xFA, 0x57, 0xB7, 0xC1, 0xEA, 0xEB, 0xB6, 0xC1, 0xF6, 0xFB, 0xB8, 0xC1, + 0x23, 0xE1, 0xBD, 0xC1, 0xD0, 0xE0, 0xC1, 0xC1, 0xBE, 0xDE, 0xBE, 0xC1, 0xEB, 0xB5, 0xB8, 0xC1, + 0xEA, 0xF6, 0xAE, 0xC1, 0x81, 0x94, 0x9A, 0xC1, 0x68, 0x26, 0xB1, 0xC1, 0x1F, 0x20, 0xB8, 0xC1, + 0x0C, 0xFD, 0xB7, 0xC1, 0x5C, 0x16, 0xBB, 0xC1, 0x7B, 0xCF, 0xB6, 0xC1, 0xF7, 0xD1, 0xB3, 0xC1, + 0x27, 0xD7, 0xB2, 0xC1, 0xF0, 0xF3, 0xB4, 0xC1, 0x01, 0xE1, 0xB7, 0xC1, 0x21, 0xD5, 0xBE, 0xC1, + 0xB4, 0x8C, 0xBB, 0xC1, 0x75, 0xD5, 0xC1, 0xC1, 0x39, 0x41, 0xC5, 0xC1, 0xA8, 0xB4, 0xC0, 0xC1, + 0x43, 0x80, 0xBF, 0xC1, 0x63, 0xFE, 0xC7, 0xC1, 0xB9, 0xC1, 0xC7, 0xC1, 0x7A, 0xF9, 0xC6, 0xC1, + 0xD2, 0xF1, 0xC6, 0xC1, 0x44, 0xA4, 0xBD, 0xC1, 0xAC, 0x0B, 0xB0, 0xC1, 0x29, 0x6B, 0xAA, 0xC1, + 0x0A, 0x09, 0xCD, 0xC1, 0xBC, 0x86, 0xCC, 0xC1, 0x20, 0xBC, 0xC1, 0xC1, 0x15, 0xF8, 0xB3, 0xC1, + 0x0D, 0x12, 0xB7, 0xC1, 0x1D, 0x91, 0xBF, 0xC1, 0x00, 0xCB, 0xBE, 0xC1, 0x7C, 0xCC, 0xBC, 0xC1, + 0x3E, 0xFD, 0xBA, 0xC1, 0x48, 0x42, 0xB9, 0xC1, 0xAD, 0x21, 0xBC, 0xC1, 0x10, 0x4B, 0xBA, 0xC1, + 0x97, 0x60, 0xB6, 0xC1, 0x24, 0xE4, 0xB5, 0xC1, 0xB3, 0xC0, 0xBF, 0xC1, 0xF0, 0xC0, 0xC4, 0xC1, + 0x6B, 0xF7, 0xB6, 0xC1, 0xCD, 0x8E, 0xA9, 0xC1, 0x27, 0x5E, 0xB6, 0xC1, 0x59, 0x43, 0xB9, 0xC1, + 0xC7, 0x86, 0xB7, 0xC1, 0x80, 0x4E, 0xAC, 0xC1, 0xE0, 0xB5, 0xB6, 0xC1, 0x8D, 0xDA, 0xBF, 0xC1, + 0x71, 0x41, 0xC0, 0xC1, 0xBD, 0x9A, 0xB8, 0xC1, 0xCD, 0x95, 0xBB, 0xC1, 0xF7, 0xD3, 0xC5, 0xC1, + 0xDB, 0x26, 0xCA, 0xC1, 0xCD, 0xE3, 0xC5, 0xC1, 0x72, 0x0E, 0xC1, 0xC1, 0xD7, 0xCE, 0xC7, 0xC1, + 0xB9, 0xFD, 0xCD, 0xC1, 0x25, 0x46, 0xCD, 0xC1, 0x60, 0x8D, 0xC4, 0xC1, 0xED, 0x64, 0xBA, 0xC1, + 0xB4, 0x1C, 0xB0, 0xC1, 0x3F, 0xC7, 0xA8, 0xC1, 0x9E, 0xF0, 0xAF, 0xC1, 0x2A, 0xE7, 0xBB, 0xC1, + 0x05, 0x71, 0xB7, 0xC1, 0x31, 0x83, 0xB5, 0xC1, 0xB3, 0x29, 0xBA, 0xC1, 0x40, 0x0E, 0xC0, 0xC1, + 0x23, 0x7D, 0xC6, 0xC1, 0xB3, 0xCA, 0xC7, 0xC1, 0x02, 0xE5, 0xC5, 0xC1, 0x34, 0xC7, 0xC2, 0xC1, + 0x4A, 0x25, 0xBD, 0xC1, 0xD7, 0x5E, 0xBD, 0xC1, 0xC5, 0x57, 0xB7, 0xC1, 0xBC, 0x20, 0xB5, 0xC1, + 0xC0, 0xF8, 0xB5, 0xC1, 0xD3, 0x8E, 0xB0, 0xC1, 0x02, 0xCF, 0xB2, 0xC1, 0x68, 0x29, 0xB8, 0xC1, + 0x32, 0x95, 0xBA, 0xC1, 0x29, 0x9D, 0xB6, 0xC1, 0x4A, 0x43, 0xAA, 0xC1, 0x29, 0x54, 0xB3, 0xC1, + 0x06, 0x12, 0xB0, 0xC1, 0x70, 0x5B, 0xB1, 0xC1, 0x7D, 0x12, 0xB7, 0xC1, 0x6A, 0xBD, 0xB6, 0xC1, + 0x63, 0x90, 0xB4, 0xC1, 0x7C, 0x24, 0xB3, 0xC1, 0xD2, 0x36, 0xB0, 0xC1, 0x71, 0x87, 0xAC, 0xC1, + 0x8F, 0x11, 0xBA, 0xC1, 0xED, 0xA6, 0xBE, 0xC1, 0x6B, 0xAA, 0xB9, 0xC1, 0x9F, 0x9F, 0xAF, 0xC1, + 0x80, 0xD2, 0xA1, 0xC1, 0xE3, 0xD5, 0xA7, 0xC1, 0x4B, 0xEE, 0xB8, 0xC1, 0x14, 0xE3, 0xB6, 0xC1, + 0xAE, 0x2A, 0xBB, 0xC1, 0x1C, 0xE9, 0xBF, 0xC1, 0xC9, 0xB4, 0xB6, 0xC1, 0x36, 0x5F, 0xAD, 0xC1, + 0x63, 0x44, 0xB0, 0xC1, 0xA9, 0x69, 0xB8, 0xC1, 0x7E, 0xC4, 0xBD, 0xC1, 0xBA, 0xDF, 0xBD, 0xC1, + 0xB1, 0x00, 0xBC, 0xC1, 0x4B, 0x25, 0xC1, 0xC1, 0xD5, 0xBD, 0xC0, 0xC1, 0x8E, 0xD3, 0xB7, 0xC1, + 0x65, 0x2E, 0xBA, 0xC1, 0xBC, 0xBC, 0xC7, 0xC1, 0x8F, 0x51, 0xC7, 0xC1, 0xD2, 0xC8, 0xC6, 0xC1, + 0xF0, 0x09, 0xC2, 0xC1, 0x85, 0x06, 0xBA, 0xC1, 0xA8, 0x62, 0xAD, 0xC1, 0xE1, 0xE3, 0xB1, 0xC1, + 0x95, 0x5F, 0xCE, 0xC1, 0x98, 0x18, 0xCB, 0xC1, 0xFE, 0xF7, 0xBF, 0xC1, 0x18, 0x42, 0xB5, 0xC1, + 0xB8, 0xB6, 0xAF, 0xC1, 0xAD, 0x1D, 0xB7, 0xC1, 0x67, 0xA4, 0xB6, 0xC1, 0xC2, 0x22, 0xB9, 0xC1, + 0x38, 0x8A, 0xB9, 0xC1, 0x71, 0x45, 0xB5, 0xC1, 0x75, 0x11, 0xB7, 0xC1, 0x43, 0xBF, 0xB7, 0xC1, + 0x08, 0xB6, 0xB3, 0xC1, 0x55, 0xFF, 0xAE, 0xC1, 0xEB, 0x2D, 0xB8, 0xC1, 0x4C, 0x6E, 0xC2, 0xC1, + 0xE4, 0xB5, 0xBE, 0xC1, 0x36, 0x65, 0xB0, 0xC1, 0x27, 0xA3, 0xB1, 0xC1, 0xD2, 0x30, 0xB5, 0xC1, + 0x14, 0xBF, 0xB3, 0xC1, 0xAF, 0x8B, 0xAD, 0xC1, 0xEA, 0x89, 0xA9, 0xC1, 0x15, 0x51, 0xBF, 0xC1, + 0x94, 0xAE, 0xC2, 0xC1, 0x3C, 0x17, 0xBF, 0xC1, 0xCF, 0xF1, 0xBB, 0xC1, 0x49, 0x34, 0xC3, 0xC1, + 0x23, 0x16, 0xC8, 0xC1, 0x63, 0x6E, 0xC8, 0xC1, 0xB4, 0x4C, 0xC0, 0xC1, 0xEB, 0x96, 0xC4, 0xC1, + 0x93, 0x70, 0xCD, 0xC1, 0x3A, 0x53, 0xCF, 0xC1, 0x94, 0xE5, 0xCC, 0xC1, 0x02, 0x02, 0xC4, 0xC1, + 0x73, 0xC1, 0xB7, 0xC1, 0xEC, 0x17, 0xAB, 0xC1, 0xCE, 0x94, 0xA7, 0xC1, 0x18, 0x81, 0xB5, 0xC1, + 0x3E, 0xAF, 0xBC, 0xC1, 0x85, 0xC1, 0xB8, 0xC1, 0x36, 0xDF, 0xBA, 0xC1, 0xF1, 0x51, 0xB1, 0xC1, + 0x0F, 0x63, 0xC2, 0xC1, 0x33, 0x8F, 0xC5, 0xC1, 0x36, 0x83, 0xC4, 0xC1, 0xDD, 0xDD, 0xC1, 0xC1, + 0x36, 0x62, 0xBA, 0xC1, 0x29, 0xBC, 0xBD, 0xC1, 0xD7, 0x08, 0xBC, 0xC1, 0xEF, 0x4D, 0xAD, 0xC1, + 0xD3, 0xEC, 0xB3, 0xC1, 0xB1, 0x1D, 0xB1, 0xC1, 0x16, 0x01, 0xB5, 0xC1, 0x0E, 0x76, 0xB6, 0xC1, + 0x44, 0x46, 0xBD, 0xC1, 0x45, 0x1C, 0xBF, 0xC1, 0xE6, 0xFF, 0xA8, 0xC1, 0x21, 0x88, 0xB0, 0xC1, + 0x17, 0xC2, 0xB1, 0xC1, 0x0F, 0x7F, 0xAE, 0xC1, 0x4B, 0x50, 0xB5, 0xC1, 0x5D, 0x9C, 0xB4, 0xC1, + 0xC2, 0x2C, 0xB3, 0xC1, 0x5C, 0x59, 0xB1, 0xC1, 0xD1, 0x78, 0xAD, 0xC1, 0x5D, 0x1A, 0xAA, 0xC1, + 0x92, 0xC2, 0xA2, 0xC1, 0x75, 0x37, 0xBC, 0xC1, 0xF7, 0x92, 0xBD, 0xC1, 0x00, 0x65, 0xB2, 0xC1, + 0x46, 0x78, 0xA9, 0xC1, 0xA5, 0x37, 0xA8, 0xC1, 0xAB, 0xDA, 0xB6, 0xC1, 0xA4, 0x8A, 0xB9, 0xC1, + 0xF0, 0x20, 0xBD, 0xC1, 0xAD, 0xDA, 0xC0, 0xC1, 0x85, 0x9D, 0xBE, 0xC1, 0xE8, 0x77, 0xAC, 0xC1, + 0x10, 0x24, 0xAD, 0xC1, 0x12, 0xDC, 0xB7, 0xC1, 0x8E, 0x92, 0xBB, 0xC1, 0x26, 0xC7, 0xBF, 0xC1, + 0xEA, 0xA7, 0xBD, 0xC1, 0x16, 0xE4, 0xBF, 0xC1, 0xBC, 0xD3, 0xBC, 0xC1, 0xFB, 0x41, 0xB8, 0xC1, + 0x19, 0x31, 0xA9, 0xC1, 0x80, 0xE2, 0xBE, 0xC1, 0x1B, 0xDE, 0xC5, 0xC1, 0x55, 0xBD, 0xC5, 0xC1, + 0x22, 0x61, 0xC2, 0xC1, 0x42, 0x28, 0xBE, 0xC1, 0xE8, 0x7B, 0xB9, 0xC1, 0x29, 0xED, 0xB0, 0xC1, + 0xED, 0x94, 0xCD, 0xC1, 0xD0, 0x9B, 0xC4, 0xC1, 0xF8, 0x2C, 0xAF, 0xC1, 0x50, 0x1B, 0xB3, 0xC1, + 0x5B, 0x22, 0xB4, 0xC1, 0xE6, 0xE0, 0xAC, 0xC1, 0x8A, 0x63, 0xA9, 0xC1, 0x9F, 0x42, 0xB9, 0xC1, + 0x11, 0x0C, 0xB3, 0xC1, 0xA9, 0xDC, 0xAE, 0xC1, 0x1B, 0x32, 0xB3, 0xC1, 0x32, 0x83, 0xB2, 0xC1, + 0x0F, 0xF6, 0xA8, 0xC1, 0x7B, 0x98, 0xA9, 0xC1, 0x43, 0x78, 0xBB, 0xC1, 0xDD, 0xF1, 0xC0, 0xC1, + 0x04, 0x3F, 0xB6, 0xC1, 0xB3, 0x5A, 0xB4, 0xC1, 0x1B, 0x3C, 0xB2, 0xC1, 0xA3, 0x60, 0xB2, 0xC1, + 0x4E, 0xF2, 0xB6, 0xC1, 0xF9, 0xFF, 0xA3, 0xC1, 0x80, 0x9D, 0xBA, 0xC1, 0x3C, 0x41, 0xC5, 0xC1, + 0x4B, 0xFD, 0xC3, 0xC1, 0x57, 0x16, 0xBD, 0xC1, 0xFE, 0xF0, 0xBF, 0xC1, 0x9E, 0x18, 0xC7, 0xC1, + 0xCD, 0x52, 0xC9, 0xC1, 0xFC, 0x46, 0xC3, 0xC1, 0x9A, 0xAF, 0xC4, 0xC1, 0x06, 0x9E, 0xC8, 0xC1, + 0xB5, 0x3A, 0xCF, 0xC1, 0x43, 0x5A, 0xCE, 0xC1, 0xA6, 0x4D, 0xCA, 0xC1, 0xB3, 0xA8, 0xC2, 0xC1, + 0x9A, 0x9C, 0xAF, 0xC1, 0x2F, 0xD2, 0xA9, 0xC1, 0x72, 0x7A, 0xB3, 0xC1, 0x73, 0x91, 0xBE, 0xC1, + 0x21, 0xEC, 0xBE, 0xC1, 0x7E, 0x76, 0xBF, 0xC1, 0xF6, 0x87, 0xB9, 0xC1, 0x5E, 0x53, 0xBD, 0xC1, + 0x48, 0xB0, 0xC4, 0xC1, 0xD2, 0xA0, 0xC3, 0xC1, 0x2A, 0x10, 0xC1, 0xC1, 0x39, 0x70, 0xBD, 0xC1, + 0x31, 0x2B, 0xBB, 0xC1, 0x47, 0x41, 0xC0, 0xC1, 0x2B, 0xEE, 0xB7, 0xC1, 0xF9, 0x13, 0xB0, 0xC1, + 0xBF, 0x52, 0xB1, 0xC1, 0x4B, 0xB1, 0xB1, 0xC1, 0x01, 0x6C, 0xB5, 0xC1, 0xB5, 0xA4, 0xBC, 0xC1, + 0x62, 0x42, 0xC1, 0xC1, 0xBC, 0x72, 0xBB, 0xC1, 0x5F, 0x95, 0xAF, 0xC1, 0x17, 0xA0, 0xB0, 0xC1, + 0x92, 0xE2, 0xAE, 0xC1, 0xF1, 0x4C, 0xB1, 0xC1, 0x77, 0xB0, 0xB7, 0xC1, 0xA5, 0x72, 0xB6, 0xC1, + 0x79, 0x39, 0xAA, 0xC1, 0xBE, 0x13, 0xA9, 0xC1, 0xC5, 0xA7, 0xA9, 0xC1, 0x4C, 0x4D, 0xA1, 0xC1, + 0xDD, 0x3E, 0xB6, 0xC1, 0x3A, 0x17, 0xBC, 0xC1, 0x04, 0x3B, 0xB8, 0xC1, 0x02, 0xFF, 0xAF, 0xC1, + 0xE5, 0xF7, 0xA9, 0xC1, 0x88, 0xA0, 0xB4, 0xC1, 0x57, 0x2A, 0xBC, 0xC1, 0xE2, 0x3F, 0xC0, 0xC1, + 0xDC, 0x51, 0xC0, 0xC1, 0x52, 0x71, 0xC6, 0xC1, 0x78, 0x3F, 0xBE, 0xC1, 0xD2, 0x5B, 0xAF, 0xC1, + 0x93, 0xF4, 0xB3, 0xC1, 0x6C, 0x44, 0xBA, 0xC1, 0xDB, 0x0D, 0xC1, 0xC1, 0xE9, 0xF9, 0xC2, 0xC1, + 0x34, 0x6A, 0xC1, 0xC1, 0x7B, 0x87, 0xBD, 0xC1, 0xA5, 0xA3, 0xB7, 0xC1, 0x17, 0x94, 0xB4, 0xC1, + 0x5C, 0xF7, 0xB8, 0xC1, 0x14, 0x56, 0xC2, 0xC1, 0x8D, 0x2F, 0xC6, 0xC1, 0xAE, 0xA1, 0xC3, 0xC1, + 0xCF, 0x62, 0xBB, 0xC1, 0x2E, 0x9C, 0xBE, 0xC1, 0xC5, 0xF9, 0xBA, 0xC1, 0x95, 0x7C, 0xB7, 0xC1}; +static constexpr unsigned char offset[] = { + 0xB0, 0xF3, 0x4B, 0x41, 0x91, 0xBB, 0x5C, 0x41, 0xD2, 0xD7, 0x81, 0x41, 0x02, 0x17, 0xDC, 0x41, + 0xB9, 0xAA, 0x0C, 0x42, 0x34, 0xBC, 0xBD, 0x41, 0x32, 0x14, 0x8D, 0x41, 0x39, 0xE9, 0xCD, 0x41, + 0x1B, 0xE5, 0xEC, 0x41, 0x6A, 0xD9, 0xB8, 0x41, 0xF0, 0xE7, 0x83, 0x41, 0x1C, 0xB1, 0x47, 0x41, + 0x49, 0x7E, 0x6E, 0x41, 0x86, 0x51, 0x53, 0x41, 0x44, 0xC2, 0x50, 0x41, 0x8E, 0x23, 0x1F, 0x41, + 0x34, 0xDB, 0x7F, 0x41, 0xC0, 0x46, 0x24, 0x42, 0x78, 0xE6, 0x1F, 0x42, 0x22, 0xC8, 0x00, 0x42, + 0x79, 0xDD, 0x04, 0x42, 0x22, 0x03, 0x1C, 0x42, 0x87, 0xBF, 0x1B, 0x42, 0x91, 0xF7, 0xAD, 0x41, + 0xB8, 0x45, 0xB6, 0x40, 0x89, 0xCB, 0x13, 0x41, 0x29, 0x67, 0xA1, 0x41, 0x02, 0x01, 0x66, 0x41, + 0x3B, 0x81, 0x8E, 0x3F, 0xA6, 0x03, 0x71, 0xBF, 0xF1, 0x02, 0x70, 0x41, 0xD3, 0x90, 0xEC, 0x41, + 0xE3, 0xFB, 0xA9, 0x41, 0x97, 0xC7, 0x82, 0x41, 0x6C, 0xE7, 0xBB, 0x41, 0x0B, 0xAA, 0x14, 0x42, + 0x15, 0x89, 0x1C, 0x42, 0xC0, 0xF4, 0x31, 0x42, 0x49, 0x80, 0x2D, 0x42, 0x10, 0x7C, 0xDC, 0x41, + 0xBD, 0xCE, 0x83, 0x41, 0x40, 0xB0, 0xE2, 0x41, 0x2C, 0x8A, 0xCC, 0x41, 0x03, 0x40, 0x1C, 0x41, + 0x73, 0xC6, 0x9F, 0x40, 0x28, 0x2D, 0xAF, 0xBF, 0xEF, 0xD7, 0x5F, 0x40, 0x5C, 0x40, 0xCA, 0x40, + 0xBB, 0xFB, 0x5B, 0x41, 0xB0, 0xAE, 0xA6, 0x41, 0xE0, 0x8B, 0xC4, 0x41, 0x91, 0xC5, 0xD5, 0x41, + 0x42, 0x77, 0xD1, 0x41, 0xED, 0xB6, 0x0C, 0x42, 0x08, 0xA5, 0x12, 0x42, 0xCF, 0x46, 0xDA, 0x41, + 0xF4, 0xCC, 0x83, 0x41, 0xF7, 0x3C, 0x8A, 0x41, 0xDC, 0x0E, 0xE1, 0x41, 0x68, 0x8D, 0xFB, 0x41, + 0x00, 0x47, 0x01, 0x42, 0xC2, 0x40, 0x41, 0x42, 0x7F, 0x3F, 0x25, 0x42, 0x8C, 0x6B, 0x0C, 0x42, + 0x6B, 0x16, 0x20, 0x42, 0x3F, 0xD4, 0x08, 0x42, 0x6E, 0xAE, 0x09, 0x42, 0x2D, 0xDA, 0x05, 0x42, + 0xD2, 0xC8, 0xC4, 0x41, 0x15, 0xE1, 0x2F, 0x41, 0x4F, 0x17, 0x21, 0x41, 0x84, 0x5A, 0xBA, 0x41, + 0xC1, 0xAB, 0x04, 0x42, 0xA4, 0x47, 0x61, 0x42, 0xB9, 0x26, 0x4B, 0x42, 0x39, 0x65, 0xC4, 0x41, + 0x64, 0x3B, 0xDE, 0x41, 0xEB, 0xD3, 0xD0, 0x41, 0xA2, 0x52, 0xD2, 0x41, 0xA4, 0x8C, 0xC8, 0x41, + 0x72, 0x0D, 0xA8, 0x41, 0x64, 0x61, 0xC8, 0x41, 0x42, 0xA0, 0x8D, 0x41, 0x7C, 0x88, 0x9F, 0x41, + 0xE6, 0x33, 0xA1, 0x41, 0x5D, 0x19, 0xA4, 0x41, 0xF2, 0x96, 0x81, 0x41, 0x1A, 0xE4, 0x6D, 0x41, + 0x81, 0xF2, 0xA8, 0x41, 0x45, 0x88, 0x30, 0x41, 0x31, 0x71, 0x0F, 0x41, 0x25, 0x76, 0x64, 0x41, + 0x56, 0x18, 0x7B, 0x41, 0x53, 0x6D, 0xC5, 0x41, 0x10, 0x5B, 0x0C, 0x42, 0xAA, 0x7D, 0x1E, 0x42, + 0x50, 0x06, 0x82, 0x41, 0x77, 0x3F, 0x8E, 0x41, 0xC3, 0x90, 0xD3, 0x41, 0xDA, 0x37, 0x2C, 0x42, + 0xDE, 0x38, 0x3F, 0x42, 0x88, 0xBC, 0xB3, 0x41, 0x28, 0x0A, 0xAF, 0x41, 0x1B, 0xD1, 0xE4, 0x41, + 0xE1, 0x99, 0xE5, 0x41, 0xE1, 0x23, 0xED, 0x41, 0x0A, 0xB7, 0xA6, 0x41, 0xE7, 0x75, 0xA9, 0x41, + 0x3C, 0x13, 0x97, 0x41, 0x6A, 0x7B, 0x9E, 0x41, 0x85, 0xC3, 0x5F, 0x41, 0x9C, 0xB5, 0x3C, 0x41, + 0x82, 0xA2, 0xBD, 0x41, 0x69, 0xAF, 0x25, 0x42, 0x2F, 0x8B, 0x1B, 0x42, 0xD2, 0x92, 0x0F, 0x42, + 0xE9, 0x9A, 0x1B, 0x42, 0xB5, 0x22, 0x4F, 0x42, 0xFD, 0x4D, 0x1F, 0x42, 0x5F, 0x0F, 0x53, 0x41, + 0x0A, 0xED, 0xEB, 0x40, 0xED, 0x21, 0x53, 0x41, 0xFD, 0xAA, 0x8F, 0x41, 0x4D, 0x6E, 0xC2, 0x40, + 0x84, 0x57, 0x3D, 0xBF, 0x60, 0x79, 0x09, 0x40, 0x44, 0xEE, 0x82, 0x41, 0x7E, 0x96, 0x94, 0x41, + 0x51, 0xCA, 0x49, 0x41, 0x9D, 0x87, 0x81, 0x41, 0x19, 0x12, 0xCD, 0x41, 0x93, 0x2F, 0x09, 0x42, + 0x92, 0x5B, 0x23, 0x42, 0xBC, 0x96, 0x42, 0x42, 0xA3, 0x36, 0x29, 0x42, 0x1F, 0x3E, 0xB3, 0x41, + 0x17, 0x34, 0xB9, 0x41, 0xCF, 0x3C, 0xCD, 0x41, 0xE7, 0x98, 0x9C, 0x41, 0x56, 0x70, 0x8E, 0x41, + 0x20, 0xC3, 0x20, 0x3F, 0xA2, 0xDD, 0x45, 0x40, 0x03, 0xC0, 0xEF, 0x40, 0x9F, 0xC5, 0x5E, 0x41, + 0x2C, 0x6B, 0xA8, 0x41, 0x54, 0x30, 0xC3, 0x41, 0x5F, 0x5C, 0xEF, 0x41, 0x72, 0x14, 0x0A, 0x42, + 0xBC, 0xE0, 0x02, 0x42, 0x5A, 0xE7, 0x11, 0x42, 0x20, 0xE6, 0x07, 0x42, 0xAB, 0x45, 0x97, 0x41, + 0xCD, 0xB9, 0x59, 0x41, 0x66, 0x7C, 0xA4, 0x41, 0xC2, 0x68, 0x17, 0x42, 0x5B, 0xD3, 0xFA, 0x41, + 0xED, 0x0E, 0x22, 0x42, 0x7A, 0x09, 0x1D, 0x42, 0x4B, 0x10, 0x04, 0x42, 0xAF, 0xB2, 0x15, 0x42, + 0xC3, 0x9A, 0xF6, 0x41, 0xA5, 0x31, 0x20, 0x42, 0x4E, 0xA1, 0x2F, 0x42, 0xFC, 0x5B, 0x2C, 0x42, + 0xEC, 0xB6, 0x00, 0x42, 0xC8, 0xC1, 0x01, 0x41, 0xFB, 0x64, 0x60, 0x41, 0x96, 0x93, 0xCD, 0x41, + 0x0A, 0xBE, 0x37, 0x42, 0x4C, 0x0D, 0x44, 0x42, 0x01, 0xE1, 0xF2, 0x41, 0xE0, 0x9C, 0xCA, 0x41, + 0xA7, 0x8A, 0xD3, 0x41, 0x2F, 0x93, 0xB1, 0x41, 0xC5, 0xF5, 0xA2, 0x41, 0x5B, 0x3B, 0xE9, 0x41, + 0x5F, 0xDD, 0xDD, 0x41, 0xCF, 0xDE, 0xA2, 0x41, 0x0F, 0x2D, 0x7C, 0x41, 0xFF, 0x03, 0xAD, 0x41, + 0xD1, 0x8D, 0xB1, 0x41, 0xCC, 0x79, 0xA7, 0x41, 0x46, 0x65, 0xA8, 0x41, 0xEC, 0xE5, 0xDC, 0x41, + 0xDA, 0x01, 0xEF, 0x41, 0xB4, 0x13, 0x37, 0x41, 0x2F, 0x44, 0x13, 0x41, 0x76, 0xD5, 0x62, 0x41, + 0x27, 0x7A, 0x97, 0x41, 0x9D, 0x17, 0xEE, 0x41, 0x13, 0x03, 0x20, 0x42, 0xAF, 0x7E, 0x17, 0x42, + 0x2C, 0x71, 0x81, 0x41, 0x47, 0xBF, 0x8F, 0x41, 0x6F, 0xC4, 0xEE, 0x41, 0x60, 0x94, 0x29, 0x42, + 0x30, 0x22, 0x43, 0x42, 0x82, 0x8A, 0x1B, 0x42, 0x82, 0x59, 0x0D, 0x42, 0x7F, 0x6F, 0xEA, 0x41, + 0x20, 0x14, 0xE0, 0x41, 0x99, 0x64, 0x10, 0x42, 0x9E, 0x62, 0x02, 0x42, 0x25, 0x95, 0xD4, 0x41, + 0x1F, 0x85, 0xD4, 0x41, 0xA6, 0x47, 0xDB, 0x41, 0x8E, 0xA9, 0xBD, 0x41, 0x44, 0x98, 0x36, 0x41, + 0xE7, 0x76, 0x61, 0x41, 0x45, 0x7A, 0x02, 0x42, 0x63, 0x2E, 0x19, 0x42, 0x5C, 0xF7, 0x12, 0x42, + 0x22, 0x9B, 0x21, 0x42, 0x21, 0x5F, 0x42, 0x42, 0xC1, 0x13, 0x52, 0x42, 0x4A, 0xDD, 0xBC, 0x41, + 0x5C, 0x09, 0xD1, 0x40, 0x92, 0x47, 0x16, 0x41, 0x8A, 0x70, 0x7E, 0x41, 0xFC, 0xA6, 0x73, 0x41, + 0x49, 0x9C, 0x77, 0x40, 0x07, 0xCA, 0x04, 0xC0, 0x9B, 0x9B, 0x18, 0x41, 0xAA, 0xCA, 0x1C, 0x41, + 0x70, 0xDE, 0x45, 0x41, 0x7B, 0x9B, 0x17, 0x41, 0x4D, 0xE2, 0x4F, 0x41, 0x5A, 0x81, 0xB5, 0x41, + 0x59, 0xB2, 0x02, 0x42, 0x36, 0x13, 0x3F, 0x42, 0x08, 0xEC, 0x57, 0x42, 0x4C, 0x42, 0x14, 0x42, + 0x38, 0x57, 0x99, 0x41, 0xCC, 0x31, 0xB4, 0x41, 0xBB, 0x6D, 0x9C, 0x41, 0x35, 0x49, 0xBC, 0x41, + 0x9D, 0xF7, 0x3C, 0x41, 0x3C, 0x26, 0x40, 0x40, 0x96, 0xA6, 0xA8, 0x40, 0xF2, 0x82, 0x3F, 0x41, + 0x39, 0x8E, 0xAD, 0x41, 0x90, 0xB8, 0xBF, 0x41, 0x52, 0x30, 0xC9, 0x41, 0xCD, 0xDF, 0x24, 0x42, + 0x43, 0xC3, 0x1F, 0x42, 0x88, 0xC3, 0x13, 0x42, 0xD5, 0x76, 0x06, 0x42, 0x91, 0x2E, 0xB1, 0x41, + 0x0D, 0x47, 0x3C, 0x41, 0x0E, 0x14, 0x14, 0x41, 0x9B, 0x98, 0x02, 0x42, 0x2F, 0x3B, 0x09, 0x42, + 0x0D, 0x76, 0xFF, 0x41, 0xD6, 0xC0, 0x1E, 0x42, 0x0C, 0x68, 0x00, 0x42, 0x09, 0x94, 0x04, 0x42, + 0x77, 0x72, 0x04, 0x42, 0xFA, 0x6F, 0x17, 0x42, 0xC8, 0x10, 0x32, 0x42, 0x16, 0x16, 0x44, 0x42, + 0xC5, 0x90, 0x37, 0x42, 0xEA, 0x77, 0x86, 0x41, 0xEB, 0xA0, 0xF6, 0x40, 0xEF, 0x0E, 0x7F, 0x41, + 0x78, 0x2C, 0x0C, 0x42, 0xEB, 0xC9, 0x2C, 0x42, 0xFD, 0xC0, 0xF4, 0x41, 0xD2, 0x93, 0xC9, 0x41, + 0xF5, 0x6A, 0xC9, 0x41, 0x45, 0x57, 0xC1, 0x41, 0xEA, 0x8B, 0x9C, 0x41, 0xAC, 0x9B, 0xEC, 0x41, + 0x10, 0x3B, 0x09, 0x42, 0x96, 0x14, 0xC4, 0x41, 0x70, 0xE4, 0x76, 0x41, 0xB1, 0xD9, 0x85, 0x41, + 0x25, 0x62, 0x8F, 0x41, 0xA4, 0x1C, 0x9E, 0x41, 0x4A, 0x85, 0xD1, 0x41, 0xB7, 0x4A, 0xEE, 0x41, + 0x7A, 0x51, 0x16, 0x42, 0x0F, 0xE5, 0xE6, 0x41, 0x19, 0x2F, 0x2C, 0x41, 0x1D, 0x90, 0x64, 0x41, + 0x70, 0xF0, 0x73, 0x41, 0x71, 0xD3, 0xC3, 0x41, 0x5B, 0x38, 0xF7, 0x41, 0x22, 0x5F, 0x14, 0x42, + 0x2C, 0xE1, 0x85, 0x41, 0x5D, 0x71, 0xC8, 0x41, 0xF3, 0x3B, 0x31, 0x42, 0x98, 0x11, 0x34, 0x42, + 0xE8, 0x64, 0x1D, 0x42, 0x5B, 0x3A, 0x1D, 0x42, 0x40, 0xF8, 0x46, 0x42, 0xD3, 0xC4, 0xF6, 0x41, + 0x8B, 0x0D, 0xFF, 0x41, 0xFA, 0x0C, 0x14, 0x42, 0xAD, 0x05, 0xF0, 0x41, 0x94, 0x38, 0xFE, 0x41, + 0x7F, 0x52, 0xE6, 0x41, 0x70, 0x5D, 0xF3, 0x41, 0x27, 0xE9, 0x9E, 0x41, 0x01, 0xE7, 0x0F, 0x41, + 0x0E, 0x1D, 0xA8, 0x41, 0x1E, 0x33, 0x0B, 0x42, 0x1B, 0x6C, 0xF4, 0x41, 0xA6, 0xD0, 0x1F, 0x42, + 0xC4, 0xCC, 0x16, 0x42, 0xF0, 0x68, 0x4E, 0x42, 0x64, 0x82, 0x03, 0x42, 0x0D, 0xAC, 0x35, 0x41, + 0xE1, 0x70, 0x9C, 0x40, 0xA2, 0x67, 0x29, 0x41, 0xB5, 0x9D, 0x89, 0x41, 0x32, 0x83, 0xFF, 0x40, + 0xDA, 0x39, 0x13, 0xC0, 0xA4, 0xA4, 0x8B, 0x40, 0x17, 0xC3, 0x02, 0x41, 0x86, 0xE8, 0x5D, 0x41, + 0x4F, 0x19, 0xD0, 0x40, 0x1E, 0x6E, 0xF5, 0x40, 0x46, 0x10, 0x3B, 0x41, 0x7E, 0x82, 0x92, 0x41, + 0xB2, 0x5F, 0x22, 0x42, 0x53, 0xE4, 0x59, 0x42, 0xDE, 0x19, 0x2F, 0x42, 0xAB, 0x45, 0xA5, 0x41, + 0x92, 0x6E, 0x84, 0x41, 0x5E, 0x41, 0x7F, 0x41, 0xAD, 0x72, 0x93, 0x41, 0x7B, 0x53, 0x5D, 0x41, + 0x30, 0x37, 0x89, 0x40, 0x93, 0xE1, 0x80, 0x40, 0xB6, 0x4B, 0x36, 0x41, 0x08, 0xEF, 0x7D, 0x41, + 0xB5, 0xE8, 0xBD, 0x41, 0xDC, 0x62, 0xBE, 0x41, 0x72, 0x4E, 0x0C, 0x42, 0xCF, 0x28, 0x2C, 0x42, + 0x92, 0x3F, 0x15, 0x42, 0x6E, 0x4C, 0x14, 0x42, 0xC9, 0xEF, 0xC7, 0x41, 0x63, 0xE4, 0x7C, 0x41, + 0xAE, 0x89, 0x0A, 0x41, 0xC5, 0x0B, 0x5C, 0x41, 0xBD, 0x42, 0xEE, 0x41, 0x6F, 0x75, 0x01, 0x42, + 0x6E, 0x1F, 0x07, 0x42, 0x0B, 0x31, 0x0C, 0x42, 0xCE, 0xAC, 0x06, 0x42, 0xA1, 0x55, 0xE3, 0x41, + 0x12, 0xF2, 0x0B, 0x42, 0x6A, 0x22, 0x2E, 0x42, 0x51, 0x52, 0x32, 0x42, 0xF7, 0xD2, 0x41, 0x42, + 0x46, 0x35, 0xE9, 0x41, 0x54, 0x75, 0x16, 0x41, 0xF5, 0xB9, 0x08, 0x41, 0xB6, 0xB8, 0xA4, 0x41, + 0xA9, 0xC0, 0x08, 0x42, 0x94, 0xBC, 0xE7, 0x41, 0xC7, 0xCE, 0xB6, 0x41, 0xD9, 0xEB, 0x99, 0x41, + 0xE6, 0x3F, 0xA9, 0x41, 0x86, 0x6B, 0x87, 0x41, 0xB3, 0xFC, 0x9F, 0x41, 0x6C, 0xC0, 0x02, 0x42, + 0x84, 0x32, 0xF0, 0x41, 0x20, 0xBB, 0xA7, 0x41, 0x5D, 0x56, 0x68, 0x41, 0x03, 0x6E, 0x6B, 0x41, + 0x3A, 0xB8, 0x83, 0x41, 0xA9, 0x74, 0xBC, 0x41, 0xC7, 0x20, 0x01, 0x42, 0x36, 0xF3, 0x13, 0x42, + 0xBD, 0x09, 0xFF, 0x41, 0xE4, 0x40, 0x7D, 0x41, 0x2A, 0xEC, 0x6B, 0x41, 0x2E, 0x9F, 0x8B, 0x41, + 0x40, 0xD3, 0xC6, 0x41, 0xA2, 0x8C, 0xDB, 0x41, 0x1C, 0x5D, 0xFB, 0x41, 0xC6, 0x25, 0x0F, 0x42}; +static constexpr bool medianReference = false; +static constexpr bool averageReference = true; +static constexpr int spikeDur = 32; +static constexpr int ampAvgDur = 13; +static constexpr float threshold = 10.0; +static constexpr float minAvgAmp = 5.0; +static constexpr float maxAHPAmp = 0.0; +static constexpr unsigned char channelPositions[] = { + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xEE, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xE9, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xE4, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xDF, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xDA, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xD5, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xD0, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xCB, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xC6, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xC1, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xBC, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xB7, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xB2, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xAD, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xA8, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0xA3, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0x9E, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0x99, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0x94, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0x8F, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0x8A, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0x85, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0xC0, 0x80, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x77, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x6D, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x63, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x59, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x4F, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x45, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x3B, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x31, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x27, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x1D, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x13, 0xC4, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x09, 0xC4, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xFF, 0xC3, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xEB, 0xC3, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xD7, 0xC3, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xC3, 0xC3, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xAF, 0xC3, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x9B, 0xC3, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x87, 0xC3, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x66, 0xC3, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x3E, 0xC3, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x16, 0xC3, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xDC, 0xC2, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x8C, 0xC2, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xF0, 0xC1, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x20, 0x41, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x48, 0x42, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xB4, 0x42, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x02, 0x43, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x2A, 0x43, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x52, 0x43, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x7A, 0x43, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0x91, 0x43, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xA5, 0x43, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xB9, 0x43, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xCD, 0x43, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xE1, 0x43, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x00, 0xF5, 0x43, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x04, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x0E, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x18, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x22, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x2C, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x36, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x40, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x4A, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x54, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x5E, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x68, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x72, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x80, 0x7C, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0x83, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0x88, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0x8D, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0x92, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0x97, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0x9C, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xA1, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xA6, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xAB, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xB0, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xB5, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xBA, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xBF, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xC4, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xC9, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xCE, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xD3, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xD8, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xDD, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xE2, 0x44, + 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xE7, 0x44, 0x00, 0x00, 0xC0, 0xC1, 0x00, 0x40, 0xEC, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xEC, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xE7, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xE2, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xDD, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xD8, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xD3, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xCE, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xC9, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xC4, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xBF, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xBA, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xB5, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xB0, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xAB, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xA6, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0xA1, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0x9C, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0x97, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0x92, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0x8D, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0x88, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x40, 0x83, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x7C, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x72, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x68, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x5E, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x54, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x4A, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x40, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x36, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x2C, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x22, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x18, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x0E, 0xC4, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x04, 0xC4, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xF5, 0xC3, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xE1, 0xC3, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xCD, 0xC3, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xB9, 0xC3, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xA5, 0xC3, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x91, 0xC3, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x7A, 0xC3, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x52, 0xC3, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x2A, 0xC3, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x02, 0xC3, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xB4, 0xC2, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x48, 0xC2, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x20, 0xC1, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xF0, 0x41, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x8C, 0x42, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xDC, 0x42, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x16, 0x43, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x3E, 0x43, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x66, 0x43, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x87, 0x43, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x9B, 0x43, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xAF, 0x43, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xC3, 0x43, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xD7, 0x43, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xEB, 0x43, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0xFF, 0x43, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x09, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x13, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x1D, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x27, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x31, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x3B, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x45, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x4F, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x59, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x63, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x6D, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0x80, 0x77, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0x80, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0x85, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0x8A, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0x8F, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0x94, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0x99, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0x9E, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xA3, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xA8, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xAD, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xB2, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xB7, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xBC, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xC1, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xC6, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xCB, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xD0, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xD5, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xDA, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xDF, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xE4, 0x44, + 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xE9, 0x44, 0x00, 0x00, 0x00, 0xC1, 0x00, 0xC0, 0xEE, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xEE, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xE9, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xE4, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xDF, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xDA, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xD5, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xD0, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xCB, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xC6, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xC1, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xBC, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xB7, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xB2, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xAD, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xA8, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0xA3, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0x9E, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0x99, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0x94, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0x8F, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0x8A, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0x85, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0xC0, 0x80, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x77, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x6D, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x63, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x59, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x4F, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x45, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x3B, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x31, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x27, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x1D, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x13, 0xC4, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x09, 0xC4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xFF, 0xC3, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xEB, 0xC3, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xD7, 0xC3, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xAF, 0xC3, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x9B, 0xC3, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x87, 0xC3, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x66, 0xC3, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x3E, 0xC3, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x16, 0xC3, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xDC, 0xC2, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x8C, 0xC2, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xF0, 0xC1, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x20, 0x41, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x48, 0x42, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xB4, 0x42, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x02, 0x43, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x2A, 0x43, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x52, 0x43, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x7A, 0x43, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x91, 0x43, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xA5, 0x43, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xB9, 0x43, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xCD, 0x43, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xE1, 0x43, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xF5, 0x43, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x04, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x0E, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x18, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x22, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x2C, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x36, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x40, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x4A, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x54, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x5E, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x68, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x72, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x80, 0x7C, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0x83, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0x88, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0x8D, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0x92, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0x97, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0x9C, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xA1, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xA6, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xAB, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xB0, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xB5, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xBA, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xBF, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xC4, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xC9, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xCE, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xD3, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xD8, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xDD, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xE2, 0x44, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xE7, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x40, 0xEC, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xEC, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xE7, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xE2, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xDD, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xD8, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xD3, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xCE, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xC9, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xC4, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xBF, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xBA, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xB5, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xB0, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xAB, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xA6, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0xA1, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0x9C, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0x97, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0x92, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0x8D, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0x88, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x40, 0x83, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x7C, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x72, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x68, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x5E, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x54, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x4A, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x40, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x36, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x2C, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x22, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x18, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x0E, 0xC4, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x04, 0xC4, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xF5, 0xC3, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xE1, 0xC3, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xCD, 0xC3, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xB9, 0xC3, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xA5, 0xC3, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x91, 0xC3, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x7A, 0xC3, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x52, 0xC3, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x2A, 0xC3, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x02, 0xC3, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xB4, 0xC2, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x48, 0xC2, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x20, 0xC1, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xF0, 0x41, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x8C, 0x42, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xDC, 0x42, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x16, 0x43, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x3E, 0x43, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x66, 0x43, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x87, 0x43, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0x9B, 0x43, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xAF, 0x43, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xC3, 0x43, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xD7, 0x43, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xEB, 0x43, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x00, 0xFF, 0x43, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x09, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x13, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x1D, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x27, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x31, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x3B, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x45, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x4F, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x59, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x63, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x6D, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0x80, 0x77, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0x80, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0x85, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0x8A, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0x8F, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0x94, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0x99, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0x9E, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xA3, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xA8, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xAD, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xB2, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xB7, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xBC, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xC1, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xC6, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xCB, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xD0, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xD5, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xDA, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xDF, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xE4, 0x44, + 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xE9, 0x44, 0x00, 0x00, 0xC0, 0x41, 0x00, 0xC0, 0xEE, 0x44}; +static constexpr float neighborRadius = 90.001; +static constexpr float innerRadius = 70.001; +static constexpr int jitterTol = 6; +static constexpr int riseDur = 8; +static constexpr bool decayFiltering = false; +static constexpr float decayRatio = 1.0; +static constexpr bool localize = true; +static constexpr bool saveShape = true; +static constexpr char filename[] = "/dev/null"; +static constexpr int cutoutStart = 10; +static constexpr int cutoutEnd = 58; +static constexpr unsigned int expectCnt[] = { + 0x000000, 0x00188A, 0x003197, 0x004B48, 0x006433, 0x007D4A, 0x00961C, 0x00AFA5, 0x00C86E, 0x00E137, + 0x00F9DB, 0x0112D9, 0x012B7B, 0x01449E, 0x015E49, 0x017795, 0x01904A, 0x01A94E, 0x01C243, 0x01DB3F, + 0x01F415, 0x020D12, 0x0225FB, 0x023E81, 0x0257CA, 0x02709A, 0x02898D, 0x02A284, 0x02BB6B, 0x02D4E5, + 0x02EDC1, 0x030681, 0x031EE8, 0x0337A2, 0x03505A, 0x0368E5, 0x0381A6, 0x039ABB, 0x03B3E8, 0x03CC91, + 0x03E514, 0x03FDA6, 0x041696, 0x042EDE, 0x044826, 0x046110, 0x047A4B, 0x0492CE, 0x04ABCB, 0x04C4BA, + 0x04DD89, 0x04F6DB, 0x050F51, 0x052820, 0x05410C, 0x055A3E, 0x057326, 0x058C65, 0x05A54F, 0x05BDCC, + 0x05D64E, 0x05EEC7, 0x0607F6, 0x0620A1, 0x063A36, 0x0653B0, 0x066C68, 0x06855E, 0x069DC8, 0x06B6FC, + 0x06CF80, 0x06E819, 0x0700E4, 0x0719D7, 0x0732CF, 0x074C27, 0x076519, 0x077DD4, 0x0795D2, 0x07AE46, + 0x07C751, 0x07E005, 0x07F905, 0x08115E, 0x082AAC, 0x0843B5, 0x085C46, 0x087587, 0x088E31, 0x08A6F4, + 0x08BFE8, 0x08D94E, 0x08F1F8, 0x090AAA, 0x0923C0, 0x093C5E, 0x095544, 0x095544, 0x095544, 0x095544, + 0x095544}; + +int main(int argc, const char **argv) +{ + fprintf(stderr, "argc = %d\n", argc); + for (int i = 0; i < argc; i++) + { + fprintf(stderr, "argv[%d] = \"%s\"\n", i, argv[i]); + } + fprintf(stderr, "\n"); + + path dataPath = path(argv[0]).parent_path() / path(dataFn); + ifstream dataFile(dataPath.c_str(), ios::binary); + + int chunkPercent = (argc > 1) ? atoi(argv[1]) : 5; + int numChunks = (dataLen / chunkSize + 99) / 100 * chunkPercent; + numChunks = (numChunks > dataLen / chunkSize) ? dataLen / chunkSize : numChunks; + + int repeat = (argc > 2) ? atoi(argv[2]) : 1; + + fprintf(stderr, "using %8d/%8d samples\n", numChunks * chunkSize, dataLen); + fprintf(stderr, "repeat %d runs\n", repeat); + fprintf(stderr, "\n"); + + fprintf(stderr, "address of buffer:\n"); + float **buffers = new float *[numChunks]; + for (int i = 0; i < numChunks; i++) + { + buffers[i] = new float[(chunkSize + chunkLeftMargin) * numChannels]; + fprintf(stderr, "%p ", buffers[i]); + if (i % 5 == 4 || i == numChunks - 1) + { + fprintf(stderr, "\n"); + } + + // long long is needed to mult numChannels + long long left = i * chunkSize - chunkLeftMargin; + long long right = i * chunkSize + chunkSize; + long long bufStart = 0; + if (left < 0) + { + bufStart = -left * numChannels; + left = 0; + } + + dataFile.seekg(dataOffset + left * numChannels * sizeof(float)) + .read((char *)(buffers[i] + bufStart), (right - left) * numChannels * sizeof(float)); + if (!dataFile.good()) + { + fprintf(stderr, "ERROR in file reading at chunk %4d/%4d! fail %d, bad %d, eof %d\n", + i, numChunks, dataFile.fail(), dataFile.bad(), dataFile.eof()); + } + } + fprintf(stderr, "\n"); + + for (int i = 0; i < repeat; i++) + { + fprintf(stderr, "repeat: %2d\n", i); + + Detection *pDet = new Detection(numChannels, chunkSize, chunkLeftMargin, + rescale, (float *)scale, (float *)offset, + medianReference, averageReference, + spikeDur, ampAvgDur, + threshold, minAvgAmp, maxAHPAmp, + (float *)channelPositions, neighborRadius, innerRadius, + jitterTol, riseDur, + decayFiltering, decayRatio, localize, + saveShape, filename, cutoutStart, cutoutEnd); + + for (int j = 0; j < numChunks; j++) + { + if ((j + 1) * chunkSize % 1000000 < chunkSize) // log each 1M samples + { + fprintf(stderr, "chunk: %4d/%4d, frame %8d~%8d\n", + j, numChunks, j * chunkSize - chunkLeftMargin, j * chunkSize + chunkSize); + } + + pDet->step(buffers[j], j * chunkSize, chunkSize); + } + + int resultCnt = pDet->finish(); + Spike result = pDet->getResult()[0]; + fprintf(stderr, "detected spikes: %6d\n", resultCnt); + fprintf(stderr, "expected number: %6d\n", expectCnt[chunkPercent]); + // fprintf(stderr, "expected around: %6d\n", 32 * numChunks * chunkSize / 1000); + fprintf(stderr, "first spike: %8d, %3d, %5d, %9.4f, %9.4f\n", + result.frame, result.channel, result.amplitude, result.position.x, result.position.y); + fprintf(stderr, "expected is: %8d, %3d, %5d, %9.4f, %9.4f\n", + 404, 119, 9484, -10.6043, -973.8785); + + delete pDet; + fprintf(stderr, "\n"); + } + + for (int i = 0; i < numChunks; i++) + { + delete[] buffers[i]; + } + delete[] buffers; + + dataFile.close(); + + fprintf(stderr, "Success\n"); + + return 0; +} From 1ae9c691a81839fbced31891a09598df8b90543a Mon Sep 17 00:00:00 2001 From: lkct Date: Wed, 20 Jul 2022 12:31:27 +0100 Subject: [PATCH 02/11] save aligned channel slices --- hs_detection/detect/Detection.cpp | 32 ++++++++++++++----------------- hs_detection/detect/Detection.h | 13 +++++++------ 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/hs_detection/detect/Detection.cpp b/hs_detection/detect/Detection.cpp index 2f52779..d1a1d5d 100644 --- a/hs_detection/detect/Detection.cpp +++ b/hs_detection/detect/Detection.cpp @@ -17,15 +17,15 @@ namespace HSDetection bool decayFiltering, FloatRatio decayRatio, bool localize, bool saveShape, string filename, IntFrame cutoutStart, IntFrame cutoutEnd) : traceRaw(chunkLeftMargin, numChannels, chunkSize), - numChannels(numChannels), chunkSize(chunkSize), chunkLeftMargin(chunkLeftMargin), - rescale(rescale), - scale(new (align_val_t(channelAlign * sizeof(IntVolt))) FloatRaw[alignChannel(numChannels)]), - offset(new (align_val_t(channelAlign * sizeof(IntVolt))) FloatRaw[alignChannel(numChannels)]), - trace(chunkSize + chunkLeftMargin, alignChannel(numChannels)), + numChannels(numChannels), alignedChannels(alignChannel(numChannels)), + chunkSize(chunkSize), chunkLeftMargin(chunkLeftMargin), rescale(rescale), + scale(new (align_val_t(channelAlign * sizeof(IntVolt))) FloatRaw[alignedChannels * channelAlign]), + offset(new (align_val_t(channelAlign * sizeof(IntVolt))) FloatRaw[alignedChannels * channelAlign]), + trace(chunkSize + chunkLeftMargin, alignedChannels * channelAlign), medianReference(medianReference), averageReference(averageReference), commonRef(chunkSize + chunkLeftMargin, 1), - runningBaseline(chunkSize + chunkLeftMargin, alignChannel(numChannels)), - runningDeviation(chunkSize + chunkLeftMargin, alignChannel(numChannels)), + runningBaseline(chunkSize + chunkLeftMargin, alignedChannels * channelAlign), + runningDeviation(chunkSize + chunkLeftMargin, alignedChannels * channelAlign), spikeTime(new IntFrame[numChannels]), spikeAmp(new IntVolt[numChannels]), spikeArea(new IntCalc[numChannels]), hasAHP(new bool[numChannels]), spikeDur(spikeDur), ampAvgDur(ampAvgDur), threshold(threshold * thrQuant), @@ -35,17 +35,16 @@ namespace HSDetection decayFilter(decayFiltering), decayRatio(decayRatio), localize(localize), saveShape(saveShape), filename(filename), cutoutStart(cutoutStart), cutoutEnd(cutoutEnd) { - fill_n(this->scale, alignChannel(numChannels), (FloatRaw)1); - fill_n(this->offset, alignChannel(numChannels), (FloatRaw)0); - + fill_n(this->scale, alignedChannels * channelAlign, (FloatRaw)1); + fill_n(this->offset, alignedChannels * channelAlign, (FloatRaw)0); if (rescale) { copy_n(scale, numChannels, this->scale); copy_n(offset, numChannels, this->offset); } - fill_n(runningBaseline[-1], numChannels, initBase); - fill_n(runningDeviation[-1], numChannels, initDev); + fill_n(runningBaseline[-1], alignedChannels * channelAlign, initBase); + fill_n(runningDeviation[-1], alignedChannels * channelAlign, initDev); fill_n(spikeTime, numChannels, (IntFrame)-1); @@ -109,9 +108,8 @@ namespace HSDetection { const FloatRaw *input = traceRaw[t]; IntVolt *trace = this->trace[t]; - IntChannel alignedChannels = alignChannel(numChannels); - for (IntChannel i = 0; i < alignedChannels; i++) + for (IntChannel i = 0; i < alignedChannels * channelAlign; i++) { trace[i] = input[i] * scale[i] + offset[i]; } @@ -124,9 +122,8 @@ namespace HSDetection { const FloatRaw *input = traceRaw[t]; IntVolt *trace = this->trace[t]; - IntChannel alignedChannels = alignChannel(numChannels); - for (IntChannel i = 0; i < alignedChannels; i++) + for (IntChannel i = 0; i < alignedChannels * channelAlign; i++) { trace[i] = input[i]; } @@ -171,9 +168,8 @@ namespace HSDetection const IntVolt *devPrev = runningDeviation[t - 1]; IntVolt *baselines = runningBaseline[t]; IntVolt *deviations = runningDeviation[t]; - IntChannel alignedChannels = alignChannel(numChannels); - for (IntChannel i = 0; i < alignedChannels; i++) + for (IntChannel i = 0; i < alignedChannels * channelAlign; i++) { IntVolt volt = trace[i] - ref - basePrev[i]; diff --git a/hs_detection/detect/Detection.h b/hs_detection/detect/Detection.h index 7810652..4bdd91e 100644 --- a/hs_detection/detect/Detection.h +++ b/hs_detection/detect/Detection.h @@ -24,15 +24,16 @@ namespace HSDetection static constexpr IntCalc thrQuant = 256; // 8bit precision - static constexpr size_t channelAlign = 32; // align IntVolt=16bit to 64B (assume FloatRaw is wider) + static constexpr IntChannel channelAlign = 32; // align IntVolt=16bit to 64B (assume FloatRaw is wider) - static constexpr IntChannel alignChannel(IntChannel x) { return (x + (channelAlign - 1)) & (-channelAlign); } + static constexpr IntChannel alignChannel(IntChannel x) { return (x + (channelAlign - 1)) / channelAlign; } // input data - TraceWrapper traceRaw; // input trace - IntChannel numChannels; // number of probe channels - IntFrame chunkSize; // size of each chunk, only the last chunk can be of a different (smaller) size - IntFrame chunkLeftMargin; // margin on the left of each chunk + TraceWrapper traceRaw; // input trace + IntChannel numChannels; // number of probe channels + IntChannel alignedChannels; // number of slices of aligned channels + IntFrame chunkSize; // size of each chunk, only the last chunk can be of a different (smaller) size + IntFrame chunkLeftMargin; // margin on the left of each chunk // rescaling bool rescale; // whether to scale the input From a517f12d5e8caca4bda555fb196339143652f68d Mon Sep 17 00:00:00 2001 From: lkct Date: Thu, 21 Jul 2022 17:45:10 +0100 Subject: [PATCH 03/11] adjust delay --- hs_detection/detect/Detection.cpp | 2 +- hs_detection/detect/SpikeQueue.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hs_detection/detect/Detection.cpp b/hs_detection/detect/Detection.cpp index d1a1d5d..5ca116d 100644 --- a/hs_detection/detect/Detection.cpp +++ b/hs_detection/detect/Detection.cpp @@ -191,7 +191,7 @@ namespace HSDetection { for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) { - while (pQueue->checkDelay(t)) + while (pQueue->checkDelay(t - spikeDur)) { pQueue->process(); } diff --git a/hs_detection/detect/SpikeQueue.cpp b/hs_detection/detect/SpikeQueue.cpp index 5c0da02..2481e81 100644 --- a/hs_detection/detect/SpikeQueue.cpp +++ b/hs_detection/detect/SpikeQueue.cpp @@ -23,7 +23,7 @@ namespace HSDetection { SpikeQueue::SpikeQueue(Detection *pDet) : queue(), queProcs(), spkProcs(), pRresult(&pDet->result), - procDelay(max(pDet->cutoutEnd, pDet->riseDur + pDet->spikeDur) + pDet->jitterTol + 1) + procDelay(max(pDet->cutoutEnd - pDet->spikeDur, pDet->riseDur) + pDet->jitterTol + 1) { SpikeProcessor *pSpkProc; QueueProcessor *pQueProc; From d80abecfc8a5cab93c27b457760f733f24963b4b Mon Sep 17 00:00:00 2001 From: lkct Date: Thu, 21 Jul 2022 18:14:38 +0100 Subject: [PATCH 04/11] save all det then proc --- hs_detection/detect/Detection.cpp | 9 +++------ hs_detection/detect/SpikeQueue.cpp | 28 +++++++++++++++++++++++++--- hs_detection/detect/SpikeQueue.h | 13 +++++++++++-- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/hs_detection/detect/Detection.cpp b/hs_detection/detect/Detection.cpp index 5ca116d..259958e 100644 --- a/hs_detection/detect/Detection.cpp +++ b/hs_detection/detect/Detection.cpp @@ -89,6 +89,8 @@ namespace HSDetection runningEstimation(chunkStart, chunkLen); detectSpikes(chunkStart, chunkLen); + + pQueue->process(); } IntResult Detection::finish() @@ -191,11 +193,6 @@ namespace HSDetection { for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) { - while (pQueue->checkDelay(t - spikeDur)) - { - pQueue->process(); - } - const IntVolt *trace = this->trace[t]; IntVolt ref = commonRef(t, 0); const IntVolt *baselines = runningBaseline[t]; @@ -260,7 +257,7 @@ namespace HSDetection if (spikeArea[i] > minAvg * ampAvgDur && // reach min area (hasAHP[i] || voltThr < maxAHP)) // AHP exist { - pQueue->push_back(Spike(t - spikeDur, i, spikeAmp[i])); + pQueue->addSpike(Spike(t - spikeDur, i, spikeAmp[i])); } spikeTime[i] = -1; // reset counter even if not spike diff --git a/hs_detection/detect/SpikeQueue.cpp b/hs_detection/detect/SpikeQueue.cpp index 2481e81..c15d573 100644 --- a/hs_detection/detect/SpikeQueue.cpp +++ b/hs_detection/detect/SpikeQueue.cpp @@ -22,7 +22,8 @@ using namespace std; namespace HSDetection { SpikeQueue::SpikeQueue(Detection *pDet) - : queue(), queProcs(), spkProcs(), pRresult(&pDet->result), + : spikes((Spike *)new char[pDet->chunkSize * pDet->numChannels * sizeof(Spike)]), spikeCnt(0), + queue(), queProcs(), spkProcs(), pRresult(&pDet->result), procDelay(max(pDet->cutoutEnd - pDet->spikeDur, pDet->riseDur) + pDet->jitterTol + 1) { SpikeProcessor *pSpkProc; @@ -64,9 +65,11 @@ namespace HSDetection for_each(spkProcs.begin(), spkProcs.end(), [](SpikeProcessor *pSpkProc) { delete pSpkProc; }); + + delete[](char *) spikes; } - void SpikeQueue::process() + void SpikeQueue::procFront() { for_each(queProcs.begin(), queProcs.end(), [this](QueueProcessor *pQueProc) @@ -76,11 +79,30 @@ namespace HSDetection queue.erase(queue.begin()); } + void SpikeQueue::process() + { + sort(spikes, spikes + spikeCnt, + [](const Spike &lhs, const Spike &rhs) + { return lhs.frame < rhs.frame || (lhs.frame == rhs.frame && lhs.channel < rhs.channel); }); + + for (IntResult i = 0; i < spikeCnt; i++) + { + while (!queue.empty() && queue.front().frame < spikes[i].frame - procDelay) + { + procFront(); + } + + queue.push_back(move(spikes[i])); + } + + spikeCnt = 0; // reset for next chunk + } + void SpikeQueue::finalize() { while (!queue.empty()) { - process(); + procFront(); } } diff --git a/hs_detection/detect/SpikeQueue.h b/hs_detection/detect/SpikeQueue.h index f28e365..ead2ac9 100644 --- a/hs_detection/detect/SpikeQueue.h +++ b/hs_detection/detect/SpikeQueue.h @@ -17,6 +17,9 @@ namespace HSDetection class SpikeQueue { private: + Spike *spikes; // buffer for detected spikes + IntResult spikeCnt; // count of detected spikes + std::list queue; // list has constant-time erase and also bi-directional iter std::vector queProcs; // content created and released here @@ -26,6 +29,9 @@ namespace HSDetection IntFrame procDelay; // delayed frames from push to process + void procFront(); + // cannot inline procFront because no definition of Processor here + public: SpikeQueue(Detection *pDet); // passing the whole param set altogether ~SpikeQueue(); @@ -35,10 +41,13 @@ namespace HSDetection // copy assignment deleted to protect container content SpikeQueue &operator=(const SpikeQueue &) = delete; - bool checkDelay(IntFrame curFrame) { return !queue.empty() && queue.front().frame < curFrame - procDelay; } + void addSpike(Spike &&spike) + { + IntResult spkIdx = spikeCnt++; + spikes[spkIdx] = std::move(spike); + } void process(); void finalize(); - // cannot inline process because no definition of Processor here // wrappers of container interface From 1dd88736b6218701b9062e72f718b02be6a98d6e Mon Sep 17 00:00:00 2001 From: lkct Date: Sat, 23 Jul 2022 19:27:25 +0100 Subject: [PATCH 05/11] merge estimation and detection loop improve data locality, higher L1 usage --- hs_detection/detect/Detection.cpp | 21 ++++----------------- hs_detection/detect/Detection.h | 3 +-- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/hs_detection/detect/Detection.cpp b/hs_detection/detect/Detection.cpp index 259958e..665a183 100644 --- a/hs_detection/detect/Detection.cpp +++ b/hs_detection/detect/Detection.cpp @@ -86,9 +86,7 @@ namespace HSDetection commonAverage(chunkStart, chunkLen); } - runningEstimation(chunkStart, chunkLen); - - detectSpikes(chunkStart, chunkLen); + estimateAndDetect(chunkStart, chunkLen); pQueue->process(); } @@ -160,7 +158,7 @@ namespace HSDetection } } - void Detection::runningEstimation(IntFrame chunkStart, IntFrame chunkLen) + void Detection::estimateAndDetect(IntFrame chunkStart, IntFrame chunkLen) { for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) { @@ -186,17 +184,6 @@ namespace HSDetection IntVolt dev = devPrev[i] + dltDev; deviations[i] = (dev < minDev) ? minDev : dev; // clamp deviations at minDev } - } - } - - void Detection::detectSpikes(IntFrame chunkStart, IntFrame chunkLen) - { - for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) - { - const IntVolt *trace = this->trace[t]; - IntVolt ref = commonRef(t, 0); - const IntVolt *baselines = runningBaseline[t]; - const IntVolt *deviations = runningDeviation[t]; for (IntChannel i = 0; i < numChannels; i++) { @@ -262,10 +249,10 @@ namespace HSDetection spikeTime[i] = -1; // reset counter even if not spike - } // for i + } // second for i } // for t - } // Detection::detectSpikes + } // Detection::estimateAndDetect } // namespace HSDetection diff --git a/hs_detection/detect/Detection.h b/hs_detection/detect/Detection.h index 4bdd91e..5787c7c 100644 --- a/hs_detection/detect/Detection.h +++ b/hs_detection/detect/Detection.h @@ -90,8 +90,7 @@ namespace HSDetection void traceCast(IntFrame chunkStart, IntFrame chunkLen); void commonMedian(IntFrame chunkStart, IntFrame chunkLen); void commonAverage(IntFrame chunkStart, IntFrame chunkLen); - void runningEstimation(IntFrame chunkStart, IntFrame chunkLen); - void detectSpikes(IntFrame chunkStart, IntFrame chunkLen); + void estimateAndDetect(IntFrame chunkStart, IntFrame chunkLen); public: Detection(IntChannel numChannels, IntFrame chunkSize, IntFrame chunkLeftMargin, From ebdf951fe02f49fa2bc395be4a0d0c3c2145c107 Mon Sep 17 00:00:00 2001 From: lkct Date: Sat, 23 Jul 2022 20:04:34 +0100 Subject: [PATCH 06/11] adjust workflow modularization --- hs_detection/detect/Detection.cpp | 97 ++++++------ hs_detection/detect/Detection.h | 242 +++++++++++++++--------------- 2 files changed, 169 insertions(+), 170 deletions(-) diff --git a/hs_detection/detect/Detection.cpp b/hs_detection/detect/Detection.cpp index 665a183..e49f6c1 100644 --- a/hs_detection/detect/Detection.cpp +++ b/hs_detection/detect/Detection.cpp @@ -68,23 +68,7 @@ namespace HSDetection { traceRaw.updateChunk(traceBuffer); - if (rescale) - { - traceScaleCast(chunkStart, chunkLen); - } - else - { - traceCast(chunkStart, chunkLen); - } - - if (medianReference) - { - commonMedian(chunkStart, chunkLen); - } - else if (averageReference) - { - commonAverage(chunkStart, chunkLen); - } + castAndCommonref(chunkStart, chunkLen); estimateAndDetect(chunkStart, chunkLen); @@ -102,62 +86,75 @@ namespace HSDetection return result.data(); } - void Detection::traceScaleCast(IntFrame chunkStart, IntFrame chunkLen) + void Detection::castAndCommonref(IntFrame chunkStart, IntFrame chunkLen) { - for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + if (rescale) { - const FloatRaw *input = traceRaw[t]; - IntVolt *trace = this->trace[t]; - - for (IntChannel i = 0; i < alignedChannels * channelAlign; i++) + for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) { - trace[i] = input[i] * scale[i] + offset[i]; + scaleCast(trace[t], traceRaw[t]); + } + } + else + { + for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + { + noscaleCast(trace[t], traceRaw[t]); } } - } - void Detection::traceCast(IntFrame chunkStart, IntFrame chunkLen) - { - for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + if (medianReference) { - const FloatRaw *input = traceRaw[t]; - IntVolt *trace = this->trace[t]; + IntVolt *buffer = new IntVolt[numChannels]; // nth_element modifies container + IntChannel mid = numChannels / 2; - for (IntChannel i = 0; i < alignedChannels * channelAlign; i++) + for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) { - trace[i] = input[i]; + commonMedian(commonRef[t], trace[t], buffer, mid); + } + + delete[] buffer; + } + else if (averageReference) + { + for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + { + commonAverage(commonRef[t], trace[t]); } } } - void Detection::commonMedian(IntFrame chunkStart, IntFrame chunkLen) + void Detection::scaleCast(IntVolt *trace, const FloatRaw *input) { - IntVolt *frame = new IntVolt[numChannels]; // nth_element modifies container - IntChannel mid = numChannels / 2; - - for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + for (IntChannel i = 0; i < alignedChannels * channelAlign; i++) { - copy_n(trace[t], numChannels, frame); - - nth_element(frame, frame + mid, frame + numChannels); - - commonRef(t, 0) = frame[mid]; + trace[i] = input[i] * scale[i] + offset[i]; } - - delete[] frame; } - void Detection::commonAverage(IntFrame chunkStart, IntFrame chunkLen) + void Detection::noscaleCast(IntVolt *trace, const FloatRaw *input) { - for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + for (IntChannel i = 0; i < alignedChannels * channelAlign; i++) { - commonRef(t, 0) = accumulate(trace[t], trace[t] + numChannels, (IntCalc)0, - [](IntCalc sum, IntVolt data) - { return sum + data; }) / - numChannels; + trace[i] = input[i]; } } + void Detection::commonMedian(IntVolt *ref, const IntVolt *trace, IntVolt *buffer, IntChannel mid) + { + copy_n(trace, numChannels, buffer); + nth_element(buffer, buffer + mid, buffer + numChannels); + *ref = buffer[mid]; + } + + void Detection::commonAverage(IntVolt *ref, const IntVolt *trace) + { + IntCalc sum = accumulate(trace, trace + numChannels, (IntCalc)0, + [](IntCalc sum, IntVolt data) + { return sum + data; }); + *ref = sum / numChannels; + } + void Detection::estimateAndDetect(IntFrame chunkStart, IntFrame chunkLen) { for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) diff --git a/hs_detection/detect/Detection.h b/hs_detection/detect/Detection.h index 5787c7c..827dc16 100644 --- a/hs_detection/detect/Detection.h +++ b/hs_detection/detect/Detection.h @@ -1,120 +1,122 @@ -#ifndef DETECTION_H -#define DETECTION_H - -#include - -#include "ProbeLayout.h" -#include "TraceWrapper.h" -#include "RollingArray.h" -#include "SpikeQueue.h" - -namespace HSDetection -{ - class Detection - { - private: - friend SpikeQueue; // allow access to the whole param set - - // constants - static constexpr IntVolt initBase = 0; // initial value of baseline - static constexpr IntVolt initDev = 400; // initial value of deviation - static constexpr IntVolt tauBase = 4; // time constant for baseline update - static constexpr IntVolt devChange = 1; // changing for deviation update - static constexpr IntVolt minDev = 200; // minimum level of deviation - - static constexpr IntCalc thrQuant = 256; // 8bit precision - - static constexpr IntChannel channelAlign = 32; // align IntVolt=16bit to 64B (assume FloatRaw is wider) - - static constexpr IntChannel alignChannel(IntChannel x) { return (x + (channelAlign - 1)) / channelAlign; } - - // input data - TraceWrapper traceRaw; // input trace - IntChannel numChannels; // number of probe channels - IntChannel alignedChannels; // number of slices of aligned channels - IntFrame chunkSize; // size of each chunk, only the last chunk can be of a different (smaller) size - IntFrame chunkLeftMargin; // margin on the left of each chunk - - // rescaling - bool rescale; // whether to scale the input - FloatRaw *scale; // scale for rescaling - FloatRaw *offset; // offset for rescaling - RollingArray trace; // rescaled and quantized trace to be used - - // common reference - bool medianReference; // whether to use CMR (overrides CAR) - bool averageReference; // whether to use CAR - RollingArray commonRef; // common median/average reference - - // running estimation - RollingArray runningBaseline; // running estimation of baseline (33 percentile) - RollingArray runningDeviation; // running estimation of deviation from baseline - - // detection - IntFrame *spikeTime; // counter for time since spike peak - IntVolt *spikeAmp; // spike peak amplitude - IntCalc *spikeArea; // area under spike used for average amplitude, actually integral*fps - bool *hasAHP; // flag for AHP existence - - IntFrame spikeDur; // duration of a spike since peak - IntFrame ampAvgDur; // duration to average amplitude - IntCalc threshold; // threshold to detect spikes, used as multiplier of deviation - IntCalc minAvgAmp; // threshold for average amplitude of peak, used as multiplier of deviation - IntCalc maxAHPAmp; // threshold for voltage level of AHP, used as multiplier of deviation - - // queue processing - SpikeQueue *pQueue; // spike queue, must be a pointer to be new-ed later - - ProbeLayout probeLayout; // geometry for probe layout - - std::vector result; // detection result, use vector to expand as needed - - IntFrame jitterTol; // tolerance of jitter in electrical signal - IntFrame riseDur; // duration that a spike rises to peak - - // decay filtering - bool decayFilter; // whether to use decay filtering instead of normal one - FloatRatio decayRatio; // ratio of amplitude to be considered as decayed - - // localization - bool localize; // whether to turn on localization - - // save shape - bool saveShape; // whether to save spike shapes to file - std::string filename; // filename for saving - IntFrame cutoutStart; // the start of spike shape cutout - IntFrame cutoutEnd; // the end of cutout - - private: - void traceScaleCast(IntFrame chunkStart, IntFrame chunkLen); - void traceCast(IntFrame chunkStart, IntFrame chunkLen); - void commonMedian(IntFrame chunkStart, IntFrame chunkLen); - void commonAverage(IntFrame chunkStart, IntFrame chunkLen); - void estimateAndDetect(IntFrame chunkStart, IntFrame chunkLen); - - public: - Detection(IntChannel numChannels, IntFrame chunkSize, IntFrame chunkLeftMargin, - bool rescale, const FloatRaw *scale, const FloatRaw *offset, - bool medianReference, bool averageReference, - IntFrame spikeDur, IntFrame ampAvgDur, - FloatRatio threshold, FloatRatio minAvgAmp, FloatRatio maxAHPAmp, - const FloatGeom *channelPositions, FloatGeom neighborRadius, FloatGeom innerRadius, - IntFrame jitterTol, IntFrame riseDur, - bool decayFiltering, FloatRatio decayRatio, bool localize, - bool saveShape, std::string filename, IntFrame cutoutStart, IntFrame cutoutEnd); - ~Detection(); - - // copy constructor deleted to protect internals - Detection(const Detection &) = delete; - // copy assignment deleted to protect internals - Detection &operator=(const Detection &) = delete; - - void step(FloatRaw *traceBuffer, IntFrame chunkStart, IntFrame chunkLen); - IntResult finish(); - const Spike *getResult() const; - - }; // class Detection - -} // namespace HSDetection - -#endif +#ifndef DETECTION_H +#define DETECTION_H + +#include + +#include "ProbeLayout.h" +#include "TraceWrapper.h" +#include "RollingArray.h" +#include "SpikeQueue.h" + +namespace HSDetection +{ + class Detection + { + private: + friend SpikeQueue; // allow access to the whole param set + + // constants + static constexpr IntVolt initBase = 0; // initial value of baseline + static constexpr IntVolt initDev = 400; // initial value of deviation + static constexpr IntVolt tauBase = 4; // time constant for baseline update + static constexpr IntVolt devChange = 1; // changing for deviation update + static constexpr IntVolt minDev = 200; // minimum level of deviation + + static constexpr IntCalc thrQuant = 256; // 8bit precision + + static constexpr IntChannel channelAlign = 32; // align IntVolt=16bit to 64B (assume FloatRaw is wider) + + static constexpr IntChannel alignChannel(IntChannel x) { return (x + (channelAlign - 1)) / channelAlign; } + + // input data + TraceWrapper traceRaw; // input trace + IntChannel numChannels; // number of probe channels + IntChannel alignedChannels; // number of slices of aligned channels + IntFrame chunkSize; // size of each chunk, only the last chunk can be of a different (smaller) size + IntFrame chunkLeftMargin; // margin on the left of each chunk + + // rescaling + bool rescale; // whether to scale the input + FloatRaw *scale; // scale for rescaling + FloatRaw *offset; // offset for rescaling + RollingArray trace; // rescaled and quantized trace to be used + + // common reference + bool medianReference; // whether to use CMR (overrides CAR) + bool averageReference; // whether to use CAR + RollingArray commonRef; // common median/average reference + + // running estimation + RollingArray runningBaseline; // running estimation of baseline (33 percentile) + RollingArray runningDeviation; // running estimation of deviation from baseline + + // detection + IntFrame *spikeTime; // counter for time since spike peak + IntVolt *spikeAmp; // spike peak amplitude + IntCalc *spikeArea; // area under spike used for average amplitude, actually integral*fps + bool *hasAHP; // flag for AHP existence + + IntFrame spikeDur; // duration of a spike since peak + IntFrame ampAvgDur; // duration to average amplitude + IntCalc threshold; // threshold to detect spikes, used as multiplier of deviation + IntCalc minAvgAmp; // threshold for average amplitude of peak, used as multiplier of deviation + IntCalc maxAHPAmp; // threshold for voltage level of AHP, used as multiplier of deviation + + // queue processing + SpikeQueue *pQueue; // spike queue, must be a pointer to be new-ed later + + ProbeLayout probeLayout; // geometry for probe layout + + std::vector result; // detection result, use vector to expand as needed + + IntFrame jitterTol; // tolerance of jitter in electrical signal + IntFrame riseDur; // duration that a spike rises to peak + + // decay filtering + bool decayFilter; // whether to use decay filtering instead of normal one + FloatRatio decayRatio; // ratio of amplitude to be considered as decayed + + // localization + bool localize; // whether to turn on localization + + // save shape + bool saveShape; // whether to save spike shapes to file + std::string filename; // filename for saving + IntFrame cutoutStart; // the start of spike shape cutout + IntFrame cutoutEnd; // the end of cutout + + private: + inline void scaleCast(IntVolt *trace, const FloatRaw *input); + inline void noscaleCast(IntVolt *trace, const FloatRaw *input); + inline void commonMedian(IntVolt *ref, const IntVolt *trace, + IntVolt *buffer, IntChannel mid); + inline void commonAverage(IntVolt *ref, const IntVolt *trace); + void castAndCommonref(IntFrame chunkStart, IntFrame chunkLen); + void estimateAndDetect(IntFrame chunkStart, IntFrame chunkLen); + + public: + Detection(IntChannel numChannels, IntFrame chunkSize, IntFrame chunkLeftMargin, + bool rescale, const FloatRaw *scale, const FloatRaw *offset, + bool medianReference, bool averageReference, + IntFrame spikeDur, IntFrame ampAvgDur, + FloatRatio threshold, FloatRatio minAvgAmp, FloatRatio maxAHPAmp, + const FloatGeom *channelPositions, FloatGeom neighborRadius, FloatGeom innerRadius, + IntFrame jitterTol, IntFrame riseDur, + bool decayFiltering, FloatRatio decayRatio, bool localize, + bool saveShape, std::string filename, IntFrame cutoutStart, IntFrame cutoutEnd); + ~Detection(); + + // copy constructor deleted to protect internals + Detection(const Detection &) = delete; + // copy assignment deleted to protect internals + Detection &operator=(const Detection &) = delete; + + void step(FloatRaw *traceBuffer, IntFrame chunkStart, IntFrame chunkLen); + IntResult finish(); + const Spike *getResult() const; + + }; // class Detection + +} // namespace HSDetection + +#endif From d80b0334ad282a40ca10da496a51997d88124463 Mon Sep 17 00:00:00 2001 From: lkct Date: Sat, 23 Jul 2022 20:33:05 +0100 Subject: [PATCH 07/11] shortcut and merge loop w/o condition also improve L1 cache --- hs_detection/detect/Detection.cpp | 16 ++++++++++++++++ hs_detection/detect/Detection.h | 1 + 2 files changed, 17 insertions(+) diff --git a/hs_detection/detect/Detection.cpp b/hs_detection/detect/Detection.cpp index e49f6c1..20d0d62 100644 --- a/hs_detection/detect/Detection.cpp +++ b/hs_detection/detect/Detection.cpp @@ -88,6 +88,12 @@ namespace HSDetection void Detection::castAndCommonref(IntFrame chunkStart, IntFrame chunkLen) { + if (rescale && !medianReference && averageReference) + { + scaleAndAverage(chunkStart, chunkLen); + return; + } + if (rescale) { for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) @@ -124,6 +130,16 @@ namespace HSDetection } } + void Detection::scaleAndAverage(IntFrame chunkStart, IntFrame chunkLen) + { + for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + { + scaleCast(trace[t], traceRaw[t]); + + commonAverage(commonRef[t], trace[t]); + } + } + void Detection::scaleCast(IntVolt *trace, const FloatRaw *input) { for (IntChannel i = 0; i < alignedChannels * channelAlign; i++) diff --git a/hs_detection/detect/Detection.h b/hs_detection/detect/Detection.h index 827dc16..0d45781 100644 --- a/hs_detection/detect/Detection.h +++ b/hs_detection/detect/Detection.h @@ -91,6 +91,7 @@ namespace HSDetection inline void commonMedian(IntVolt *ref, const IntVolt *trace, IntVolt *buffer, IntChannel mid); inline void commonAverage(IntVolt *ref, const IntVolt *trace); + void scaleAndAverage(IntFrame chunkStart, IntFrame chunkLen); void castAndCommonref(IntFrame chunkStart, IntFrame chunkLen); void estimateAndDetect(IntFrame chunkStart, IntFrame chunkLen); From 0fda5f192757ed591cd80e0cfb5e59d424bc17c6 Mon Sep 17 00:00:00 2001 From: lkct Date: Sat, 23 Jul 2022 20:57:42 +0100 Subject: [PATCH 08/11] adjust align from 4k to 512 --- hs_detection/detect/RollingArray.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hs_detection/detect/RollingArray.h b/hs_detection/detect/RollingArray.h index c492359..5b107e7 100644 --- a/hs_detection/detect/RollingArray.h +++ b/hs_detection/detect/RollingArray.h @@ -13,7 +13,7 @@ namespace HSDetection IntFrame frameMask; // rolling length will be 2^n and mask is 2^n-1 for bit ops IntChannel numChannels; - static constexpr std::align_val_t memAlign = std::align_val_t(4096); // align to 4K anyway + static constexpr std::align_val_t memAlign = std::align_val_t(512); // align to 4K/8 to avoid 4K alias static constexpr IntFrame getMask(IntFrame x) // get minimum 0...01...1 >= x { From 1d967668fb92a1ce76d9dced3cc531ed269df080 Mon Sep 17 00:00:00 2001 From: lkct Date: Sun, 24 Jul 2022 01:44:45 +0100 Subject: [PATCH 09/11] use omp --- hs_detection/detect/Detection.cpp | 41 +++++++++++++++++++++++-------- hs_detection/detect/SpikeQueue.h | 4 ++- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/hs_detection/detect/Detection.cpp b/hs_detection/detect/Detection.cpp index 20d0d62..0384844 100644 --- a/hs_detection/detect/Detection.cpp +++ b/hs_detection/detect/Detection.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include "Detection.h" using namespace std; @@ -68,9 +70,12 @@ namespace HSDetection { traceRaw.updateChunk(traceBuffer); - castAndCommonref(chunkStart, chunkLen); - - estimateAndDetect(chunkStart, chunkLen); +#pragma omp parallel + { + castAndCommonref(chunkStart, chunkLen); +#pragma omp barrier + estimateAndDetect(chunkStart, chunkLen); + } pQueue->process(); } @@ -88,22 +93,29 @@ namespace HSDetection void Detection::castAndCommonref(IntFrame chunkStart, IntFrame chunkLen) { + int numThreads = omp_get_num_threads(); + int threadNum = omp_get_thread_num(); + // each thread have ceil(chunkLen / numThreads), last has fewer + IntFrame thChunkLen = (chunkLen + numThreads - 1) / numThreads; + IntFrame thChunkStart = chunkStart + threadNum * thChunkLen; + thChunkLen = min(thChunkLen, chunkStart + chunkLen - thChunkStart); + if (rescale && !medianReference && averageReference) { - scaleAndAverage(chunkStart, chunkLen); + scaleAndAverage(thChunkStart, thChunkLen); return; } if (rescale) { - for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + for (IntFrame t = thChunkStart; t < thChunkStart + thChunkLen; t++) { scaleCast(trace[t], traceRaw[t]); } } else { - for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + for (IntFrame t = thChunkStart; t < thChunkStart + thChunkLen; t++) { noscaleCast(trace[t], traceRaw[t]); } @@ -114,7 +126,7 @@ namespace HSDetection IntVolt *buffer = new IntVolt[numChannels]; // nth_element modifies container IntChannel mid = numChannels / 2; - for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + for (IntFrame t = thChunkStart; t < thChunkStart + thChunkLen; t++) { commonMedian(commonRef[t], trace[t], buffer, mid); } @@ -123,7 +135,7 @@ namespace HSDetection } else if (averageReference) { - for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) + for (IntFrame t = thChunkStart; t < thChunkStart + thChunkLen; t++) { commonAverage(commonRef[t], trace[t]); } @@ -173,6 +185,15 @@ namespace HSDetection void Detection::estimateAndDetect(IntFrame chunkStart, IntFrame chunkLen) { + int numThreads = omp_get_num_threads(); + int threadNum = omp_get_thread_num(); + // each thread have ceil(alignedChannels / numThreads), last has fewer + IntChannel thChannels = (alignedChannels + numThreads - 1) / numThreads; + IntChannel thAlignedStart = threadNum * thChannels; + IntChannel thAlignedEnd = (threadNum + 1) * thChannels; + thAlignedEnd = min(thAlignedEnd, alignedChannels); + IntChannel thActualEnd = min(thAlignedEnd * channelAlign, numChannels); + for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) { const IntVolt *trace = this->trace[t]; @@ -182,7 +203,7 @@ namespace HSDetection IntVolt *baselines = runningBaseline[t]; IntVolt *deviations = runningDeviation[t]; - for (IntChannel i = 0; i < alignedChannels * channelAlign; i++) + for (IntChannel i = thAlignedStart * channelAlign; i < thAlignedEnd * channelAlign; i++) { IntVolt volt = trace[i] - ref - basePrev[i]; @@ -198,7 +219,7 @@ namespace HSDetection deviations[i] = (dev < minDev) ? minDev : dev; // clamp deviations at minDev } - for (IntChannel i = 0; i < numChannels; i++) + for (IntChannel i = thAlignedStart * channelAlign; i < thActualEnd; i++) { IntVolt volt = trace[i] - ref - baselines[i]; // calc against updated baselines IntVolt dev = deviations[i]; diff --git a/hs_detection/detect/SpikeQueue.h b/hs_detection/detect/SpikeQueue.h index ead2ac9..d0bd0be 100644 --- a/hs_detection/detect/SpikeQueue.h +++ b/hs_detection/detect/SpikeQueue.h @@ -43,7 +43,9 @@ namespace HSDetection void addSpike(Spike &&spike) { - IntResult spkIdx = spikeCnt++; + IntResult spkIdx; +#pragma omp atomic capture + spkIdx = spikeCnt++; spikes[spkIdx] = std::move(spike); } void process(); From db9532af412e041ef4c657fff819bbf52d48a3f6 Mon Sep 17 00:00:00 2001 From: lkct Date: Sun, 24 Jul 2022 17:08:09 +0100 Subject: [PATCH 10/11] split into inline funcs --- hs_detection/detect/Detection.cpp | 162 ++++++++++++++++-------------- hs_detection/detect/Detection.h | 7 ++ 2 files changed, 94 insertions(+), 75 deletions(-) diff --git a/hs_detection/detect/Detection.cpp b/hs_detection/detect/Detection.cpp index 0384844..8f0eb95 100644 --- a/hs_detection/detect/Detection.cpp +++ b/hs_detection/detect/Detection.cpp @@ -196,97 +196,109 @@ namespace HSDetection for (IntFrame t = chunkStart; t < chunkStart + chunkLen; t++) { - const IntVolt *trace = this->trace[t]; - IntVolt ref = commonRef(t, 0); - const IntVolt *basePrev = runningBaseline[t - 1]; - const IntVolt *devPrev = runningDeviation[t - 1]; - IntVolt *baselines = runningBaseline[t]; - IntVolt *deviations = runningDeviation[t]; - - for (IntChannel i = thAlignedStart * channelAlign; i < thAlignedEnd * channelAlign; i++) - { - IntVolt volt = trace[i] - ref - basePrev[i]; - - IntVolt dltBase = 0; - dltBase = (devPrev[i] < volt) ? devPrev[i] / tauBase : dltBase; - dltBase = (volt < -devPrev[i]) ? -devPrev[i] / (tauBase * 2) : dltBase; - baselines[i] = basePrev[i] + dltBase; - - IntVolt dltDev = 0; - dltDev = (devPrev[i] < volt && volt < 5 * devPrev[i]) ? devChange : dltDev; - dltDev = ((0 < volt && volt <= devPrev[i]) || 6 * devPrev[i] < volt) ? -devChange : dltDev; - IntVolt dev = devPrev[i] + dltDev; - deviations[i] = (dev < minDev) ? minDev : dev; // clamp deviations at minDev - } + estimation(runningBaseline[t], runningDeviation[t], + trace[t], commonRef[t], + runningBaseline[t - 1], runningDeviation[t - 1], + thAlignedStart, thAlignedEnd); + + detection(trace[t], commonRef[t], + runningBaseline[t], runningDeviation[t], + thAlignedStart * channelAlign, thActualEnd, t); + } + } - for (IntChannel i = thAlignedStart * channelAlign; i < thActualEnd; i++) - { - IntVolt volt = trace[i] - ref - baselines[i]; // calc against updated baselines - IntVolt dev = deviations[i]; + void Detection::estimation(IntVolt *baselines, IntVolt *deviations, + const IntVolt *trace, const IntVolt *ref, + const IntVolt *basePrev, const IntVolt *devPrev, + IntChannel alignedStart, IntChannel alignedEnd) + { + for (IntChannel i = alignedStart * channelAlign; i < alignedEnd * channelAlign; i++) + { + IntVolt volt = trace[i] - *ref - basePrev[i]; + + IntVolt dltBase = 0; + dltBase = (devPrev[i] < volt) ? devPrev[i] / tauBase : dltBase; + dltBase = (volt < -devPrev[i]) ? -devPrev[i] / (tauBase * 2) : dltBase; + baselines[i] = basePrev[i] + dltBase; + + IntVolt dltDev = 0; + dltDev = (devPrev[i] < volt && volt < 5 * devPrev[i]) ? devChange : dltDev; + dltDev = ((0 < volt && volt <= devPrev[i]) || 6 * devPrev[i] < volt) ? -devChange : dltDev; + IntVolt dev = devPrev[i] + dltDev; + deviations[i] = (dev < minDev) ? minDev : dev; // clamp deviations at minDev + } + } - IntCalc voltThr = volt * thrQuant; - IntCalc thr = threshold * dev; - IntCalc minAvg = minAvgAmp * dev; - IntCalc maxAHP = maxAHPAmp * dev; + void Detection::detection(const IntVolt *trace, const IntVolt *ref, + const IntVolt *baselines, const IntVolt *deviations, + IntChannel channelStart, IntChannel channelEnd, IntFrame t) + { + for (IntChannel i = channelStart; i < channelEnd; i++) + { + IntVolt volt = trace[i] - *ref - baselines[i]; // calc against updated baselines + IntVolt dev = deviations[i]; - if (spikeTime[i] < 0) // not in spike + IntCalc voltThr = volt * thrQuant; + IntCalc thr = threshold * dev; + IntCalc minAvg = minAvgAmp * dev; + IntCalc maxAHP = maxAHPAmp * dev; + + if (spikeTime[i] < 0) // not in spike + { + if (voltThr > thr) // threshold crossing { - if (voltThr > thr) // threshold crossing - { - spikeTime[i] = 0; - spikeAmp[i] = volt; - spikeArea[i] = voltThr; - hasAHP[i] = false; - } - continue; + spikeTime[i] = 0; + spikeAmp[i] = volt; + spikeArea[i] = voltThr; + hasAHP[i] = false; } - // else: during a spike - spikeTime[i]++; - // 1 <= spikeTime[i] + continue; + } + // else: during a spike + spikeTime[i]++; + // 1 <= spikeTime[i] - if (spikeTime[i] < ampAvgDur) // sum up area in ampAvgDur + if (spikeTime[i] < ampAvgDur) // sum up area in ampAvgDur + { + spikeArea[i] += voltThr; + if (spikeAmp[i] < volt) // larger amp found { - spikeArea[i] += voltThr; - if (spikeAmp[i] < volt) // larger amp found - { - spikeTime[i] = 0; // reset peak to current - spikeAmp[i] = volt; - // but accumulate area (already added) - hasAHP[i] = false; - } - continue; + spikeTime[i] = 0; // reset peak to current + spikeAmp[i] = volt; + // but accumulate area (already added) + hasAHP[i] = false; } - // else: ampAvgDur <= spikeTime[i] + continue; + } + // else: ampAvgDur <= spikeTime[i] - if (spikeTime[i] < spikeDur) + if (spikeTime[i] < spikeDur) + { + if (voltThr < maxAHP) // AHP found { - if (voltThr < maxAHP) // AHP found - { - hasAHP[i] = true; - } - else if (spikeAmp[i] < volt) // larger amp found - { - spikeTime[i] = 0; // reset peak to current - spikeAmp[i] = volt; - spikeArea[i] += voltThr; // but accumulate area - hasAHP[i] = false; - } - continue; + hasAHP[i] = true; } - // else: spikeTime[i] == spikeDur, spike end - - if (spikeArea[i] > minAvg * ampAvgDur && // reach min area - (hasAHP[i] || voltThr < maxAHP)) // AHP exist + else if (spikeAmp[i] < volt) // larger amp found { - pQueue->addSpike(Spike(t - spikeDur, i, spikeAmp[i])); + spikeTime[i] = 0; // reset peak to current + spikeAmp[i] = volt; + spikeArea[i] += voltThr; // but accumulate area + hasAHP[i] = false; } + continue; + } + // else: spikeTime[i] == spikeDur, spike end - spikeTime[i] = -1; // reset counter even if not spike + if (spikeArea[i] > minAvg * ampAvgDur && // reach min area + (hasAHP[i] || voltThr < maxAHP)) // AHP exist + { + pQueue->addSpike(Spike(t - spikeDur, i, spikeAmp[i])); + } - } // second for i + spikeTime[i] = -1; // reset counter even if not spike - } // for t + } // for i - } // Detection::estimateAndDetect + } // Detection::detection } // namespace HSDetection diff --git a/hs_detection/detect/Detection.h b/hs_detection/detect/Detection.h index 0d45781..87a2a0f 100644 --- a/hs_detection/detect/Detection.h +++ b/hs_detection/detect/Detection.h @@ -93,6 +93,13 @@ namespace HSDetection inline void commonAverage(IntVolt *ref, const IntVolt *trace); void scaleAndAverage(IntFrame chunkStart, IntFrame chunkLen); void castAndCommonref(IntFrame chunkStart, IntFrame chunkLen); + inline void estimation(IntVolt *baselines, IntVolt *deviations, + const IntVolt *trace, const IntVolt *ref, + const IntVolt *basePrev, const IntVolt *devPrev, + IntChannel alignedStart, IntChannel alignedEnd); + inline void detection(const IntVolt *trace, const IntVolt *ref, + const IntVolt *baselines, const IntVolt *deviations, + IntChannel channelStart, IntChannel channelEnd, IntFrame t); void estimateAndDetect(IntFrame chunkStart, IntFrame chunkLen); public: From e73107cc997147936303a463b7969d888a299bec Mon Sep 17 00:00:00 2001 From: lkct Date: Tue, 16 Aug 2022 20:57:32 +0100 Subject: [PATCH 11/11] update setup --- setup.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 9c36ddb..4cc4900 100644 --- a/setup.py +++ b/setup.py @@ -31,6 +31,7 @@ def cythonize(module_list, **kwargs): PROFILE = 0 +NATIVE_OPTIM = True def get_version() -> str: @@ -67,8 +68,9 @@ def get_version() -> str: sources = glob.glob('hs_detection/detect/**/[A-Z]*.cpp', recursive=True) sources += [os.path.join('hs_detection/detect', fn) for fn in ext_src] -extra_compile_args = ['-std=c++17', '-O3'] -link_extra_args = [] +extra_compile_args = ['-std=c++17', '-O3', '-fopenmp'] + \ + ['-march=native', '-mtune=native'] * NATIVE_OPTIM +link_extra_args = ['-fopenmp'] # OS X support if platform.system() == 'Darwin': extra_compile_args += ['-mmacosx-version-min=10.14', '-F.'] @@ -79,7 +81,8 @@ def get_version() -> str: Extension(name='hs_detection.detect.detect', sources=sources, include_dirs=[numpy_include], - define_macros=[('CYTHON_TRACE_NOGIL', '1' if PROFILE >= 2 else '0')], + define_macros=[ + ('CYTHON_TRACE_NOGIL', '1' if PROFILE >= 2 else '0')], extra_compile_args=extra_compile_args, extra_link_args=link_extra_args, language='c++'),