added butterworth filter \n added activity rec for baro using butter \n added moduel for walker with activity
This commit is contained in:
@@ -1,94 +0,0 @@
|
||||
# Usage:
|
||||
# Create build folder, like RC-build next to RobotControl and WifiScan folder
|
||||
# CD into build folder and execute 'cmake -DCMAKE_BUILD_TYPE=Debug ../RobotControl'
|
||||
# make
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
|
||||
# select build type
|
||||
SET( CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" )
|
||||
|
||||
PROJECT(Indoor)
|
||||
|
||||
IF(NOT CMAKE_BUILD_TYPE)
|
||||
MESSAGE(STATUS "No build type selected. Default to Debug")
|
||||
SET(CMAKE_BUILD_TYPE "Debug")
|
||||
ENDIF()
|
||||
|
||||
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
../
|
||||
/mnt/firma/kunden/HandyGames/
|
||||
)
|
||||
|
||||
|
||||
FILE(GLOB HEADERS
|
||||
./*.h
|
||||
./*/*.h
|
||||
./*/*/*.h
|
||||
./*/*/*/*.h
|
||||
./*/*/*/*/*.h
|
||||
./*/*/*/*/*/*.h
|
||||
)
|
||||
|
||||
FILE(GLOB SOURCES
|
||||
./*.cpp
|
||||
./*/*.cpp
|
||||
./*/*/*.cpp
|
||||
./*/*/*/*.cpp
|
||||
)
|
||||
|
||||
|
||||
if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
|
||||
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_X86_ /D_USE_MATH_DEFINES")
|
||||
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi /Oi /GL /Ot /Ox /D_X86_ /D_USE_MATH_DEFINES")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /INCREMENTAL:NO")
|
||||
|
||||
set(CMAKE_CONFIGURATION_TYPES Release Debug)
|
||||
|
||||
else()
|
||||
|
||||
# system specific compiler flags
|
||||
ADD_DEFINITIONS(
|
||||
|
||||
-std=gnu++11
|
||||
|
||||
-Wall
|
||||
-Werror=return-type
|
||||
-Wextra
|
||||
-Wpedantic
|
||||
|
||||
-fstack-protector-all
|
||||
|
||||
-g3
|
||||
-O0
|
||||
-march=native
|
||||
|
||||
-DWITH_TESTS
|
||||
-DWITH_ASSERTIONS
|
||||
-DWITH_DEBUG_LOG
|
||||
|
||||
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
# build a binary file
|
||||
ADD_EXECUTABLE(
|
||||
${PROJECT_NAME}
|
||||
${HEADERS}
|
||||
${SOURCES}
|
||||
)
|
||||
|
||||
# needed external libraries
|
||||
TARGET_LINK_LIBRARIES(
|
||||
${PROJECT_NAME}
|
||||
gtest
|
||||
pthread
|
||||
)
|
||||
|
||||
SET(CMAKE_C_COMPILER ${CMAKE_CXX_COMPILER})
|
||||
|
||||
64
grid/walk/v2/modules/WalkModuleButterActivity.h
Normal file
64
grid/walk/v2/modules/WalkModuleButterActivity.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef WALKMODULEBUTTERACTIVITY_H
|
||||
#define WALKMODULEBUTTERACTIVITY_H
|
||||
|
||||
#include "WalkModule.h"
|
||||
#include "WalkStateHeading.h"
|
||||
|
||||
#include "../../../../geo/Heading.h"
|
||||
#include "../../../../math/Distributions.h"
|
||||
#include "../../../../sensors/pressure/ActivityButterPressure.h"
|
||||
|
||||
|
||||
/** favor z-transitions */
|
||||
template <typename Node, typename WalkState> class WalkModuleButterActivity : public WalkModule<Node, WalkState> {
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
WalkModuleButterActivity() {
|
||||
;
|
||||
}
|
||||
|
||||
virtual void updateBefore(WalkState& state) override {
|
||||
(void) state;
|
||||
}
|
||||
|
||||
virtual void updateAfter(WalkState& state, const Node& startNode, const Node& endNode) override {
|
||||
(void) state;
|
||||
(void) startNode;
|
||||
(void) endNode;
|
||||
|
||||
}
|
||||
|
||||
virtual void step(WalkState& state, const Node& curNode, const Node& nextNode) override {
|
||||
(void) state;
|
||||
(void) curNode;
|
||||
(void) nextNode;
|
||||
}
|
||||
|
||||
double getProbability(const WalkState& state, const Node& startNode, const Node& curNode, const Node& potentialNode) const override {
|
||||
|
||||
(void) state;
|
||||
(void) startNode;
|
||||
|
||||
const int deltaZ_cm = curNode.z_cm - potentialNode.z_cm;
|
||||
|
||||
if(state.act == ActivityButterPressure::Activity::DOWN){
|
||||
if (deltaZ_cm < 0) {return 0;}
|
||||
if (deltaZ_cm == 0) {return 0.1;}
|
||||
return 0.9;
|
||||
} else if (state.act == ActivityButterPressure::Activity::UP){
|
||||
if (deltaZ_cm > 0) {return 0;}
|
||||
if (deltaZ_cm == 0) {return 0.1;}
|
||||
return 0.9;
|
||||
} else {
|
||||
if (deltaZ_cm == 0) {return 0.9;}
|
||||
return 0.1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // WALKMODULEBUTTERACTIVITY_H
|
||||
4
main.cpp
4
main.cpp
@@ -17,9 +17,9 @@ int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
// skip all tests starting with LIVE_
|
||||
::testing::GTEST_FLAG(filter) = "-*.LIVE_*";
|
||||
::testing::GTEST_FLAG(filter) = "*Barometer*";
|
||||
|
||||
::testing::GTEST_FLAG(filter) = "*GridWalk2HeadingControl*";
|
||||
::testing::GTEST_FLAG(filter) = "*Activity*";
|
||||
|
||||
//::testing::GTEST_FLAG(filter) = "*Grid.*";
|
||||
//::testing::GTEST_FLAG(filter) = "*Dijkstra.*";
|
||||
|
||||
312
math/filter/Butterworth.h
Normal file
312
math/filter/Butterworth.h
Normal file
@@ -0,0 +1,312 @@
|
||||
#ifndef BUTTERWORTHLP_H
|
||||
#define BUTTERWORTHLP_H
|
||||
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
#include <complex>
|
||||
|
||||
namespace Filter {
|
||||
|
||||
/** butterworth lowpass filter*/
|
||||
template <typename Scalar> class ButterworthLP {
|
||||
|
||||
private:
|
||||
|
||||
/** Cascaded second-order sections */
|
||||
class SOS{
|
||||
|
||||
public:
|
||||
|
||||
SOS(const Scalar b0, const Scalar b1, const Scalar b2, const Scalar a1, const Scalar a2, const Scalar gain) :
|
||||
_b0(b0), _b1(b1), _b2(b2), _a1(a1), _a2(a2), _gain(gain), _z1(0), _z2(0),
|
||||
_preCompStateSpaceOutputVec1(_b1 - _b0*_a1),
|
||||
_preCompStateSpaceOutputVec2(_b2 - _b0*_a2){
|
||||
|
||||
}
|
||||
|
||||
void safeRestoreState(Scalar &z1, Scalar &z2, const bool restore){
|
||||
|
||||
if (restore)
|
||||
{
|
||||
_z1 = z1;
|
||||
_z2 = z2;
|
||||
}
|
||||
else
|
||||
{
|
||||
z1 = _z1;
|
||||
z2 = _z2;
|
||||
}
|
||||
}
|
||||
|
||||
void stepInitialization(const Scalar value){
|
||||
|
||||
// Set second-order section state to steady state w.r.t. given step response value
|
||||
// http://www.emt.tugraz.at/publications/diplomarbeiten/da_hoebenreich/node21.html
|
||||
_z1 = _z2 = value / (1.0 + _a1 + _a2);
|
||||
}
|
||||
|
||||
Scalar process(const Scalar input){
|
||||
|
||||
/**
|
||||
SOS state space model
|
||||
z' = A * z + b * x
|
||||
y = c^T * z + d * x
|
||||
with A = [-a1 -a2; 1 0] b = [1; 0] c = [b1 - b0*a1; b2 - b0*a2] d = [b0]
|
||||
*/
|
||||
|
||||
Scalar x = input;
|
||||
Scalar y = x;
|
||||
Scalar z1_new, z2_new;
|
||||
|
||||
z1_new = -_a1 * _z1 - _a2 * _z2 + x;
|
||||
z2_new = _z1;
|
||||
y = _preCompStateSpaceOutputVec1 * _z1 + _preCompStateSpaceOutputVec2 * _z2 + _b0 * x;
|
||||
_z1 = z1_new;
|
||||
_z2 = z2_new;
|
||||
|
||||
// Include SOS gain factor
|
||||
y *= _gain;
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
~SOS()
|
||||
{ }
|
||||
|
||||
private:
|
||||
|
||||
const Scalar _b0, _b1, _b2, _a1, _a2, _gain;
|
||||
|
||||
const Scalar _preCompStateSpaceOutputVec1, _preCompStateSpaceOutputVec2;
|
||||
|
||||
Scalar _z1, _z2;
|
||||
|
||||
};
|
||||
|
||||
|
||||
size_t _numSOS;
|
||||
std::vector<SOS> _sosVec;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
Generates a Butterworth lowpass filter with a given normalized cutoff frequency and filter order.
|
||||
@param normalizedCutoffFrequency (0, 1) Normalized cutoff frequency := cuttoffFreq / samplingFreq.
|
||||
@param filterOrder [1, inf] Butterworth filter order.
|
||||
*/
|
||||
ButterworthLP(const Scalar normalizedCutoffFrequency, const size_t filterOrder) :
|
||||
_numSOS(0)
|
||||
{
|
||||
if (!coefficients(normalizedCutoffFrequency, filterOrder))
|
||||
{
|
||||
throw std::domain_error(std::string("Failed to design a filter due to invalid parameters (normalized cutoff frequency and / or filter order) or instability of the resulting digitalized filter."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Generates a Butterworth lowpass filter of a given order with a given cutoff frequency [Hz] in respect of the data sampling frequency [Hz].
|
||||
@param samplingFrequency [1, inf] [Hz] Sampling frequency of the data.
|
||||
@param cutoffFrequency [1, samplingFrequency - 1] [Hz] Cutoff frequency
|
||||
@param filterOrder [1, inf] Butterworth filter order.
|
||||
*/
|
||||
ButterworthLP(const Scalar samplingFrequency, const Scalar cutoffFrequency, const size_t filterOrder) :
|
||||
ButterworthLP(cutoffFrequency / samplingFrequency, filterOrder)
|
||||
{ }
|
||||
|
||||
/**
|
||||
Set the filter state to a steady state w.r.t. to the given input value (assuming a constant filter input for infinite time steps in the past;
|
||||
see also http://www.emt.tugraz.at/publications/diplomarbeiten/da_hoebenreich/node21.html).
|
||||
@param value Desired steady state output value
|
||||
*/
|
||||
void stepInitialization(const Scalar value){
|
||||
Scalar stepResponseValue = value;
|
||||
|
||||
// Propagate step initialization through all second-order sections
|
||||
for (size_t i = 0; i < _numSOS; ++i)
|
||||
{
|
||||
_sosVec[i].stepInitialization(stepResponseValue);
|
||||
stepResponseValue = _sosVec[i].process(stepResponseValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Processes the input value online depending on the current filter state.
|
||||
@param input [-inf, inf] Input value
|
||||
@return [-inf, inf] Filter response
|
||||
*/
|
||||
Scalar process(const Scalar input){
|
||||
Scalar x = input;
|
||||
Scalar y = x;
|
||||
|
||||
// Cascade all second-order sections s.t. output of SOS i is input for SOS i+1
|
||||
for (size_t i = 0; i < _numSOS; ++i)
|
||||
{
|
||||
y = _sosVec[i].process(x);
|
||||
x = y;
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Processes the input data offline.
|
||||
@param *input Ptr to input data.
|
||||
@param *output Ptr to output data.
|
||||
@param size [0, inf] Length of data.
|
||||
@param initialConditionValue [-inf, inf] Initializes the filter state to a steady state w.r.t. the given initial value (see stepInitialization).
|
||||
@param forwardBackward {true, false} Eliminate phase delay by filtering twice: forward and backward.
|
||||
Note that forward-backward filtering corresponds to filtering with a 2n-th order filter.
|
||||
*/
|
||||
void filter(const Scalar *input, Scalar *output, const size_t size, const Scalar initialConditionValue, const bool forwardBackward){
|
||||
|
||||
// Save all current SOS states before offline filtering
|
||||
std::vector<Scalar> zSaved(_numSOS * 2);
|
||||
for (size_t i = 0; i < _numSOS; ++i)
|
||||
{
|
||||
_sosVec[i].safeRestoreState(zSaved[i], zSaved[i + 1], false);
|
||||
}
|
||||
|
||||
// Set initial step response conditions
|
||||
stepInitialization(initialConditionValue);
|
||||
|
||||
// Filtering on input data
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
output[i] = process(input[i]);
|
||||
}
|
||||
|
||||
// Additional backward filtering on filtered output data if requested
|
||||
if (forwardBackward)
|
||||
{
|
||||
for (size_t i = size; i > 0;)
|
||||
{
|
||||
output[--i] = process(output[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore all SOS states
|
||||
for (size_t i = 0; i < _numSOS; ++i)
|
||||
{
|
||||
_sosVec[i].safeRestoreState(zSaved[i], zSaved[i + 1], true);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool coefficients(const Scalar normalizedCutoffFrequency, const size_t filterOrder){
|
||||
|
||||
// Assure valid parameters
|
||||
if (filterOrder < 1 || normalizedCutoffFrequency <= 0 || normalizedCutoffFrequency > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::complex<Scalar>> poles(filterOrder);
|
||||
|
||||
// Prewarp the analog prototype's cutoff frequency
|
||||
Scalar omegaCutoff = 2 * tan(M_PI * normalizedCutoffFrequency);
|
||||
|
||||
Scalar gain = pow(omegaCutoff, filterOrder);
|
||||
Scalar initialGain = gain;
|
||||
|
||||
std::complex<Scalar> two(2.0, 0);
|
||||
|
||||
for (size_t i = 0, i_end = (filterOrder + 1) / 2; i < i_end; ++i){
|
||||
|
||||
size_t i2 = 2 * i;
|
||||
|
||||
/**
|
||||
Design the analog prototype Butterworth lowpass filter
|
||||
*/
|
||||
|
||||
// Generate s-poles of prototype filter
|
||||
Scalar phi = static_cast<Scalar>(i2 + 1) * M_PI / (2 * filterOrder);
|
||||
Scalar real = -sin(phi);
|
||||
Scalar imag = cos(phi);
|
||||
|
||||
std::complex<Scalar> pole = std::complex<Scalar>(real, imag);
|
||||
|
||||
/**
|
||||
Customize analog prototype filter w.r.t cutoff frequency
|
||||
*/
|
||||
|
||||
// Scale s-pole with the cutoff frequency
|
||||
pole *= omegaCutoff;
|
||||
|
||||
/**
|
||||
Digitalize the analog filter
|
||||
*/
|
||||
|
||||
// Map pole from s-plane to z-plane using bilinear transform
|
||||
std::complex<Scalar> s = pole;
|
||||
pole = (two + s) / (two - s);
|
||||
|
||||
// Update overall gain in respect of z-pole gain
|
||||
gain *= abs((two - s));
|
||||
|
||||
// Ensure z-pole lies in unit circle of z-plane
|
||||
if (abs(pole) > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add stable z-pole
|
||||
poles[i2] = pole;
|
||||
|
||||
// Odd filter order: ignore the second complex conjugate pole
|
||||
if (i2 + 1 >= filterOrder)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Do the same as above with the conjugate complex pole
|
||||
pole = std::complex<Scalar>(real, -imag);
|
||||
pole *= omegaCutoff;
|
||||
s = pole;
|
||||
pole = (two + s) / (two - s);
|
||||
gain *= abs((two - s));
|
||||
if (abs(pole) > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
poles[i2 + 1] = pole;
|
||||
}
|
||||
|
||||
// Distribute the overall gain over all z-poles
|
||||
Scalar overallGain = initialGain * (initialGain / gain);
|
||||
Scalar distributedPoleGain = pow(overallGain, 1.0 / static_cast<Scalar>(filterOrder));
|
||||
Scalar distributedPolePairGain = distributedPoleGain * distributedPoleGain;
|
||||
|
||||
/**
|
||||
Generate second-order sections from conjugate complex z-pole pairs
|
||||
*/
|
||||
|
||||
for (size_t i = 0, i_end = filterOrder - 1; i < i_end; i += 2){
|
||||
|
||||
addSOS(SOS(1.0, 2.0, 1.0, -(poles[i] + poles[i + 1]).real(), (poles[i] * poles[i + 1]).real(), distributedPolePairGain));
|
||||
}
|
||||
|
||||
// Odd filter order: remaining single z-pole requires additional second-order section
|
||||
if (filterOrder % 2 == 1){
|
||||
|
||||
addSOS(SOS(1.0, 1.0, 0.0, -poles[filterOrder - 1].real(), 0.0, distributedPoleGain));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void addSOS(const SOS sos){
|
||||
|
||||
_sosVec.push_back(sos);
|
||||
++_numSOS;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BUTTERWORTHLP_H
|
||||
185
sensors/pressure/ActivityButterPressure.h
Normal file
185
sensors/pressure/ActivityButterPressure.h
Normal file
@@ -0,0 +1,185 @@
|
||||
#ifndef ACTIVITYBUTTERPRESSURE_H
|
||||
#define ACTIVITYBUTTERPRESSURE_H
|
||||
|
||||
#include "../../data/Timestamp.h"
|
||||
#include "../../math/filter/Butterworth.h"
|
||||
#include "../../math/FixedFrequencyInterpolator.h"
|
||||
#include "../../math/MovingAVG.h"
|
||||
|
||||
#include "BarometerData.h"
|
||||
|
||||
/**
|
||||
* receives pressure measurements, interpolates them to a ficex frequency, lowpass filtering
|
||||
* activity recognition based on a small window given by matlabs diff(window)
|
||||
*/
|
||||
class ActivityButterPressure {
|
||||
|
||||
public:
|
||||
|
||||
enum Activity {DOWN, STAY, UP};
|
||||
|
||||
|
||||
|
||||
struct History {
|
||||
Timestamp ts;
|
||||
BarometerData data;
|
||||
History(const Timestamp ts, const BarometerData data) : ts(ts), data(data) {;}
|
||||
};
|
||||
|
||||
private:
|
||||
//just for debugging and plotting
|
||||
std::vector<History> input;
|
||||
std::vector<History> inputInterp;
|
||||
std::vector<History> output;
|
||||
std::vector<float> sumHist;
|
||||
std::vector<float> mvAvgHist;
|
||||
std::vector<History> actHist;
|
||||
|
||||
Activity currentActivity;
|
||||
MovingAVG<float> mvAvg = MovingAVG<float>(20);
|
||||
|
||||
/** change this values for much success */
|
||||
const bool additionalLowpassFilter = false;
|
||||
const int diffSize = 20; //the number values used for finding the activity.
|
||||
const float threshold = 0.025; // if diffSize is getting smaller, treshold needs to be adjusted in the same direction!
|
||||
Filter::ButterworthLP<float> butter = Filter::ButterworthLP<float>(10,0.05f,2);
|
||||
Filter::ButterworthLP<float> butter2 = Filter::ButterworthLP<float>(10,0.1f,2);
|
||||
FixedFrequencyInterpolator<float> ffi = FixedFrequencyInterpolator<float>(Timestamp::fromMS(100));
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/** ctor */
|
||||
ActivityButterPressure() : currentActivity(STAY){
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
/** add new sensor readings that were received at the given timestamp */
|
||||
Activity add(const Timestamp& ts, const BarometerData& baro) {
|
||||
|
||||
//init
|
||||
static bool firstCall = false;
|
||||
if(!firstCall){
|
||||
butter.stepInitialization(baro.hPa);
|
||||
firstCall = true;
|
||||
|
||||
butter2.stepInitialization(0);
|
||||
return STAY;
|
||||
}
|
||||
|
||||
input.push_back(History(ts, baro));
|
||||
|
||||
bool newInterpolatedValues = false;
|
||||
|
||||
//interpolate & butter
|
||||
auto callback = [&] (const Timestamp ts, const float val) {
|
||||
float interpValue = val;
|
||||
inputInterp.push_back(History(ts, BarometerData(interpValue)));
|
||||
|
||||
//butter
|
||||
float butterValue = butter.process(interpValue);
|
||||
output.push_back(History(ts, BarometerData(butterValue)));
|
||||
|
||||
newInterpolatedValues = true;
|
||||
|
||||
};
|
||||
ffi.add(ts, baro.hPa, callback);
|
||||
|
||||
if(newInterpolatedValues == true){
|
||||
|
||||
//getActivity
|
||||
if(output.size() > diffSize){
|
||||
//diff
|
||||
std::vector<float> diff;
|
||||
for(int i = output.size() - diffSize; i < output.size() - 1; ++i){
|
||||
|
||||
float diffVal = output[i+1].data.hPa - output[i].data.hPa;
|
||||
|
||||
diff.push_back(diffVal);
|
||||
}
|
||||
|
||||
float sum = 0;
|
||||
for(float val : diff){
|
||||
sum += val;
|
||||
}
|
||||
|
||||
float actValue = 0;
|
||||
if(additionalLowpassFilter == true){
|
||||
//additional butter/moving average for the results
|
||||
//mvAvg.add(sum);
|
||||
//actValue = mvAvg.get();
|
||||
actValue = butter2.process(sum);
|
||||
}else{
|
||||
actValue = sum;
|
||||
}
|
||||
sumHist.push_back(actValue);
|
||||
|
||||
if(actValue > threshold){
|
||||
currentActivity = DOWN;
|
||||
}
|
||||
else if (actValue < -threshold){
|
||||
currentActivity = UP;
|
||||
}
|
||||
else{
|
||||
currentActivity = STAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actHist.push_back(History(ts, BarometerData(currentActivity)));
|
||||
|
||||
return currentActivity;
|
||||
|
||||
}
|
||||
|
||||
/** get the current Activity */
|
||||
Activity getCurrentActivity() {
|
||||
return currentActivity;
|
||||
}
|
||||
|
||||
std::vector<float> getSensorHistory(){
|
||||
std::vector<float> tmp;
|
||||
|
||||
for(History val : input){
|
||||
tmp.push_back(val.data.hPa);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
std::vector<float> getInterpolatedHistory(){
|
||||
std::vector<float> tmp;
|
||||
|
||||
for(History val : inputInterp){
|
||||
tmp.push_back(val.data.hPa);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
std::vector<float> getOutputHistory(){
|
||||
|
||||
std::vector<float> tmp;
|
||||
|
||||
for(History val : output){
|
||||
tmp.push_back(val.data.hPa);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
std::vector<float> getSumHistory(){
|
||||
return sumHist;
|
||||
}
|
||||
|
||||
|
||||
std::vector<History> getActHistory(){
|
||||
|
||||
return actHist;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // ACTIVITYBUTTERPRESSURE_H
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
static inline std::string getDataFile(const std::string& name) {
|
||||
return "/mnt/data/workspaces/Indoor/tests/data/" + name;
|
||||
return "/home/toni/Documents/programme/localization/Indoor/tests/data/" + name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
257
tests/math/filter/TestButter.cpp
Normal file
257
tests/math/filter/TestButter.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
#ifdef WITH_TESTS
|
||||
|
||||
#include "../../Tests.h"
|
||||
#include "../../../math/filter/Butterworth.h"
|
||||
#include "../../../misc/Time.h"
|
||||
#include "../../../math/Interpolator.h"
|
||||
|
||||
#include"../../../sensors/pressure/ActivityButterPressure.h"
|
||||
|
||||
#include <KLib/misc/gnuplot/Gnuplot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlotElementPoints.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlotElementColorPoints.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlotElementLines.h>
|
||||
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
TEST(Butterworth, offlineSinus) {
|
||||
|
||||
//input data
|
||||
std::minstd_rand gen;
|
||||
std::uniform_real_distribution<double> noise (-0.1, +0.1);
|
||||
|
||||
int size = 1100; //Fs
|
||||
double* input = new double[size];
|
||||
double* output = new double[size];
|
||||
|
||||
// 17.5hz sin signal with random noise [-0.1, 0.1]
|
||||
for( int i=0; i < size; ++i ){
|
||||
input[i] = sin(0.1 * i) + noise(gen);
|
||||
}
|
||||
|
||||
//butterworth
|
||||
Filter::ButterworthLP<double> butter(size,20,5);
|
||||
butter.stepInitialization(0);
|
||||
butter.filter(input, output, size, 0, true);
|
||||
|
||||
K::Gnuplot gp;
|
||||
K::GnuplotPlot plot;
|
||||
K::GnuplotPlotElementLines linesInput;
|
||||
K::GnuplotPlotElementLines linesOutput;
|
||||
|
||||
for(int i=0; i < size-1; ++i){
|
||||
|
||||
K::GnuplotPoint2 input_p1(i, input[i]);
|
||||
K::GnuplotPoint2 input_p2(i+1, input[i+1]);
|
||||
|
||||
K::GnuplotPoint2 output_p1(i, output[i]);
|
||||
K::GnuplotPoint2 output_p2(i+1, output[i+1]);
|
||||
|
||||
linesInput.addSegment(input_p1, input_p2);
|
||||
linesOutput.addSegment(output_p1, output_p2);
|
||||
}
|
||||
linesOutput.setColorHex("#00FF00");
|
||||
|
||||
plot.add(&linesInput);
|
||||
plot.add(&linesOutput);
|
||||
|
||||
gp.draw(plot);
|
||||
gp.flush();
|
||||
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
TEST(Butterworth, onlineSinus) {
|
||||
|
||||
int size = 1100; //Fs
|
||||
double* input = new double[size];
|
||||
double* output = new double[size];
|
||||
|
||||
Filter::ButterworthLP<double> butter(size,20,5);
|
||||
butter.stepInitialization(0);
|
||||
|
||||
//input data
|
||||
std::minstd_rand gen;
|
||||
std::uniform_real_distribution<double> noise (-0.1, +0.1);
|
||||
|
||||
// 17.5hz sin signal with random noise [-0.1, 0.1]
|
||||
for( int i=0; i < size; ++i ){
|
||||
input[i] = sin(0.1 * i) + noise(gen);
|
||||
|
||||
output[i] = butter.process(input[i]);
|
||||
}
|
||||
|
||||
K::Gnuplot gp;
|
||||
K::GnuplotPlot plot;
|
||||
K::GnuplotPlotElementLines linesInput;
|
||||
K::GnuplotPlotElementLines linesOutput;
|
||||
|
||||
for(int i=0; i < size-1; ++i){
|
||||
|
||||
K::GnuplotPoint2 input_p1(i, input[i]);
|
||||
K::GnuplotPoint2 input_p2(i+1, input[i+1]);
|
||||
|
||||
K::GnuplotPoint2 output_p1(i, output[i]);
|
||||
K::GnuplotPoint2 output_p2(i+1, output[i+1]);
|
||||
|
||||
linesInput.addSegment(input_p1, input_p2);
|
||||
linesOutput.addSegment(output_p1, output_p2);
|
||||
}
|
||||
linesOutput.setColorHex("#00FF00");
|
||||
|
||||
plot.add(&linesInput);
|
||||
plot.add(&linesOutput);
|
||||
|
||||
gp.draw(plot);
|
||||
gp.flush();
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
TEST(Butterworth, offlineOctaveBaro) {
|
||||
|
||||
|
||||
double* input = new double[100000];
|
||||
double* output = new double[100000];
|
||||
|
||||
Interpolator<int, double> interp;
|
||||
|
||||
//read file
|
||||
std::string line;
|
||||
std::string filename = getDataFile("baro/logfile_UAH_R1_S4_baro.dat");
|
||||
std::ifstream infile(filename);
|
||||
|
||||
int counter = 0;
|
||||
while (std::getline(infile, line))
|
||||
{
|
||||
std::istringstream iss(line);
|
||||
int ts;
|
||||
double value;
|
||||
|
||||
while (iss >> ts >> value) {
|
||||
|
||||
interp.add(ts, value);
|
||||
|
||||
while(interp.getMaxKey() > counter*20 ){
|
||||
double interpValue = interp.get(counter*20);
|
||||
|
||||
input[counter] = interpValue;
|
||||
//std::cout << counter*20 << " " << interpValue << " i" << std::endl;
|
||||
++counter;
|
||||
}
|
||||
|
||||
//std::cout << ts << " " << value << " r" << std::endl;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Filter::ButterworthLP<double> butter(50,0.2,2);
|
||||
butter.filter(input, output, counter, 938.15, true);
|
||||
|
||||
K::Gnuplot gp;
|
||||
K::GnuplotPlot plot;
|
||||
K::GnuplotPlotElementLines linesInput;
|
||||
K::GnuplotPlotElementLines linesOutput;
|
||||
|
||||
for(int i=0; i < counter-1; ++i){
|
||||
|
||||
K::GnuplotPoint2 input_p1(i, input[i]);
|
||||
K::GnuplotPoint2 input_p2(i+1, input[i+1]);
|
||||
|
||||
K::GnuplotPoint2 output_p1(i, output[i]);
|
||||
K::GnuplotPoint2 output_p2(i+1, output[i+1]);
|
||||
|
||||
linesInput.addSegment(input_p1, input_p2);
|
||||
linesOutput.addSegment(output_p1, output_p2);
|
||||
}
|
||||
linesOutput.setColorHex("#00FF00");
|
||||
|
||||
plot.add(&linesInput);
|
||||
plot.add(&linesOutput);
|
||||
|
||||
gp.draw(plot);
|
||||
gp.flush();
|
||||
|
||||
sleep(1);
|
||||
|
||||
}
|
||||
|
||||
TEST(Butterworth, onlineOctaveBaro) {
|
||||
|
||||
std::vector<double> input;
|
||||
std::vector<double> output;
|
||||
|
||||
Interpolator<int, double> interp;
|
||||
|
||||
Filter::ButterworthLP<double> butter(50,0.02,2);
|
||||
butter.stepInitialization(938.15);
|
||||
|
||||
//read file
|
||||
std::string line;
|
||||
std::string filename = getDataFile("baro/logfile_UAH_R1_S4_baro.dat");
|
||||
std::ifstream infile(filename);
|
||||
|
||||
int counter = 1;
|
||||
while (std::getline(infile, line))
|
||||
{
|
||||
std::istringstream iss(line);
|
||||
int ts;
|
||||
double value;
|
||||
|
||||
while (iss >> ts >> value) {
|
||||
|
||||
interp.add(ts, value);
|
||||
|
||||
while(interp.getMaxKey() > counter*20 ){
|
||||
double interpValue = interp.get(counter*20);
|
||||
|
||||
//std::cout << counter*20 << " " << interpValue << " i" << std::endl;
|
||||
|
||||
input.push_back(interpValue);
|
||||
|
||||
output.push_back(butter.process(interpValue));
|
||||
|
||||
++counter;
|
||||
}
|
||||
|
||||
//std::cout << ts << " " << value << " r" << std::endl;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
K::Gnuplot gp;
|
||||
K::GnuplotPlot plot;
|
||||
K::GnuplotPlotElementLines linesInput;
|
||||
K::GnuplotPlotElementLines linesOutput;
|
||||
|
||||
for(int i=0; i < input.size()-1; ++i){
|
||||
|
||||
K::GnuplotPoint2 input_p1(i, input[i]);
|
||||
K::GnuplotPoint2 input_p2(i+1, input[i+1]);
|
||||
|
||||
K::GnuplotPoint2 output_p1(i, output[i]);
|
||||
K::GnuplotPoint2 output_p2(i+1, output[i+1]);
|
||||
|
||||
linesInput.addSegment(input_p1, input_p2);
|
||||
linesOutput.addSegment(output_p1, output_p2);
|
||||
}
|
||||
linesOutput.setColorHex("#00FF00");
|
||||
|
||||
plot.add(&linesInput);
|
||||
plot.add(&linesOutput);
|
||||
|
||||
gp.draw(plot);
|
||||
gp.flush();
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "../../../sensors/pressure/RelativePressure.h"
|
||||
#include "../../../sensors/pressure/PressureTendence.h"
|
||||
#include "../../../sensors/pressure/ActivityButterPressure.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
@@ -121,5 +122,51 @@ TEST(Barometer, LIVE_tendence2) {
|
||||
|
||||
}
|
||||
|
||||
TEST(Barometer, Activity) {
|
||||
ActivityButterPressure act;
|
||||
|
||||
//read file
|
||||
std::string line;
|
||||
std::string filename = getDataFile("baro/logfile_UAH_R2_S3_baro.dat");
|
||||
std::ifstream infile(filename);
|
||||
|
||||
while (std::getline(infile, line))
|
||||
{
|
||||
std::istringstream iss(line);
|
||||
int ts;
|
||||
double value;
|
||||
|
||||
while (iss >> ts >> value) {
|
||||
ActivityButterPressure::Activity currentAct = act.add(Timestamp::fromMS(ts), BarometerData(value));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> sum = act.getSumHistory();
|
||||
std::vector<float> interpolated = act.getInterpolatedHistory();
|
||||
std::vector<float> raw = act.getSensorHistory();
|
||||
std::vector<float> butter = act.getOutputHistory();
|
||||
std::vector<ActivityButterPressure::History> actHist = act.getActHistory();
|
||||
|
||||
K::Gnuplot gp;
|
||||
K::GnuplotPlot plot;
|
||||
K::GnuplotPlotElementLines rawLines;
|
||||
|
||||
for(int i=0; i < actHist.size()-1; ++i){
|
||||
|
||||
K::GnuplotPoint2 input_p1(actHist[i].ts.sec(), actHist[i].data.hPa);
|
||||
K::GnuplotPoint2 input_p2(actHist[i+1].ts.sec(), actHist[i+1].data.hPa);
|
||||
|
||||
rawLines.addSegment(input_p1, input_p2);
|
||||
}
|
||||
|
||||
plot.add(&rawLines);
|
||||
|
||||
gp.draw(plot);
|
||||
gp.flush();
|
||||
|
||||
sleep(1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user