mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 11:45:36 +02:00
Merge pull request #2981 from wangyix/master
added MovingPercentile for filtering bad clockskew values for Node
This commit is contained in:
commit
7f3630a990
9 changed files with 354 additions and 4 deletions
|
@ -57,7 +57,8 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket,
|
|||
_linkedData(NULL),
|
||||
_isAlive(true),
|
||||
_clockSkewUsec(0),
|
||||
_mutex()
|
||||
_mutex(),
|
||||
_clockSkewMovingPercentile(30, 0.8f) // moving 80th percentile of 30 samples
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -133,6 +134,11 @@ float Node::getAverageKilobitsPerSecond() {
|
|||
}
|
||||
}
|
||||
|
||||
void Node::updateClockSkewUsec(int clockSkewSample) {
|
||||
_clockSkewMovingPercentile.updatePercentile((float)clockSkewSample);
|
||||
_clockSkewUsec = (int)_clockSkewMovingPercentile.getValueAtPercentile();
|
||||
}
|
||||
|
||||
QDataStream& operator<<(QDataStream& out, const Node& node) {
|
||||
out << node._type;
|
||||
out << node._uuid;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "HifiSockAddr.h"
|
||||
#include "NodeData.h"
|
||||
#include "SimpleMovingAverage.h"
|
||||
#include "MovingPercentile.h"
|
||||
|
||||
typedef quint8 NodeType_t;
|
||||
|
||||
|
@ -94,7 +95,7 @@ public:
|
|||
void setPingMs(int pingMs) { _pingMs = pingMs; }
|
||||
|
||||
int getClockSkewUsec() const { return _clockSkewUsec; }
|
||||
void setClockSkewUsec(int clockSkew) { _clockSkewUsec = clockSkew; }
|
||||
void updateClockSkewUsec(int clockSkewSample);
|
||||
QMutex& getMutex() { return _mutex; }
|
||||
|
||||
friend QDataStream& operator<<(QDataStream& out, const Node& node);
|
||||
|
@ -120,6 +121,7 @@ private:
|
|||
int _pingMs;
|
||||
int _clockSkewUsec;
|
||||
QMutex _mutex;
|
||||
MovingPercentile _clockSkewMovingPercentile;
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, const Node &message);
|
||||
|
|
|
@ -96,8 +96,8 @@ void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer&
|
|||
int clockSkew = othersReplyTime - othersExprectedReply;
|
||||
|
||||
sendingNode->setPingMs(pingTime / 1000);
|
||||
sendingNode->setClockSkewUsec(clockSkew);
|
||||
|
||||
sendingNode->updateClockSkewUsec(clockSkew);
|
||||
|
||||
const bool wantDebug = false;
|
||||
|
||||
if (wantDebug) {
|
||||
|
|
61
libraries/shared/src/MovingPercentile.cpp
Normal file
61
libraries/shared/src/MovingPercentile.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// MovingPercentile.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Yixin Wang on 6/4/2014
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "MovingPercentile.h"
|
||||
|
||||
MovingPercentile::MovingPercentile(int numSamples, float percentile)
|
||||
: _numSamples(numSamples),
|
||||
_percentile(percentile),
|
||||
_samplesSorted(),
|
||||
_sampleIds(),
|
||||
_newSampleId(0),
|
||||
_indexOfPercentile(0),
|
||||
_valueAtPercentile(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
void MovingPercentile::updatePercentile(float sample) {
|
||||
|
||||
// insert the new sample into _samplesSorted
|
||||
int newSampleIndex;
|
||||
if (_samplesSorted.size() < _numSamples) {
|
||||
// if not all samples have been filled yet, simply append it
|
||||
newSampleIndex = _samplesSorted.size();
|
||||
_samplesSorted.append(sample);
|
||||
_sampleIds.append(_newSampleId);
|
||||
|
||||
// update _indexOfPercentile
|
||||
float index = _percentile * (float)(_samplesSorted.size() - 1);
|
||||
_indexOfPercentile = (int)(index + 0.5f); // round to int
|
||||
} else {
|
||||
// find index of sample with id = _newSampleId and replace it with new sample
|
||||
newSampleIndex = _sampleIds.indexOf(_newSampleId);
|
||||
_samplesSorted[newSampleIndex] = sample;
|
||||
}
|
||||
|
||||
// increment _newSampleId. cycles from 0 thru N-1
|
||||
_newSampleId = (_newSampleId == _numSamples - 1) ? 0 : _newSampleId + 1;
|
||||
|
||||
// swap new sample with neighbors in _samplesSorted until it's in sorted order
|
||||
// try swapping up first, then down. element will only be swapped one direction.
|
||||
while (newSampleIndex < _samplesSorted.size() - 1 && sample > _samplesSorted[newSampleIndex + 1]) {
|
||||
_samplesSorted.swap(newSampleIndex, newSampleIndex + 1);
|
||||
_sampleIds.swap(newSampleIndex, newSampleIndex + 1);
|
||||
newSampleIndex++;
|
||||
}
|
||||
while (newSampleIndex > 0 && sample < _samplesSorted[newSampleIndex - 1]) {
|
||||
_samplesSorted.swap(newSampleIndex, newSampleIndex - 1);
|
||||
_sampleIds.swap(newSampleIndex, newSampleIndex - 1);
|
||||
newSampleIndex--;
|
||||
}
|
||||
|
||||
// find new value at percentile
|
||||
_valueAtPercentile = _samplesSorted[_indexOfPercentile];
|
||||
}
|
36
libraries/shared/src/MovingPercentile.h
Normal file
36
libraries/shared/src/MovingPercentile.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// MovingPercentile.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Yixin Wang on 6/4/2014
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_MovingPercentile_h
|
||||
#define hifi_MovingPercentile_h
|
||||
|
||||
#include <qlist.h>
|
||||
|
||||
class MovingPercentile {
|
||||
|
||||
public:
|
||||
MovingPercentile(int numSamples, float percentile = 0.5f);
|
||||
|
||||
void updatePercentile(float sample);
|
||||
float getValueAtPercentile() const { return _valueAtPercentile; }
|
||||
|
||||
private:
|
||||
const int _numSamples;
|
||||
const float _percentile;
|
||||
|
||||
QList<float> _samplesSorted;
|
||||
QList<int> _sampleIds; // incrementally assigned, is cyclic
|
||||
int _newSampleId;
|
||||
|
||||
int _indexOfPercentile;
|
||||
float _valueAtPercentile;
|
||||
};
|
||||
|
||||
#endif
|
38
tests/shared/CMakeLists.txt
Normal file
38
tests/shared/CMakeLists.txt
Normal file
|
@ -0,0 +1,38 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
if (WIN32)
|
||||
cmake_policy (SET CMP0020 NEW)
|
||||
endif (WIN32)
|
||||
|
||||
set(TARGET_NAME shared-tests)
|
||||
|
||||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||
|
||||
#find_package(Qt5Network REQUIRED)
|
||||
#find_package(Qt5Script REQUIRED)
|
||||
#find_package(Qt5Widgets REQUIRED)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
|
||||
include(${MACRO_DIR}/AutoMTC.cmake)
|
||||
auto_mtc(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
#qt5_use_modules(${TARGET_NAME} Network Script Widgets)
|
||||
|
||||
#include glm
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
# link in the shared libraries
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
IF (WIN32)
|
||||
#target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
|
||||
ENDIF(WIN32)
|
||||
|
169
tests/shared/src/MovingPercentileTests.cpp
Normal file
169
tests/shared/src/MovingPercentileTests.cpp
Normal file
|
@ -0,0 +1,169 @@
|
|||
//
|
||||
// MovingPercentileTests.cpp
|
||||
// tests/shared/src
|
||||
//
|
||||
// Created by Yixin Wang on 6/4/2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "MovingPercentileTests.h"
|
||||
|
||||
#include "SharedUtil.h"
|
||||
#include "MovingPercentile.h"
|
||||
|
||||
#include <qqueue.h>
|
||||
|
||||
float MovingPercentileTests::random() {
|
||||
return rand() / (float)RAND_MAX;
|
||||
}
|
||||
|
||||
void MovingPercentileTests::runAllTests() {
|
||||
|
||||
QVector<int> valuesForN;
|
||||
|
||||
valuesForN.append(1);
|
||||
valuesForN.append(2);
|
||||
valuesForN.append(3);
|
||||
valuesForN.append(4);
|
||||
valuesForN.append(5);
|
||||
valuesForN.append(10);
|
||||
valuesForN.append(100);
|
||||
|
||||
|
||||
QQueue<float> lastNSamples;
|
||||
|
||||
for (int i=0; i<valuesForN.size(); i++) {
|
||||
|
||||
int N = valuesForN.at(i);
|
||||
|
||||
qDebug() << "testing moving percentile with N =" << N << "...";
|
||||
|
||||
{
|
||||
bool fail = false;
|
||||
|
||||
qDebug() << "\t testing running min...";
|
||||
|
||||
lastNSamples.clear();
|
||||
MovingPercentile movingMin(N, 0.0f);
|
||||
|
||||
for (int s = 0; s < 3*N; s++) {
|
||||
|
||||
float sample = random();
|
||||
|
||||
lastNSamples.push_back(sample);
|
||||
if (lastNSamples.size() > N) {
|
||||
lastNSamples.pop_front();
|
||||
}
|
||||
|
||||
movingMin.updatePercentile(sample);
|
||||
|
||||
float experimentMin = movingMin.getValueAtPercentile();
|
||||
|
||||
float actualMin = lastNSamples[0];
|
||||
for (int j = 0; j < lastNSamples.size(); j++) {
|
||||
if (lastNSamples.at(j) < actualMin) {
|
||||
actualMin = lastNSamples.at(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (experimentMin != actualMin) {
|
||||
qDebug() << "\t\t FAIL at sample" << s;
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fail) {
|
||||
qDebug() << "\t\t PASS";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
bool fail = false;
|
||||
|
||||
qDebug() << "\t testing running max...";
|
||||
|
||||
lastNSamples.clear();
|
||||
MovingPercentile movingMax(N, 1.0f);
|
||||
|
||||
for (int s = 0; s < 10000; s++) {
|
||||
|
||||
float sample = random();
|
||||
|
||||
lastNSamples.push_back(sample);
|
||||
if (lastNSamples.size() > N) {
|
||||
lastNSamples.pop_front();
|
||||
}
|
||||
|
||||
movingMax.updatePercentile(sample);
|
||||
|
||||
float experimentMax = movingMax.getValueAtPercentile();
|
||||
|
||||
float actualMax = lastNSamples[0];
|
||||
for (int j = 0; j < lastNSamples.size(); j++) {
|
||||
if (lastNSamples.at(j) > actualMax) {
|
||||
actualMax = lastNSamples.at(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (experimentMax != actualMax) {
|
||||
qDebug() << "\t\t FAIL at sample" << s;
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fail) {
|
||||
qDebug() << "\t\t PASS";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
bool fail = false;
|
||||
|
||||
qDebug() << "\t testing running median...";
|
||||
|
||||
lastNSamples.clear();
|
||||
MovingPercentile movingMedian(N, 0.5f);
|
||||
|
||||
for (int s = 0; s < 10000; s++) {
|
||||
|
||||
float sample = random();
|
||||
|
||||
lastNSamples.push_back(sample);
|
||||
if (lastNSamples.size() > N) {
|
||||
lastNSamples.pop_front();
|
||||
}
|
||||
|
||||
movingMedian.updatePercentile(sample);
|
||||
|
||||
float experimentMedian = movingMedian.getValueAtPercentile();
|
||||
|
||||
int samplesLessThan = 0;
|
||||
int samplesMoreThan = 0;
|
||||
|
||||
for (int j=0; j<lastNSamples.size(); j++) {
|
||||
if (lastNSamples.at(j) < experimentMedian) {
|
||||
samplesLessThan++;
|
||||
} else if (lastNSamples.at(j) > experimentMedian) {
|
||||
samplesMoreThan++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!(samplesLessThan <= N/2 && samplesMoreThan <= N-1/2)) {
|
||||
qDebug() << "\t\t FAIL at sample" << s;
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fail) {
|
||||
qDebug() << "\t\t PASS";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
22
tests/shared/src/MovingPercentileTests.h
Normal file
22
tests/shared/src/MovingPercentileTests.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// MovingPercentileTests.h
|
||||
// tests/shared/src
|
||||
//
|
||||
// Created by Yixin Wang on 6/4/2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_MovingPercentileTests_h
|
||||
#define hifi_MovingPercentileTests_h
|
||||
|
||||
namespace MovingPercentileTests {
|
||||
|
||||
float random();
|
||||
|
||||
void runAllTests();
|
||||
}
|
||||
|
||||
#endif // hifi_MovingPercentileTests_h
|
16
tests/shared/src/main.cpp
Normal file
16
tests/shared/src/main.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// main.cpp
|
||||
// tests/physics/src
|
||||
//
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "MovingPercentileTests.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
MovingPercentileTests::runAllTests();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue