Skip to content

Commit

Permalink
Implement recording
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed Aug 31, 2024
1 parent 01c6053 commit c2b6e35
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 56 deletions.
27 changes: 25 additions & 2 deletions Hrv/HeartbeatMetrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,29 @@ namespace fheel

void HeartbeatMetrics::startRecording()
{
// TODO
// Recreate the accumulators for stats
// Global ones
std::destroy_at(&accumulators);
std::construct_at(&accumulators);

// Per-sensor
for(auto& [name, hb] : this->beats)
{
std::destroy_at(&hb.accumulators);
std::construct_at(&hb.accumulators);
}
}

void HeartbeatMetrics::stopRecording()
{
// TODO
inputs.baseline.value = ba::extract::mean(accumulators);
global_stddev = std::sqrt(ba::extract::variance(accumulators));

for(auto& [name, hb] : this->beats)
{
hb.average = ba::extract::mean(hb.accumulators);
hb.stddev = std::sqrt(ba::extract::variance(hb.accumulators));
}
}

void HeartbeatMetrics::addRow(const std::string& name, int bpm)
Expand All @@ -30,6 +47,12 @@ void HeartbeatMetrics::addRow(const std::string& name, int bpm)
auto& vec = hb.data;
vec.push_back({m_last_point_timestamp, bpm});

if(inputs.recording)
{
this->accumulators(bpm);
hb.accumulators(bpm);
}

computeIndividualMetrics(hb, std::chrono::milliseconds(inputs.window.value));

this->outputs.excitation(excitation{
Expand Down
61 changes: 43 additions & 18 deletions Hrv/HeartbeatMetrics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

/* SPDX-License-Identifier: GPL-3.0-or-later */

#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/rolling_mean.hpp>
#include <boost/accumulators/statistics/rolling_variance.hpp>
#include <boost/circular_buffer.hpp>
#include <boost/unordered/unordered_flat_map.hpp>

Expand All @@ -13,7 +16,7 @@

#include <chrono>
#include <vector>

namespace ba = boost::accumulators;
namespace fheel
{
// Structures de données représentant les statistiques
Expand Down Expand Up @@ -62,11 +65,16 @@ class HeartbeatMetrics
using timestamp = clk::time_point;
using bpm = std::pair<timestamp, int>;

using stat_accum
= ba::accumulator_set<float, ba::stats<ba::tag::mean, ba::tag::variance>>;

// Structure de donnée interne pour stocker l'information reçue d'un capteur donné
struct heartbeats
{
boost::circular_buffer<bpm> data = boost::circular_buffer<bpm>(default_capacity);
struct statistics

// Statistics for the current window of time (e.g. the last 5 seconds)
struct running_statistics
{
std::vector<float> bpms;
int count{};
Expand All @@ -77,6 +85,12 @@ class HeartbeatMetrics
float stddev{};
float rmssd{};
} stats;

// Global statistics from the recording feature
stat_accum accumulators;

float average{};
float stddev{};
};

// Messages qu'on veut pouvoir traiter depuis Max
Expand All @@ -91,46 +105,53 @@ class HeartbeatMetrics
self.addRow(name, bpm);
}
} heartbeats;

struct
{
halp_meta(name, "start")
void operator()(HeartbeatMetrics& self) { self.startRecording(); }
} start;

struct
{
halp_meta(name, "stop")
void operator()(HeartbeatMetrics& self) { self.stopRecording(); }
} stop;
};

// Attributs et autres entrées
struct
{
struct : halp::hslider_f32<"Baseline", halp::range{20., 200., 74.}> {
struct : halp::hslider_f32<"Baseline", halp::range{20., 200., 74.}>
{
halp_meta(c_name, "baseline")
halp_meta(description, "Heart-rate baseline in bpm")
halp_flag(class_attribute);
} baseline;

struct : halp::hslider_f32<"Ceil", halp::range{1., 4., 1.25}> {
struct : halp::hslider_f32<"Ceil", halp::range{1., 4., 1.25}>
{
halp_meta(c_name, "ceil")
halp_meta(description, "Heart-rate peak ceil")
halp_flag(class_attribute);
} ceil;

struct : halp::hslider_i32<"Window", halp::irange{1, 10000, 1000}> {
struct : halp::hslider_i32<"Window", halp::irange{1, 10000, 1000}>
{
halp_meta(c_name, "window")
halp_meta(description, "Time window in ms upon which the analysis is performed")
halp_flag(class_attribute);
} window;

struct : halp::hslider_f32<"Stddev Range", halp::range{0.1, 5, 3}> {
struct : halp::hslider_f32<"Stddev Range", halp::range{0.1, 5, 3}>
{
halp_meta(c_name, "stddev_range")
halp_meta(description, "Std deviation range")
halp_flag(class_attribute);
} stddev;

struct : halp::val_port<"Recording", bool>
{
halp_meta(c_name, "recording")
halp_meta(description, "Data will be recorded when this is enabled.")
halp_flag(class_attribute);

void update(HeartbeatMetrics& self)
{
if(value)
self.startRecording();
else
self.stopRecording();
}
} recording;
} inputs;

// Sorties
Expand Down Expand Up @@ -164,5 +185,9 @@ class HeartbeatMetrics
private:
timestamp m_last_point_timestamp{};
boost::unordered_flat_map<std::string, heartbeats> beats;

// Global accumulators for mean / variance
stat_accum accumulators;
double global_stddev = 1.;
};
}
56 changes: 20 additions & 36 deletions max/package/help/heartbeat_metrics.maxhelp
Original file line number Diff line number Diff line change
Expand Up @@ -95,42 +95,6 @@
"patching_rect" : [ 176.0, 408.5, 24.0, 24.0 ]
}

}
, {
"box" : {
"id" : "obj-28",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 16.0, 130.0, 127.0, 33.0 ],
"text" : "Pas encore fini d' implémenter sorry"
}

}
, {
"box" : {
"id" : "obj-27",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 56.0, 173.0, 31.0, 22.0 ],
"text" : "stop"
}

}
, {
"box" : {
"id" : "obj-25",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 16.0, 173.0, 32.0, 22.0 ],
"text" : "start"
}

}
, {
"box" : {
Expand Down Expand Up @@ -604,6 +568,19 @@
"patching_rect" : [ 429.0, 261.0, 150.0, 22.0 ]
}

}
, {
"box" : {
"attr" : "recording",
"id" : "obj-24",
"maxclass" : "attrui",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"parameter_enable" : 0,
"patching_rect" : [ 429.0, 14.0, 150.0, 22.0 ]
}

}
],
"lines" : [ {
Expand Down Expand Up @@ -698,6 +675,13 @@
"source" : [ "obj-2", 0 ]
}

}
, {
"patchline" : {
"destination" : [ "obj-5", 0 ],
"source" : [ "obj-24", 0 ]
}

}
, {
"patchline" : {
Expand Down

0 comments on commit c2b6e35

Please sign in to comment.