ZeroCross: algo fix and energy deviation implement
Don't use energy deviation for the moment ; only the time deviation with the fix makes things better and to be tested.
This commit is contained in:
parent
d322ec1c5e
commit
73318f3551
2 changed files with 61 additions and 33 deletions
|
@ -5,40 +5,52 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using namespace patterns;
|
||||||
|
|
||||||
/// Maximum rest of division to be a multiple of
|
/// Maximum rest of division to be a multiple of
|
||||||
#define EPS_DIVISOR 0.1
|
#define EPS_DIVISOR 0.1
|
||||||
/// Consider it is a correct pattern to avoid multiples of
|
/// Consider it is a correct pattern to avoid multiples of
|
||||||
#define CORRECT_DEVIATION 1
|
#define CORRECT_TIME_DEVIATION 1
|
||||||
|
/// max factor of deviation to consider multiple to be dropped
|
||||||
|
#define MAX_TIME_DEVIATION_FACTOR_MULTIPLE 2
|
||||||
|
//#define CORRECT_ENERGY_DEVIATION 1
|
||||||
|
|
||||||
// local functions
|
// local functions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return average and standart deviation of pattern approx. interval in values
|
* Return average and standart deviation of pattern approx. interval in values
|
||||||
*/
|
*/
|
||||||
pair<double,double> IsPattern(const vector<double> &values, double interval)
|
PatternMatch IsPattern(const vector<Pattern> &values, double interval)
|
||||||
{
|
{
|
||||||
double sum = 0, deviation = 0, current = 0;
|
double current = 0;
|
||||||
int nb = 0;
|
int nb = 0;
|
||||||
double diff = interval;
|
double diff = interval;
|
||||||
|
double sum_energy = 0, first_energy = -1;
|
||||||
|
PatternMatch match;
|
||||||
|
|
||||||
for (double v : values) {
|
for (const Pattern &v : values) {
|
||||||
if (fabs(diff - v) < fabs(diff)) {
|
if (fabs(diff - v.time) < fabs(diff)) {
|
||||||
current += v;
|
current += v.time;
|
||||||
|
sum_energy += v.energy;
|
||||||
diff = interval - current;
|
diff = interval - current;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sum += current;
|
if (first_energy == -1) first_energy = sum_energy;
|
||||||
deviation += diff * diff;
|
|
||||||
current = 0;
|
match.time += current;
|
||||||
diff = interval;
|
match.time_deviation += diff * diff;
|
||||||
|
match.energy_deviation += pow(first_energy - sum_energy, 2);
|
||||||
|
current = v.time;
|
||||||
|
sum_energy = v.energy;
|
||||||
|
diff = interval - current;
|
||||||
nb++;
|
nb++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nb < 2) return pair<double,double>(0,0);
|
if (nb < 2) return PatternMatch(); // empty pattern
|
||||||
sum /= nb;
|
match.time /= nb; // time is average
|
||||||
deviation = sqrt(deviation) / nb;
|
match.time_deviation = sqrt(match.time_deviation) / nb;
|
||||||
return pair<double,double>(sum, deviation);
|
match.energy_deviation = sqrt(match.energy_deviation) / match.time;
|
||||||
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,21 +59,21 @@ pair<double,double> IsPattern(const vector<double> &values, double interval)
|
||||||
*
|
*
|
||||||
* @return best interval pattern, standart deviation for best pattern
|
* @return best interval pattern, standart deviation for best pattern
|
||||||
*/
|
*/
|
||||||
pair<double,double> FindPattern(const vector<double> &values, double pattern_min, double pattern_max)
|
PatternMatch FindPattern(const vector<Pattern> &values, double pattern_min, double pattern_max)
|
||||||
{
|
{
|
||||||
auto best = pair<double,double>(0,0);
|
PatternMatch res, best;
|
||||||
double interval = 0;
|
double interval = 0;
|
||||||
|
|
||||||
for (double v : values) {
|
for (const Pattern &v : values) {
|
||||||
interval += v;
|
interval += v.time;
|
||||||
if (interval < pattern_min) continue;
|
if (interval < pattern_min) continue;
|
||||||
if (interval > pattern_max) break;
|
if (interval > pattern_max) break;
|
||||||
|
|
||||||
auto res = IsPattern(values, interval);
|
res = IsPattern(values, interval);
|
||||||
// cout << " " << res.first << " " << res.second << endl;
|
// cout << " " << res.time << " " << 16000/res.time << " " << res.time_deviation << " " << res.energy_deviation << endl;
|
||||||
if (res.first && (res.second < best.second || best.first == 0)) {
|
if (res.time && (res.time_deviation < best.time_deviation || best.time == 0)) {
|
||||||
if (best.first && best.second < CORRECT_DEVIATION) {
|
if (best.time && best.time_deviation < CORRECT_TIME_DEVIATION && best.time_deviation / res.time_deviation < MAX_TIME_DEVIATION_FACTOR_MULTIPLE) {
|
||||||
double div = res.first / best.first;
|
double div = res.time / best.time;
|
||||||
// it is a multiple of previous
|
// it is a multiple of previous
|
||||||
if (fabs(div - round(div)) < EPS_DIVISOR) continue;
|
if (fabs(div - round(div)) < EPS_DIVISOR) continue;
|
||||||
// cout << "... " << div - floor(div) << endl;
|
// cout << "... " << div - floor(div) << endl;
|
||||||
|
@ -70,7 +82,7 @@ pair<double,double> FindPattern(const vector<double> &values, double pattern_min
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//cerr << " -> " << best.first << " " << best.second << endl;
|
//cerr << " -> " << best.first << " " << best.second << endl;
|
||||||
if (best.second > CORRECT_DEVIATION) return pair<double,double>(0,0);
|
if (best.time_deviation > CORRECT_TIME_DEVIATION) return PatternMatch(); // empty pattern
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +100,7 @@ template<typename A> ZeroCross<A>::ZeroCross(const Config &config)
|
||||||
|
|
||||||
template<typename sample_t> void ZeroCross<sample_t>::Clear()
|
template<typename sample_t> void ZeroCross<sample_t>::Clear()
|
||||||
{
|
{
|
||||||
nb_frame_current = -1;
|
pattern_current.time = -1;
|
||||||
nb_frame_analysed = 0;
|
nb_frame_analysed = 0;
|
||||||
freq = 0;
|
freq = 0;
|
||||||
last_zero = false;
|
last_zero = false;
|
||||||
|
@ -100,18 +112,22 @@ template<typename sample_t> void ZeroCross<sample_t>::ComputeFrame(sample_t x)
|
||||||
double delta;
|
double delta;
|
||||||
|
|
||||||
// count frame only if ever crossed
|
// count frame only if ever crossed
|
||||||
if (nb_frame_current != -1) nb_frame_current++;
|
if (pattern_current.time != -1) {
|
||||||
|
pattern_current.time++;
|
||||||
|
pattern_current.energy += x * x;
|
||||||
|
}
|
||||||
// get only from negative to positive
|
// get only from negative to positive
|
||||||
if (x > 0 && last_sample < 0) {
|
if (x > 0 && last_sample < 0) {
|
||||||
if (last_zero) delta = 1;
|
if (last_zero) delta = 1;
|
||||||
else delta = (double) x / (x - last_sample);
|
else delta = (double) x / (x - last_sample);
|
||||||
|
|
||||||
if (nb_frame_current > 0) {
|
if (pattern_current.time > 0) {
|
||||||
nb_frame_current -= delta;
|
pattern_current.time -= delta;
|
||||||
pattern.push_back(nb_frame_current);
|
pattern.push_back(pattern_current);
|
||||||
//cout << nb_frame_current << " ";
|
//cout << nb_frame_current << " ";
|
||||||
}
|
}
|
||||||
nb_frame_current = delta;
|
pattern_current.time = delta;
|
||||||
|
pattern_current.energy = x * x;
|
||||||
}
|
}
|
||||||
// drop 0 values to know sign change
|
// drop 0 values to know sign change
|
||||||
if (x) last_sample = x, last_zero = false;
|
if (x) last_sample = x, last_zero = false;
|
||||||
|
@ -119,7 +135,7 @@ template<typename sample_t> void ZeroCross<sample_t>::ComputeFrame(sample_t x)
|
||||||
// compute if window suffisent
|
// compute if window suffisent
|
||||||
if (nb_frame_analysed++ == nb_frame_to_analyse) {
|
if (nb_frame_analysed++ == nb_frame_to_analyse) {
|
||||||
auto res = FindPattern(pattern, sample_min, sample_max);
|
auto res = FindPattern(pattern, sample_min, sample_max);
|
||||||
if (res.first) freq = rate / res.first;
|
if (res.time) freq = rate / res.time;
|
||||||
else freq = 0;
|
else freq = 0;
|
||||||
nb_frame_analysed = 0;
|
nb_frame_analysed = 0;
|
||||||
pattern.clear();
|
pattern.clear();
|
||||||
|
|
|
@ -4,6 +4,18 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
namespace patterns {
|
||||||
|
|
||||||
|
struct Pattern {
|
||||||
|
double time, energy;
|
||||||
|
};
|
||||||
|
struct PatternMatch {
|
||||||
|
double time, time_deviation, energy_deviation;
|
||||||
|
PatternMatch() : time(0), time_deviation(0), energy_deviation(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
template<typename sample_t> class ZeroCross {
|
template<typename sample_t> class ZeroCross {
|
||||||
public:
|
public:
|
||||||
struct Config {
|
struct Config {
|
||||||
|
@ -14,11 +26,11 @@ template<typename sample_t> class ZeroCross {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int rate, nb_frame_to_analyse, nb_frame_analysed, diff_x;
|
int rate, nb_frame_to_analyse, nb_frame_analysed, diff_x;
|
||||||
double nb_frame_current;
|
patterns::Pattern pattern_current;
|
||||||
int16_t last_sample;
|
int16_t last_sample;
|
||||||
double freq, sample_min, sample_max;
|
double freq, sample_min, sample_max;
|
||||||
bool last_zero;
|
bool last_zero;
|
||||||
std::vector<double> pattern;
|
std::vector<patterns::Pattern> pattern;
|
||||||
|
|
||||||
inline void ComputeFrame(sample_t x);
|
inline void ComputeFrame(sample_t x);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue