kopia lustrzana https://github.com/ogre/habdec
262 wiersze
6.0 KiB
C++
262 wiersze
6.0 KiB
C++
/*
|
|
|
|
Copyright 2018 Michal Fratczak
|
|
|
|
This file is part of habdec.
|
|
|
|
habdec is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
habdec is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with habdec. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <cmath>
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <numeric>
|
|
|
|
namespace
|
|
{
|
|
|
|
template <typename T>
|
|
inline int sgn(T val)
|
|
{
|
|
return (T(0) < val) - (val < T(0));
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
inline int _dir(T left, T right)
|
|
{
|
|
if( sgn(left) < sgn(right) )
|
|
return 1;
|
|
else if( sgn(left) > sgn(right) )
|
|
return -1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
template<typename TReal, typename TRVector>
|
|
void FlipPointAvrg(
|
|
const TRVector& v,
|
|
const size_t i,
|
|
const size_t R,
|
|
TReal& o_avg_l,
|
|
TReal& o_avg_r )
|
|
{
|
|
using namespace std; int _L = max(int(i-R), 0); // left bound
|
|
int _R = min(i+R, v.size()); // right bound
|
|
o_avg_l = std::accumulate(v.begin()+_L, v.begin()+i, TReal(0)) / (i-_L);
|
|
o_avg_r = std::accumulate(v.begin()+i, v.begin()+_R, TReal(0)) / (_R-i);
|
|
}
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace habdec
|
|
{
|
|
|
|
template<typename TReal>
|
|
class SymbolExtractor
|
|
{
|
|
|
|
public:
|
|
typedef std::vector<TReal> TRVector;
|
|
|
|
void pushSamples(const TRVector& v); //REAL samples after Freq demodulation
|
|
|
|
void samplingRate(const double sm_r) { sampling_rate_ = sm_r; }
|
|
double samplingRate() const { return sampling_rate_; }
|
|
|
|
void symbolRate(const double sb_r) { symbol_rate_ = sb_r; } // baud
|
|
double symbolRate() const { return symbol_rate_; }
|
|
|
|
std::vector<bool> get(size_t count=0);
|
|
|
|
size_t samplesPerBit() const { return size_t(round( samplingRate()/symbolRate() )); }
|
|
|
|
void operator()();
|
|
|
|
private:
|
|
double sampling_rate_ = 0;
|
|
double symbol_rate_ = 1;
|
|
TRVector samples_;
|
|
std::vector<bool> bits_;
|
|
|
|
size_t findFirstFlipPoint(const size_t start_offset);
|
|
std::vector<size_t> findFlipPoints();
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename TReal>
|
|
void SymbolExtractor<TReal>::pushSamples(const TRVector& v)
|
|
{
|
|
using namespace std;
|
|
|
|
if(!v.size())
|
|
return;
|
|
|
|
// safety vent
|
|
if(samples_.size() > 1e6)
|
|
{
|
|
cout<<"SymbolExtractor::pushSamples overflow. Delete samples."<<endl;
|
|
samples_.clear();
|
|
}
|
|
|
|
const size_t prev_size = samples_.size();
|
|
samples_.resize( samples_.size() + v.size() );
|
|
memcpy( samples_.data() + prev_size, v.data(), v.size() * sizeof(TReal) );
|
|
}
|
|
|
|
|
|
template<typename TReal>
|
|
void SymbolExtractor<TReal>::operator()()
|
|
{
|
|
if( !sampling_rate_ || !symbol_rate_ )
|
|
return;
|
|
|
|
if( samples_.size() < samplingRate()/symbolRate()*3 ) // have at least 3 symbols
|
|
return;
|
|
|
|
std::vector<size_t> flip_points = findFlipPoints();
|
|
if(!flip_points.size())
|
|
return;
|
|
|
|
size_t last_flip_point = 0;
|
|
for(const auto flip_point : flip_points)
|
|
{
|
|
TReal avg = TReal(
|
|
std::accumulate( samples_.begin()+last_flip_point,
|
|
samples_.begin()+flip_point, (TReal)0 )
|
|
) / (flip_point-last_flip_point);
|
|
|
|
bool bit_value = avg > 0;
|
|
size_t bit_count = size_t( round( float(flip_point-last_flip_point) / float(samplesPerBit()) ) );
|
|
last_flip_point = flip_point;
|
|
while(bit_count--)
|
|
bits_.push_back(bit_value);
|
|
}
|
|
|
|
size_t erase_to = std::min(last_flip_point, samples_.size());
|
|
samples_.erase( samples_.begin(), samples_.begin() + erase_to );
|
|
}
|
|
|
|
|
|
template<typename TReal>
|
|
size_t SymbolExtractor<TReal>::findFirstFlipPoint(const size_t start_offset)
|
|
{
|
|
if( (samples_.size()-start_offset) < samplesPerBit() )
|
|
return 0;
|
|
|
|
// FIND FIRST FLIP POINT
|
|
// IT NEEDS TO HAVE DIFFERENT SIGN OF AVERAGE
|
|
// ON IT'S LEFT AND RIGHT SIDE OF LENGTH R
|
|
const size_t R = std::max(4, int(samplesPerBit() / 4));
|
|
|
|
std::vector<size_t> flip_points;
|
|
|
|
// start at R
|
|
size_t flip_point = start_offset + R;
|
|
|
|
TReal avg_left;
|
|
TReal avg_right;
|
|
FlipPointAvrg(samples_, flip_point, R, avg_left, avg_right);
|
|
|
|
// SCAN UNTIL FIRST FLIP_POINT
|
|
while(sgn(avg_left) == sgn(avg_right))
|
|
{
|
|
flip_point += 1;
|
|
|
|
if(flip_point >= (samples_.size() - samplesPerBit()))
|
|
return 0;
|
|
|
|
FlipPointAvrg(samples_, flip_point, R, avg_left, avg_right);
|
|
}
|
|
|
|
size_t flip_point_left = flip_point;
|
|
// int value_change_dir = _dir(avg_left, avg_right);
|
|
|
|
// SCAN UNTIL LAST FLIP_POINT WITH CHANGING SIGN OF AVERAGE
|
|
while(sgn(avg_left) != sgn(avg_right))
|
|
{
|
|
flip_point += 1;
|
|
|
|
if(flip_point >= (samples_.size() - samplesPerBit()))
|
|
return 0;
|
|
|
|
FlipPointAvrg(samples_, flip_point, R, avg_left, avg_right);
|
|
}
|
|
|
|
size_t flip_point_right = flip_point;
|
|
|
|
// in range [flip_point_left, flip_point_right)
|
|
// find point with largest difference in average values
|
|
|
|
std::vector<size_t> flip_point_candidates;
|
|
std::vector<float> flip_point_candidates_weight;
|
|
for(size_t i=flip_point_left; i<flip_point_right; ++i)
|
|
{
|
|
FlipPointAvrg(samples_, i, R, avg_left, avg_right);
|
|
flip_point_candidates.push_back(i);
|
|
flip_point_candidates_weight.push_back( abs(avg_right-avg_left) );
|
|
}
|
|
|
|
auto p_max = max_element(flip_point_candidates_weight.begin(), flip_point_candidates_weight.end());
|
|
size_t max_index = p_max - flip_point_candidates_weight.begin();
|
|
|
|
return flip_point_candidates[max_index];
|
|
}
|
|
|
|
|
|
template<typename TReal>
|
|
std::vector<size_t> SymbolExtractor<TReal>::findFlipPoints()
|
|
{
|
|
size_t offset = 0;
|
|
size_t flip_point = findFirstFlipPoint(offset);
|
|
std::vector<size_t> all_points;
|
|
|
|
while(flip_point)
|
|
{
|
|
all_points.push_back(flip_point);
|
|
offset = flip_point;
|
|
flip_point = findFirstFlipPoint(offset);
|
|
}
|
|
return all_points;
|
|
}
|
|
|
|
|
|
template<typename TReal>
|
|
std::vector<bool> SymbolExtractor<TReal>::get(size_t count)
|
|
{
|
|
if(count == 0)
|
|
count = bits_.size();
|
|
const size_t _count = std::min(count, bits_.size());
|
|
|
|
const std::vector<bool> res( bits_.begin(), bits_.begin() + _count );
|
|
bits_.erase( bits_.begin(), bits_.begin() + _count );
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
} // namespace habdec
|
|
|
|
|