Skip to content

Commit

Permalink
Part of #89. Multiple analyses and exposures now working
Browse files Browse the repository at this point in the history
Multiple analyses and exposures now working
- Fixed bug in UUID == method
- Fixed bug in allocatable array readlIndex method (Caused issues in exposure manager linking values to the correct agent)
- Multi-variate analyses in analysis API now working
- const SampleList iterators now working well
- Multiple exposure types supported in exposure manager
- RunningMean<ValT> datatype working well with exposure and analysis APIs
- Just the final risk score calculation to add now
Signed-off-by: Adam Fowler <[email protected]>
  • Loading branch information
adamfowleruk committed Dec 5, 2021
1 parent 6ca609d commit fb07456
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 101 deletions.
34 changes: 16 additions & 18 deletions .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,29 @@
{
"name": "Win64",
"includePath": [
"${default}",
"${workspaceFolder}/herald/include"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
"${workspaceFolder}"
// "${workspaceFolder}/herald/include",
// "${workspaceFolder}/herald-tests"
],
"windowsSdkVersion": "10.0.19041.0",
"compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.27.29110/bin/Hostx64/x64/cl.exe",
// "defines": [
// "_DEBUG",
// "UNICODE",
// "_UNICODE"
// ],
// "windowsSdkVersion": "10.0.19041.0",
// "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.27.29110/bin/Hostx64/x64/cl.exe",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "msvc-x64",
"configurationProvider": "ms-vscode.cmake-tools",
"browse": {
"path": [
"${workspaceFolder}",
"${workspaceFolder}/herald/include"
],
"limitSymbolsToIncludedHeaders": true
}
// "intelliSenseMode": "msvc-x64",
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
"configurationProvider": "ms-vscode.cmake-tools"
},
{
"name": "zephyr",
"includePath": [
"${default}",
"${workspaceFolder}/herald/include",
"${workspaceFolder}/herald-tests",
"${ZEPHYR_BASE}/include",
"${ZEPHYR_BASE}/../nrf/include"
],
Expand All @@ -49,6 +45,8 @@
"path": [
"${workspaceFolder}",
"${workspaceFolder}/herald/include",
"${workspaceFolder}/herald/src",
"${workspaceFolder}/herald-tests",
"${ZEPHYR_BASE}/include",
"${ZEPHYR_BASE}/../nrf/include"
],
Expand Down
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,9 @@
"board": "nrf52840dk_nrf52840",
"arch": "arm",
"dir": "${ZEPHYR_BASE}/boards/arm/nrf52840dk_nrf52840"
},
"C_Cpp.intelliSenseMemoryLimit": 16384,
"editor.quickSuggestions": {
"other": true
}
}
93 changes: 93 additions & 0 deletions herald-tests/analysisrunner-tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,45 @@ struct DummyDistanceDelegate /* : herald::analysis::AnalysisDelegate */ {
};


struct DummyBrightnessDelegate {
using value_type = RunningMean<Luminosity>;

DummyBrightnessDelegate() : lastSampledID(0), brightness() {};
DummyBrightnessDelegate(const DummyBrightnessDelegate&) = delete; // copy ctor deleted
DummyBrightnessDelegate(DummyBrightnessDelegate&& other) noexcept : lastSampledID(other.lastSampledID), brightness(std::move(other.brightness)) {} // move ctor
~DummyBrightnessDelegate() {};

DummyBrightnessDelegate& operator=(DummyBrightnessDelegate&& other) noexcept {
lastSampledID = other.lastSampledID;
std::swap(brightness,other.brightness);
return *this;
}

// specific override of template
void newSample(SampledID sampled, Sample<RunningMean<Luminosity>> sample) {
lastSampledID = sampled;
brightness.push(sample);
}

void reset() {
brightness.clear();
lastSampledID = 0;
}

// Test only methods
SampledID lastSampled() {
return lastSampledID;
}

const SampleList<Sample<RunningMean<Luminosity>>,25>& samples() {
return brightness;
}

private:
SampledID lastSampledID;
SampleList<Sample<RunningMean<Luminosity>>,25> brightness;
};

