Coverage Report

Created: 2021-08-28 18:14

D:\git\skunkworks\herald-for-cpp\herald\include\herald\analysis\distance_conversion.h
Line
Count
Source (jump to first uncovered line)
1
//  Copyright 2021 Herald Project Contributors
2
//  SPDX-License-Identifier: Apache-2.0
3
//
4
5
#ifndef HERALD_DISTANCE_CONVERSION_H
6
#define HERALD_DISTANCE_CONVERSION_H
7
8
#include <cmath>
9
10
#include "aggregates.h"
11
#include "ranges.h"
12
#include "runner.h"
13
#include "sampling.h"
14
#include "../datatype/distance.h"
15
16
// Debug only
17
// #include <iostream>
18
19
namespace herald {
20
namespace analysis {
21
namespace algorithms {
22
namespace distance {
23
24
using namespace herald::analysis::aggregates;
25
using namespace herald::analysis::sampling;
26
using namespace herald::datatype;
27
28
struct FowlerBasic {
29
  static constexpr int runs = 1;
30
31
14
  FowlerBasic(double intercept, double coefficient) : run(1), mode(), intercept(intercept), coefficient(coefficient) {}
32
69
  ~FowlerBasic() = default;
33
34
10
  void beginRun(int thisRun) { // 1 indexed
35
10
    run = thisRun;
36
10
    mode.beginRun(thisRun);
37
10
  }
38
39
  template <typename ValT>
40
44
  void map(ValT value) {
41
44
    mode.map(value);
42
44
  }
43
44
10
  double reduce() {
45
10
    double exponent = (mode.reduce() - intercept) / coefficient;
46
10
    return std::pow(10, exponent); // distance
47
10
  }
48
49
9
  void reset() {
50
9
    run = 1;
51
9
    mode.reset();
52
9
  }
53
54
private:
55
  int run;
56
  Mode mode; // cleaner to use the Mode rather than redo it in this class
57
  double intercept;
58
  double coefficient;
59
};
60
61
struct FowlerBasicAnalyser {
62
  using input_value_type = RSSI;
63
  using output_value_type = Distance;
64
65
  /// default constructor required for array instantiation in manager AnalysisProviderManager
66
6
  FowlerBasicAnalyser() : interval(10), basic(-11,-0.4), lastRan(0) {}
67
6
  FowlerBasicAnalyser(long interval, double intercept, double coefficient) : interval(interval), basic(intercept, coefficient), lastRan(0) {}
68
18
  ~FowlerBasicAnalyser() = default;
69
70
  // Generic
71
  // TODO consider removing this annoyance somehow...
72
  template <typename SrcT, std::size_t SrcSz,typename DstT, std::size_t DstSz, typename CallableForNewSample>
73
0
  bool analyse(Date timeNow, SampledID sampled, SampleList<Sample<SrcT>,SrcSz>& src, SampleList<Sample<DstT>,DstSz>& dst, CallableForNewSample& callable) {
74
0
    return false; // no op - compiled out
75
0
  }
Unexecuted instantiation: ??$analyse@VRSSI@datatype@herald@@$0BJ@V123@$0BJ@U?$AnalysisRunner@U?$AnalysisDelegateManager@UDummyDistanceDelegate@@@analysis@herald@@U?$AnalysisProviderManager@UFowlerBasicAnalyser@distance@algorithms@analysis@herald@@@23@VRSSI@datatype@3@UDistance@63@@analysis@3@@FowlerBasicAnalyser@distance@algorithms@analysis@herald@@QEAA_NVDate@datatype@4@_KAEAU?$SampleList@U?$Sample@VRSSI@datatype@herald@@@sampling@analysis@herald@@$0BJ@VRSSI@datatype@4@@sampling@34@2AEAU?$AnalysisRunner@U?$AnalysisDelegateManager@UDummyDistanceDelegate@@@analysis@herald@@U?$AnalysisProviderManager@UFowlerBasicAnalyser@distance@algorithms@analysis@herald@@@23@VRSSI@datatype@3@UDistance@63@@34@@Z
Unexecuted instantiation: ??$analyse@VRSSI@datatype@herald@@$0BJ@V123@$0BJ@U?$AnalysisRunner@U?$AnalysisDelegateManager@UDummyDistanceDelegate@@U?$LoggingAnalysisDelegate@U?$Context@UDefaultPlatformType@herald@@UDummyLoggingSink@@VDummyBluetoothStateManager@@@herald@@UDistance@datatype@2@@analysis@herald@@@analysis@herald@@U?$AnalysisProviderManager@UFowlerBasicAnalyser@distance@algorithms@analysis@herald@@@23@VRSSI@datatype@3@UDistance@63@@analysis@3@@FowlerBasicAnalyser@distance@algorithms@analysis@herald@@QEAA_NVDate@datatype@4@_KAEAU?$SampleList@U?$Sample@VRSSI@datatype@herald@@@sampling@analysis@herald@@$0BJ@VRSSI@datatype@4@@sampling@34@2AEAU?$AnalysisRunner@U?$AnalysisDelegateManager@UDummyDistanceDelegate@@U?$LoggingAnalysisDelegate@U?$Context@UDefaultPlatformType@herald@@UDummyLoggingSink@@VDummyBluetoothStateManager@@@herald@@UDistance@datatype@2@@analysis@herald@@@analysis@herald@@U?$AnalysisProviderManager@UFowlerBasicAnalyser@distance@algorithms@analysis@herald@@@23@VRSSI@datatype@3@UDistance@63@@34@@Z
76
77
  // Specialisation
78
  template <std::size_t SrcSz,std::size_t DstSz, typename CallableForNewSample>
79
17
  bool analyse(Date timeNow, SampledID sampled, SampleList<Sample<RSSI>,SrcSz>& src, SampleList<Sample<Distance>,DstSz>& dst, CallableForNewSample& callable) {
80
17
    if (lastRan + interval >= timeNow) 
return false8
; // interval guard
81
9
    // std::cout << "RUNNING FOWLER BASIC ANALYSIS at " << timeNow.secondsSinceUnixEpoch() << std::endl;
82
9
83
9
    herald::analysis::views::in_range valid(-99,-10);
84
9
85
9
    // Check that there has been any new data since the last run
86
9
    herald::analysis::views::since sinceLastRun(lastRan);
87
9
    auto newData = src
88
9
                 | herald::analysis::views::filter(valid) 
89
9
                 | herald::analysis::views::filter(sinceLastRun)
90
9
                 | herald::analysis::views::to_view();
91
9
    // if (newData.ended()) { // Doesn't work because the filter's are not applied until a data item is fetched
92
9
    //   lastRan = timeNow;
93
9
    //   return false;
94
9
    // }
95
9
96
9
    basic.reset();
97
9
98
9
    auto values = src 
99
9
                | herald::analysis::views::filter(valid) 
100
9
                | herald::analysis::views::filter(sinceLastRun)
101
9
                | herald::analysis::views::to_view();
102
9
103
9
    auto summary = newData
104
9
                 | summarise<Count,Mode,Variance>();
105
9
106
9
    auto count = summary.template get<Count>();
107
9
    if (0.0 == count) {
108
1
      // No actual new data after filtering has been applied
109
1
      lastRan = timeNow;
110
1
      return false;
111
1
    }
112
8
    auto mode = summary.template get<Mode>();
113
8
    auto var = summary.template get<Variance>();
114
8
    auto sd = std::sqrt(var);
115
8
116
8
    auto distance = src 
117
8
                  | herald::analysis::views::filter(valid) 
118
8
                  | herald::analysis::views::filter(
119
8
                      herald::analysis::views::in_range(
120
8
                        mode - 2*sd, // NOTE: WE USE THE MODE FOR FILTER, BUT SD FOR BOUNDS - See website for the reasoning
121
8
                        mode + 2*sd
122
8
                      )
123
8
                    )
124
8
                  | aggregate(basic); // type actually <herald::analysis::algorithms::distance::FowlerBasic>
125
8
    
126
8
    auto agg = distance.template get<FowlerBasic>();
127
8
    auto d = agg.reduce();
128
8
129
8
130
8
    Date latestTime = values.latest();
131
8
    lastRan = latestTime; // TODO move this logic to the caller not the analysis provider
132
8
    // std::cout << "Latest value at time: " << latestTime.secondsSinceUnixEpoch() << std::endl;
133
8
134
8
    Sample<Distance> newSample((Date)latestTime,Distance(d));
135
8
    dst.push(newSample);
136
8
    callable(sampled,newSample);
137
8
    return true;
138
8
  }
??$analyse@$0BJ@$0BJ@U?$AnalysisRunner@U?$AnalysisDelegateManager@UDummyDistanceDelegate@@@analysis@herald@@U?$AnalysisProviderManager@UFowlerBasicAnalyser@distance@algorithms@analysis@herald@@@23@VRSSI@datatype@3@UDistance@63@@analysis@herald@@@FowlerBasicAnalyser@distance@algorithms@analysis@herald@@QEAA_NVDate@datatype@4@_KAEAU?$SampleList@U?$Sample@VRSSI@datatype@herald@@@sampling@analysis@herald@@$0BJ@VRSSI@datatype@4@@sampling@34@AEAU?$SampleList@U?$Sample@UDistance@datatype@herald@@@sampling@analysis@herald@@$0BJ@UDistance@datatype@4@@834@AEAU?$AnalysisRunner@U?$AnalysisDelegateManager@UDummyDistanceDelegate@@@analysis@herald@@U?$AnalysisProviderManager@UFowlerBasicAnalyser@distance@algorithms@analysis@herald@@@23@VRSSI@datatype@3@UDistance@63@@34@@Z
Line
Count
Source
79
15
  bool analyse(Date timeNow, SampledID sampled, SampleList<Sample<RSSI>,SrcSz>& src, SampleList<Sample<Distance>,DstSz>& dst, CallableForNewSample& callable) {
80
15
    if (lastRan + interval >= timeNow) 
return false7
; // interval guard
81
8
    // std::cout << "RUNNING FOWLER BASIC ANALYSIS at " << timeNow.secondsSinceUnixEpoch() << std::endl;
82
8
83
8
    herald::analysis::views::in_range valid(-99,-10);
84
8
85
8
    // Check that there has been any new data since the last run
86
8
    herald::analysis::views::since sinceLastRun(lastRan);
87
8
    auto newData = src
88
8
                 | herald::analysis::views::filter(valid) 
89
8
                 | herald::analysis::views::filter(sinceLastRun)
90
8
                 | herald::analysis::views::to_view();
91
8
    // if (newData.ended()) { // Doesn't work because the filter's are not applied until a data item is fetched
92
8
    //   lastRan = timeNow;
93
8
    //   return false;
94
8
    // }
95
8
96
8
    basic.reset();
97
8
98
8
    auto values = src 
99
8
                | herald::analysis::views::filter(valid) 
100
8
                | herald::analysis::views::filter(sinceLastRun)
101
8
                | herald::analysis::views::to_view();
102
8
103
8
    auto summary = newData
104
8
                 | summarise<Count,Mode,Variance>();
105
8
106
8
    auto count = summary.template get<Count>();
107
8
    if (0.0 == count) {
108
1
      // No actual new data after filtering has been applied
109
1
      lastRan = timeNow;
110
1
      return false;
111
1
    }
112
7
    auto mode = summary.template get<Mode>();
113
7
    auto var = summary.template get<Variance>();
114
7
    auto sd = std::sqrt(var);
115
7
116
7
    auto distance = src 
117
7
                  | herald::analysis::views::filter(valid) 
118
7
                  | herald::analysis::views::filter(
119
7
                      herald::analysis::views::in_range(
120
7
                        mode - 2*sd, // NOTE: WE USE THE MODE FOR FILTER, BUT SD FOR BOUNDS - See website for the reasoning
121
7
                        mode + 2*sd
122
7
                      )
123
7
                    )
124
7
                  | aggregate(basic); // type actually <herald::analysis::algorithms::distance::FowlerBasic>
125
7
    
126
7
    auto agg = distance.template get<FowlerBasic>();
127
7
    auto d = agg.reduce();
128
7
129
7
130
7
    Date latestTime = values.latest();
131
7
    lastRan = latestTime; // TODO move this logic to the caller not the analysis provider
132
7
    // std::cout << "Latest value at time: " << latestTime.secondsSinceUnixEpoch() << std::endl;
133
7
134
7
    Sample<Distance> newSample((Date)latestTime,Distance(d));
135
7
    dst.push(newSample);
136
7
    callable(sampled,newSample);
137
7
    return true;
138
7
  }
??$analyse@$0BJ@$0BJ@U?$AnalysisRunner@U?$AnalysisDelegateManager@UDummyDistanceDelegate@@U?$LoggingAnalysisDelegate@U?$Context@UDefaultPlatformType@herald@@UDummyLoggingSink@@VDummyBluetoothStateManager@@@herald@@UDistance@datatype@2@@analysis@herald@@@analysis@herald@@U?$AnalysisProviderManager@UFowlerBasicAnalyser@distance@algorithms@analysis@herald@@@23@VRSSI@datatype@3@UDistance@63@@analysis@herald@@@FowlerBasicAnalyser@distance@algorithms@analysis@herald@@QEAA_NVDate@datatype@4@_KAEAU?$SampleList@U?$Sample@VRSSI@datatype@herald@@@sampling@analysis@herald@@$0BJ@VRSSI@datatype@4@@sampling@34@AEAU?$SampleList@U?$Sample@UDistance@datatype@herald@@@sampling@analysis@herald@@$0BJ@UDistance@datatype@4@@834@AEAU?$AnalysisRunner@U?$AnalysisDelegateManager@UDummyDistanceDelegate@@U?$LoggingAnalysisDelegate@U?$Context@UDefaultPlatformType@herald@@UDummyLoggingSink@@VDummyBluetoothStateManager@@@herald@@UDistance@datatype@2@@analysis@herald@@@analysis@herald@@U?$AnalysisProviderManager@UFowlerBasicAnalyser@distance@algorithms@analysis@herald@@@23@VRSSI@datatype@3@UDistance@63@@34@@Z
Line
Count
Source
79
2
  bool analyse(Date timeNow, SampledID sampled, SampleList<Sample<RSSI>,SrcSz>& src, SampleList<Sample<Distance>,DstSz>& dst, CallableForNewSample& callable) {
80
2
    if (lastRan + interval >= timeNow) 
return false1
; // interval guard
81
1
    // std::cout << "RUNNING FOWLER BASIC ANALYSIS at " << timeNow.secondsSinceUnixEpoch() << std::endl;
82
1
83
1
    herald::analysis::views::in_range valid(-99,-10);
84
1
85
1
    // Check that there has been any new data since the last run
86
1
    herald::analysis::views::since sinceLastRun(lastRan);
87
1
    auto newData = src
88
1
                 | herald::analysis::views::filter(valid) 
89
1
                 | herald::analysis::views::filter(sinceLastRun)
90
1
                 | herald::analysis::views::to_view();
91
1
    // if (newData.ended()) { // Doesn't work because the filter's are not applied until a data item is fetched
92
1
    //   lastRan = timeNow;
93
1
    //   return false;
94
1
    // }
95
1
96
1
    basic.reset();
97
1
98
1
    auto values = src 
99
1
                | herald::analysis::views::filter(valid) 
100
1
                | herald::analysis::views::filter(sinceLastRun)
101
1
                | herald::analysis::views::to_view();
102
1
103
1
    auto summary = newData
104
1
                 | summarise<Count,Mode,Variance>();
105
1
106
1
    auto count = summary.template get<Count>();
107
1
    if (0.0 == count) {
108
0
      // No actual new data after filtering has been applied
109
0
      lastRan = timeNow;
110
0
      return false;
111
0
    }
112
1
    auto mode = summary.template get<Mode>();
113
1
    auto var = summary.template get<Variance>();
114
1
    auto sd = std::sqrt(var);
115
1
116
1
    auto distance = src 
117
1
                  | herald::analysis::views::filter(valid) 
118
1
                  | herald::analysis::views::filter(
119
1
                      herald::analysis::views::in_range(
120
1
                        mode - 2*sd, // NOTE: WE USE THE MODE FOR FILTER, BUT SD FOR BOUNDS - See website for the reasoning
121
1
                        mode + 2*sd
122
1
                      )
123
1
                    )
124
1
                  | aggregate(basic); // type actually <herald::analysis::algorithms::distance::FowlerBasic>
125
1
    
126
1
    auto agg = distance.template get<FowlerBasic>();
127
1
    auto d = agg.reduce();
128
1
129
1
130
1
    Date latestTime = values.latest();
131
1
    lastRan = latestTime; // TODO move this logic to the caller not the analysis provider
132
1
    // std::cout << "Latest value at time: " << latestTime.secondsSinceUnixEpoch() << std::endl;
133
1
134
1
    Sample<Distance> newSample((Date)latestTime,Distance(d));
135
1
    dst.push(newSample);
136
1
    callable(sampled,newSample);
137
1
    return true;
138
1
  }
139
140
private:
141
  TimeInterval interval;
142
  FowlerBasic basic;
143
  Date lastRan;
144
};
145
146
}
147
}
148
}
149
}
150
151
#endif