diff --git a/EdgeImpulse.EI-SDK.pdsc b/EdgeImpulse.EI-SDK.pdsc
index a9ef04e..24dc4a9 100644
--- a/EdgeImpulse.EI-SDK.pdsc
+++ b/EdgeImpulse.EI-SDK.pdsc
@@ -5,13 +5,16 @@
EI-SDK
LICENSE-apache-2.0.txt
Edge Impulse SDK
- https://github.com/edgeimpulse/edge-impulse-sdk-pack/releases/download/v1.49.18/
+ https://github.com/edgeimpulse/edge-impulse-sdk-pack/releases/download/v1.49.21/
hello@edgeimpulse.com
https://github.com/edgeimpulse/edge-impulse-sdk-pack.git
-
+
EI-SDK
+
+ EI-SDK
+
EI-SDK
@@ -125,7 +128,7 @@
-
+
Edge Impulse SDK
@@ -615,6 +618,7 @@
+
diff --git a/EdgeImpulse.pidx b/EdgeImpulse.pidx
index d2bf066..74f0f02 100644
--- a/EdgeImpulse.pidx
+++ b/EdgeImpulse.pidx
@@ -2,8 +2,8 @@
EdgeImpulse
https://raw.githubusercontent.com/edgeimpulse/edge-impulse-sdk-pack/main/
- 2024-04-30 16:25:39
+ 2024-05-03 10:40:48
-
+
diff --git a/edgeimpulse/edge-impulse-sdk/classifier/ei_model_types.h b/edgeimpulse/edge-impulse-sdk/classifier/ei_model_types.h
index 5ed5608..c85e8d6 100644
--- a/edgeimpulse/edge-impulse-sdk/classifier/ei_model_types.h
+++ b/edgeimpulse/edge-impulse-sdk/classifier/ei_model_types.h
@@ -107,7 +107,7 @@ typedef struct {
uint8_t *axes;
size_t axes_size;
int version; // future proof, can easily add to this struct now
- DspHandle* (*factory)(void* config); // nullptr means no state
+ DspHandle* (*factory)(void* config, float sampling_freq); // nullptr means no state
// v1 ends here
} ei_model_dsp_t;
@@ -264,7 +264,7 @@ typedef DspHandle* _dsp_handle_ptr_t;
DspHandle* get_dsp_handle(size_t ix) {
if (dsp_handles[ix] == nullptr) {
- dsp_handles[ix] = impulse->dsp_blocks[ix].factory(impulse->dsp_blocks[ix].config);
+ dsp_handles[ix] = impulse->dsp_blocks[ix].factory(impulse->dsp_blocks[ix].config, impulse->frequency);
}
return dsp_handles[ix];
}
diff --git a/edgeimpulse/edge-impulse-sdk/classifier/ei_run_dsp.h b/edgeimpulse/edge-impulse-sdk/classifier/ei_run_dsp.h
index 4ad67ac..e46612c 100644
--- a/edgeimpulse/edge-impulse-sdk/classifier/ei_run_dsp.h
+++ b/edgeimpulse/edge-impulse-sdk/classifier/ei_run_dsp.h
@@ -25,6 +25,10 @@
#include "edge-impulse-sdk/dsp/ei_flatten.h"
#include "model-parameters/model_metadata.h"
+#if EI_CLASSIFIER_HR_ENABLED
+#include "edge-impulse-sdk/dsp/ei_hr.hpp"
+#endif
+
#if defined(__cplusplus) && EI_C_LINKAGE == 1
extern "C" {
extern void ei_printf(const char *format, ...);
@@ -48,6 +52,23 @@ static float *ei_dsp_cont_current_frame = nullptr;
static size_t ei_dsp_cont_current_frame_size = 0;
static int ei_dsp_cont_current_frame_ix = 0;
+__attribute__((unused)) int extract_hr_features(
+ signal_t *signal,
+ matrix_t *output_matrix,
+ void *config_ptr,
+ const float frequency)
+{
+#if EI_CLASSIFIER_HR_ENABLED
+ auto handle = hr_class::create(config_ptr, frequency);
+ auto ret = handle->extract(signal, output_matrix, config_ptr, frequency);
+ delete handle;
+ return ret;
+#else
+ ei_printf("ERR: Please contact EI sales to enable heart rate processing in deployment");
+ return EIDSP_NOT_SUPPORTED;
+#endif
+}
+
__attribute__((unused)) int extract_spectral_analysis_features(
signal_t *signal,
matrix_t *output_matrix,
@@ -137,7 +158,7 @@ __attribute__((unused)) int extract_raw_features(signal_t *signal, matrix_t *out
}
__attribute__((unused)) int extract_flatten_features(signal_t *signal, matrix_t *output_matrix, void *config_ptr, const float frequency) {
- auto handle = flatten_class::create(config_ptr);
+ auto handle = flatten_class::create(config_ptr, frequency);
auto ret = handle->extract(signal, output_matrix, config_ptr, frequency);
delete handle;
return ret;
diff --git a/edgeimpulse/edge-impulse-sdk/dsp/ei_flatten.h b/edgeimpulse/edge-impulse-sdk/dsp/ei_flatten.h
index 8802543..d7586b2 100644
--- a/edgeimpulse/edge-impulse-sdk/dsp/ei_flatten.h
+++ b/edgeimpulse/edge-impulse-sdk/dsp/ei_flatten.h
@@ -154,7 +154,7 @@ class flatten_class : public DspHandle {
return EIDSP_OK;
}
- static DspHandle* create(void* config);
+ static DspHandle* create(void* config, float _sampling_frequency);
void* operator new(size_t size) {
// Custom memory allocation logic here
@@ -190,7 +190,7 @@ class flatten_class : public DspHandle {
}
};
-DspHandle* flatten_class::create(void* config_in) { // NOLINT def in header is OK at EI
+DspHandle* flatten_class::create(void* config_in, float _sampling_frequency) { // NOLINT def in header is OK at EI
auto config = reinterpret_cast(config_in);
return new flatten_class(config->moving_avg_num_windows, config->axes);
};
diff --git a/edgeimpulse/edge-impulse-sdk/dsp/ei_hr.hpp b/edgeimpulse/edge-impulse-sdk/dsp/ei_hr.hpp
new file mode 100644
index 0000000..6570f9b
--- /dev/null
+++ b/edgeimpulse/edge-impulse-sdk/dsp/ei_hr.hpp
@@ -0,0 +1,96 @@
+/* Edge Impulse inferencing library
+ * Copyright (c) 2022 EdgeImpulse Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef HR_PPG_HPP
+#define HR_PPG_HPP
+
+#include "edge-impulse-sdk/dsp/numpy.hpp"
+#include "edge-impulse-sdk/dsp/ei_dsp_handle.h"
+#include "edge-impulse-enterprise/hr/hr_ppg.hpp"
+
+class hr_class : public DspHandle {
+public:
+ int print() override {
+ ei_printf("Last HR: %f\n", ppg._res.hr);
+ return ei::EIDSP_OK;
+ }
+
+ int extract(ei::signal_t *signal, ei::matrix_t *output_matrix, void *config_ptr, const float frequency) override {
+ using namespace ei;
+
+ // Don't need just yet
+ // ei_dsp_config_hr_t config = *((ei_dsp_config_hr_t*)config_ptr);
+
+
+ // TODO fix for axes / accel
+ size_t samples_per_inc = ppg.win_inc_samples;
+ // TODO go in a loop for the full window size, once I can actually test this vs studio
+ if(signal->total_length != samples_per_inc) {
+ return EIDSP_BUFFER_SIZE_MISMATCH;
+ }
+
+ // TODO ask for smaller increments and bp them into place
+ // Copy into the end of the buffer
+ matrix_t temp(ppg.axes, samples_per_inc);
+ signal->get_data(0, samples_per_inc, temp.buffer);
+
+
+ output_matrix->buffer[0] = ppg.stream(&temp);
+
+ output_matrix->rows = 1;
+ output_matrix->cols = 1;
+ return EIDSP_OK;
+ }
+
+ // TODO: actually read in config: axes too!
+ hr_class(float frequency) : ppg(frequency, 1, 8*50, 2*50, true) {
+ }
+
+ // Boilerplate below here
+ static DspHandle* create(void* config, float frequency);
+
+ void* operator new(size_t size) {
+ // Custom memory allocation logic here
+ return ei_malloc(size);
+ }
+
+ void operator delete(void* ptr) {
+ // Custom memory deallocation logic here
+ ei_free(ptr);
+ }
+ // end boilerplate
+private:
+ ei::hr_ppg ppg;
+};
+
+DspHandle* hr_class::create(void* config_in, float frequency) { // NOLINT def in header is OK at EI
+ // Don't need just yet
+ // auto config = reinterpret_cast(config_in);
+ // TODO: actually read in config
+ return new hr_class(frequency);
+};
+
+/*
+NOTE, contact EI sales for license and source to use EI heart rate and heart rate variance functions in deployment
+*/
+
+#endif
\ No newline at end of file
diff --git a/edgeimpulse/edge-impulse-sdk/dsp/numpy.hpp b/edgeimpulse/edge-impulse-sdk/dsp/numpy.hpp
index 7870ff7..28b8f22 100644
--- a/edgeimpulse/edge-impulse-sdk/dsp/numpy.hpp
+++ b/edgeimpulse/edge-impulse-sdk/dsp/numpy.hpp
@@ -335,37 +335,40 @@ class numpy {
}
static void transpose_in_place(matrix_t *matrix) {
- size_t size = matrix->cols * matrix->rows - 1;
- float temp; // temp for swap
- size_t next; // next item to swap
- size_t cycleBegin; // index of start of cycle
- size_t i; // location in matrix
- size_t all_done_mark = 1;
- ei_vector done(size+1,false);
-
- i = 1; // Note that matrix[0] and last element of matrix won't move
- while (1)
- {
- cycleBegin = i;
- temp = matrix->buffer[i];
- do
+ // Don't bother if either dim is one, just need to swap the dimension sizes
+ if( matrix->rows != 1 && matrix->cols != 1) {
+ size_t size = matrix->cols * matrix->rows - 1;
+ float temp; // temp for swap
+ size_t next; // next item to swap
+ size_t cycleBegin; // index of start of cycle
+ size_t i; // location in matrix
+ size_t all_done_mark = 1;
+ ei_vector done(size+1,false);
+
+ i = 1; // Note that matrix[0] and last element of matrix won't move
+ while (1)
{
- size_t col = i % matrix->cols;
- size_t row = i / matrix->cols;
- // swap row and col to make new idx, b/c we want to know where in the transposed matrix
- next = col*matrix->rows + row;
- float temp2 = matrix->buffer[next];
- matrix->buffer[next] = temp;
- temp = temp2;
- done[next] = true;
- i = next;
- }
- while (i != cycleBegin);
+ cycleBegin = i;
+ temp = matrix->buffer[i];
+ do
+ {
+ size_t col = i % matrix->cols;
+ size_t row = i / matrix->cols;
+ // swap row and col to make new idx, b/c we want to know where in the transposed matrix
+ next = col*matrix->rows + row;
+ float temp2 = matrix->buffer[next];
+ matrix->buffer[next] = temp;
+ temp = temp2;
+ done[next] = true;
+ i = next;
+ }
+ while (i != cycleBegin);
- // start next cycle by find next not done
- for (i = all_done_mark; done[i]; i++) {
- all_done_mark++; // move the high water mark so we don't look again
- if(i>=size) { goto LOOP_END; }
+ // start next cycle by find next not done
+ for (i = all_done_mark; done[i]; i++) {
+ all_done_mark++; // move the high water mark so we don't look again
+ if(i>=size) { goto LOOP_END; }
+ }
}
}
LOOP_END:
diff --git a/edgeimpulse/edge-impulse-sdk/dsp/spectral/signal.hpp b/edgeimpulse/edge-impulse-sdk/dsp/spectral/signal.hpp
index 7452f76..37fb0e9 100644
--- a/edgeimpulse/edge-impulse-sdk/dsp/spectral/signal.hpp
+++ b/edgeimpulse/edge-impulse-sdk/dsp/spectral/signal.hpp
@@ -95,7 +95,12 @@ class signal {
zi_vec(zi_, zi_ + (num_sections_ * 2)),
num_sections(num_sections_)
{
- zi = zi_vec.data();
+ }
+
+ void update(const float *coeff_, const float *zi_)
+ {
+ coeff = coeff_;
+ zi_vec.assign(zi_, zi_ + (num_sections * 2));
}
/**
@@ -109,7 +114,7 @@ class signal {
{
assert(num_sections > 0);
- iir2(input, output, size, coeff, coeff + 3, zi);
+ iir2(input, output, size, coeff, coeff + 3, zi_vec.data());
for (size_t sect = 1; sect < num_sections; sect++) {
iir2(
@@ -118,15 +123,15 @@ class signal {
size,
coeff + sect * 6,
coeff + sect * 6 + 3,
- zi + sect * 2);
+ zi_vec.data() + sect * 2);
}
}
void init(float x0)
{
for (size_t sect = 0; sect < num_sections; sect++) {
- zi[sect * 2] *= x0;
- zi[sect * 2 + 1] *= x0;
+ zi_vec.data()[sect * 2] *= x0;
+ zi_vec.data()[sect * 2 + 1] *= x0;
}
}
};