TEST_CASE("variantset-basic", "[variantset][basic]") {
SECTION("variantset-basic") {
herald::analysis::VariantSet<int,double> vs;
Expand Down Expand Up @@ -177,6 +216,60 @@ TEST_CASE("analysisrunner-singledataitem", "[analysisrunner][singledataitem]") {
}
}


/// Single data item use case with 1 data item, no failures, correct summary output
TEST_CASE("analysisrunner-singledataitem-twoanalyses", "[analysisrunner][singledataitem][twoanalyses][multivariate]") {
SECTION("analysisrunner-singledataitem-twoanalyses") {
SampleList<Sample<RSSI>,25> srcData;
srcData.push(50,-55);
DummySampleSource src(1234,std::move(srcData));

SampleList<Sample<Luminosity>,15> srcLightData;
srcLightData.push(40,12);
srcLightData.push(50,12);
srcLightData.push(60,12);
DummySampleSource srcLight(5678,std::move(srcLightData));

herald::analysis::algorithms::distance::FowlerBasicAnalyser distanceAnalyser(30, -50, -24);
herald::analysis::algorithms::RunningMeanAnalyser<herald::datatype::Luminosity,2> meanLight;

DummyDistanceDelegate myDelegate;
DummyBrightnessDelegate myBrightnessDelegate;
herald::analysis::AnalysisDelegateManager adm(std::move(myDelegate),std::move(myBrightnessDelegate)); // NOTE: myDelegate MOVED FROM and no longer accessible
herald::analysis::AnalysisProviderManager apm(std::move(distanceAnalyser), std::move(meanLight)); // NOTE: distanceAnalyser MOVED FROM and no longer accessible

herald::analysis::AnalysisRunner<
herald::analysis::AnalysisDelegateManager<
DummyDistanceDelegate,
DummyBrightnessDelegate
>,
herald::analysis::AnalysisProviderManager<
herald::analysis::algorithms::distance::FowlerBasicAnalyser,
herald::analysis::algorithms::RunningMeanAnalyser<herald::datatype::Luminosity,2>
>,
RSSI,Distance,Luminosity,RunningMean<Luminosity>
> runner(adm, apm); // just for Sample<RSSI> types, and their produced output (Sample<Distance>)

src.run(140,runner);
srcLight.run(160,runner);
REQUIRE(src.getLastRunAdded() == 1); // Single data item
REQUIRE(srcLight.getLastRunAdded() == 3); // Three data items

auto& delegateRef = adm.get<DummyDistanceDelegate>();
REQUIRE(delegateRef.lastSampled() == 1234); // ran once, past 50, for SampleID=1234

auto& samples = delegateRef.samples();
REQUIRE(samples.size() == 1); // 1 as single data item (for THIS delegate)


auto& delegateBRef = adm.get<DummyBrightnessDelegate>();
REQUIRE(delegateBRef.lastSampled() == 5678); // ran once, past 50, for SampleID=1234

auto& samplesB = delegateBRef.samples();
REQUIRE(samplesB.size() == 1); // 1 as only one mean generated (one run) for this variable
}
}

/// [Who] As a DCT app developer
/// [What] I want to link my live application data to an analysis runner easily
/// [Value] So I don't have to write plumbing code for Herald itself
Expand Down
21 changes: 13 additions & 8 deletions herald-tests/exposure-manager-tests-new.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ TEST_CASE("risk-multi-variate", "[exposure][periods][window][risk][multi-variate
srcLightData.push(240,50);
srcLightData.push(270,50);
srcLightData.push(300,50);
DummySampleSource srcLight(1234,std::move(srcLightData)); // Type derived from Sample List Sample's type
// NOTE instance ID (5678) MUST be different from RSSI's as source sensors are different
DummySampleSource srcLight(5678,std::move(srcLightData)); // Type derived from Sample List Sample's type


herald::analysis::algorithms::RSSIMinutesAnalyser riskAnalyser{60}; // One RSSIMinute every 60 seconds of input
Expand All @@ -259,7 +260,8 @@ TEST_CASE("risk-multi-variate", "[exposure][periods][window][risk][multi-variate
herald::exposure::ExposureManagerDelegate<
herald::datatype::RSSIMinute,
herald::exposure::ExposureManager<DummyExposureCallbackHandler,8, DummyExposureStore>
>,
>
,
herald::exposure::ExposureManagerDelegate<
herald::datatype::RunningMean<herald::datatype::Luminosity>,
herald::exposure::ExposureManager<DummyExposureCallbackHandler,8, DummyExposureStore>
Expand Down Expand Up @@ -287,7 +289,8 @@ TEST_CASE("risk-multi-variate", "[exposure][periods][window][risk][multi-variate
sensorClass::bluetoothProximityHerald, proxInstanceId);
// Now add luminosity
herald::datatype::UUID lumInstanceId =
herald::datatype::UUID::fromString("88888888-1111-4011-8011-111111111111");
herald::datatype::UUID::fromString("88888888-1111-4011-8011-122221111111");
// TODO determine why the following line causes changeCount to be set to 0 instead of a value
bool addSuccess2 = em.addSource<RunningMean<Luminosity>>(
herald::datatype::agent::lightBrightness,
sensorClass::luninositySingleChannelLums, lumInstanceId);
Expand All @@ -304,19 +307,21 @@ TEST_CASE("risk-multi-variate", "[exposure][periods][window][risk][multi-variate
em.enableRunning(); // required, else no changes will be recorded
// WARNING: Unlike in real life, these data add operations occur in series, not in parallel
srcRssi.run(301, runner); // NB correctly increments changeCount (to 1, which is modified throughout)
srcLight.run(301, runner); // Incorrectly never calls applyExposure in ExposureManager
srcLight.run(301, runner);
// Now fire off any exposure changes
bool result = em.notifyOfChanges(); // TODO debug why this now produces no changes
bool result = em.notifyOfChanges(); // Note: Was failing because of substitution failure in analysis API due to SampleList iterator not supporting const

// Now confirm callback values are the same with a different window
REQUIRE(result); // A notification occured
// Note: Not introspecting callbacks as multiple variables which are valid to arrive in any order

// Now confirm we have the correct number of samples for each agent
// RSSI: 120 second windows, starting at 60 seconds, 300 second period in total - so 2 periods
// Luminosity: 120 second windows, starting at 0 seconds, 300 second period in total - so 3 periods
REQUIRE(2 == em.getCountByInstanceId(proxInstanceId));
REQUIRE(3 == em.getCountByInstanceId(lumInstanceId));
// Luminosity: 120 second windows, starting at 0 seconds, 300 second period in total, but only ran once so average gives 1 result only
REQUIRE(1 == em.getCountByInstanceId(lumInstanceId));
// Check luminosity hasn't overwritten rssi prox values
auto cnt = em.getCountByInstanceId(proxInstanceId);
REQUIRE(2 == cnt);

// TODO Also determine that there are two risk values for the same time period (risk times are set to 120 seconds)
// Risk score should be:-
Expand Down
7 changes: 4 additions & 3 deletions herald/include/herald/analysis/sample_algorithms.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,10 @@ struct RunningMeanAggregate {

RunningMeanAggregate() : run(1), values() {}
RunningMeanAggregate(const RunningMeanAggregate<ValT,MaxRecentValues>& other) : run(other.run), values() {
// for (const auto& v: other.values) {
// values.add(v);
// }
auto iter = other.values.begin();
for (;iter != other.values.end();++iter) {
values.push(*iter);
}
}
RunningMeanAggregate(RunningMeanAggregate<ValT,MaxRecentValues>&& other) : run(other.run), values() {
// for (auto& v: other.values) {
Expand Down
10 changes: 5 additions & 5 deletions herald/include/herald/analysis/sampling.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,11 @@ struct SampleList {
return data[oldestPosition].taken;
}

SampleIterator<SampleList<SampleT,MaxSize>> begin() noexcept {
SampleIterator<SampleList<SampleT,MaxSize>> begin() const noexcept {
return SampleIterator<SampleList<SampleT,MaxSize>>(*this);
}

SampleIterator<SampleList<SampleT,MaxSize>> end() noexcept {
SampleIterator<SampleList<SampleT,MaxSize>> end() const noexcept {
if (size() == 0) return SampleIterator<SampleList<SampleT,MaxSize>>(*this);
return SampleIterator<SampleList<SampleT,MaxSize>>(*this,size()); // calls this object's size() function, not the array!
}
Expand Down Expand Up @@ -259,8 +259,8 @@ struct SampleIterator {
using pointer = value_type*;
using reference = value_type&;

SampleIterator(SampleListT& sl) : list(sl), pos(0) {}
SampleIterator(SampleListT& sl, std::size_t from) : list(sl), pos(from) {} // used to get list.end() (size() + 1)
SampleIterator(const SampleListT& sl) : list(sl), pos(0) {}
SampleIterator(const SampleListT& sl, std::size_t from) : list(sl), pos(from) {} // used to get list.end() (size() + 1)
SampleIterator(const SampleIterator<SampleListT>& other) : list(other.list), pos(other.pos) {} // copy ctor
SampleIterator(SampleIterator<SampleListT>&& other) : list(other.list), pos(other.pos) {} // move ctor (cheaper to copy)
~SampleIterator() = default;
Expand Down Expand Up @@ -316,7 +316,7 @@ struct SampleIterator {
}

private:
SampleListT& list;
const SampleListT& list;
std::size_t pos;
};

Expand Down
7 changes: 4 additions & 3 deletions herald/include/herald/datatype/allocatable_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,14 @@ class AllocatableArray {
std::size_t count = 0;
while (idx < max_size) {
if (m_allocated.test(idx)) {
lastMatchedIndex = idx;
// Increment count
++count;
// Now check if we're at the virtualIndex'th allocated element
if (virtualIndex == count - 1) {
// return this index
return idx;
}
// Else just increment count
++count;
lastMatchedIndex = idx;
}
++idx;
}
Expand Down
Loading

0 comments on commit fb07456

Please sign in to comment.