1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
//
// Copyright 2011-2011 Ettus Research LLC
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <osmosdr/ranges.h>
#include <stdexcept>
#include <boost/math/special_functions/round.hpp>
#include <algorithm>
#include <sstream>
using namespace osmosdr;
/***********************************************************************
* range_t implementation code
**********************************************************************/
struct range_t::impl{
impl(double start, double stop, double step):
start(start), stop(stop), step(step)
{
/* NOP */
}
double start, stop, step;
};
range_t::range_t(double value):
_impl(OSMOSDR_PIMPL_MAKE(impl, (value, value, 0)))
{
/* NOP */
}
range_t::range_t(
double start, double stop, double step
):
_impl(OSMOSDR_PIMPL_MAKE(impl, (start, stop, step)))
{
if (stop < start){
throw std::runtime_error("cannot make range where stop < start");
}
}
double range_t::start(void) const{
return _impl->start;
}
double range_t::stop(void) const{
return _impl->stop;
}
double range_t::step(void) const{
return _impl->step;
}
const std::string range_t::to_pp_string(void) const{
std::stringstream ss;
ss << "(" << this->start();
if (this->start() != this->stop()) ss << ", " << this->stop();
if (this->step() != 0) ss << ", " << this->step();
ss << ")";
return ss.str();
}
/***********************************************************************
* meta_range_t implementation code
**********************************************************************/
void check_meta_range_monotonic(const meta_range_t &mr){
if (mr.empty()){
throw std::runtime_error("meta-range cannot be empty");
}
for (size_t i = 1; i < mr.size(); i++){
if (mr.at(i).start() < mr.at(i-1).stop()){
throw std::runtime_error("meta-range is not monotonic");
}
}
}
meta_range_t::meta_range_t(void){
/* NOP */
}
meta_range_t::meta_range_t(
double start, double stop, double step
):
std::vector<range_t > (1, range_t(start, stop, step))
{
/* NOP */
}
double meta_range_t::start(void) const{
check_meta_range_monotonic(*this);
double min_start = this->front().start();
for (const range_t &r : (*this)){
min_start = std::min(min_start, r.start());
}
return min_start;
}
double meta_range_t::stop(void) const{
check_meta_range_monotonic(*this);
double max_stop = this->front().stop();
for (const range_t &r : (*this)){
max_stop = std::max(max_stop, r.stop());
}
return max_stop;
}
double meta_range_t::step(void) const{
check_meta_range_monotonic(*this);
std::vector<double> non_zero_steps;
range_t last = this->front();
for (const range_t &r : (*this)){
//steps at each range
if (r.step() > 0) non_zero_steps.push_back(r.step());
//and steps in-between ranges
double ibtw_step = r.start() - last.stop();
if (ibtw_step > 0) non_zero_steps.push_back(ibtw_step);
//store ref to last
last = r;
}
if (non_zero_steps.empty()) return 0; //all zero steps, its zero...
return *std::min_element(non_zero_steps.begin(), non_zero_steps.end());
}
double meta_range_t::clip(double value, bool clip_step) const{
check_meta_range_monotonic(*this);
double last_stop = this->front().stop();
for (const range_t &r : (*this)){
//in-between ranges, clip to nearest
if (value < r.start()){
return (std::abs(value - r.start()) < std::abs(value - last_stop))?
r.start() : last_stop;
}
//in this range, clip here
if (value <= r.stop()){
if (! clip_step || r.step() == 0) return value;
return boost::math::round((value - r.start())/r.step())*r.step() + r.start();
}
//continue on to the next range
last_stop = r.stop();
}
return last_stop;
}
std::vector<double> meta_range_t::values() const {
std::vector<double> values;
for (const range_t &r : (*this)) {
if (r.start() != r.stop()) {
if ( r.step() == 0 ) {
values.push_back( r.start() );
values.push_back( r.stop() );
} else {
for ( double val = r.start(); val <= r.stop(); val += r.step() ) {
values.push_back( val );
}
}
} else {
values.push_back( r.start() );
}
}
return values;
}
const std::string meta_range_t::to_pp_string(void) const{
std::stringstream ss;
for (const range_t &r : (*this)){
ss << r.to_pp_string() << std::endl;
}
return ss.str();
}
|