Statistics
| Branch: | Tag: | Revision:

root / host / lib / types / ranges.cpp @ 4357f5d3

History | View | Annotate | Download (4.72 KB)

1
//
2
// Copyright 2011-2011 Ettus Research LLC
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

    
18
#include <uhd/types/ranges.hpp>
19
#include <uhd/exception.hpp>
20
#include <boost/math/special_functions/round.hpp>
21
#include <boost/foreach.hpp>
22
#include <algorithm>
23
#include <sstream>
24

    
25
using namespace uhd;
26

    
27
/***********************************************************************
28
 * range_t implementation code
29
 **********************************************************************/
30
struct range_t::impl{
31
    impl(double start, double stop, double step):
32
        start(start), stop(stop), step(step)
33
    {
34
        /* NOP */
35
    }
36
    double start, stop, step;
37
};
38

    
39
range_t::range_t(double value):
40
    _impl(UHD_PIMPL_MAKE(impl, (value, value, 0)))
41
{
42
    /* NOP */
43
}
44

    
45
range_t::range_t(
46
    double start, double stop, double step
47
):
48
    _impl(UHD_PIMPL_MAKE(impl, (start, stop, step)))
49
{
50
    if (stop < start){
51
        throw uhd::value_error("cannot make range where stop < start");
52
    }
53
}
54

    
55
double range_t::start(void) const{
56
    return _impl->start;
57
}
58

    
59
double range_t::stop(void) const{
60
    return _impl->stop;
61
}
62

    
63
double range_t::step(void) const{
64
    return _impl->step;
65
}
66

    
67
const std::string range_t::to_pp_string(void) const{
68
    std::stringstream ss;
69
    ss << "(" << this->start();
70
    if (this->start() != this->stop()) ss << ", " << this->stop();
71
    if (this->step() != 0) ss << ", " << this->step();
72
    ss << ")";
73
    return ss.str();
74
}
75

    
76
/***********************************************************************
77
 * meta_range_t implementation code
78
 **********************************************************************/
79
void check_meta_range_monotonic(const meta_range_t &mr){
80
    if (mr.empty()){
81
        throw uhd::value_error("meta-range cannot be empty");
82
    }
83
    for (size_t i = 1; i < mr.size(); i++){
84
        if (mr.at(i).start() < mr.at(i-1).stop()){
85
            throw uhd::value_error("meta-range is not monotonic");
86
        }
87
    }
88
}
89

    
90
meta_range_t::meta_range_t(void){
91
    /* NOP */
92
}
93

    
94
meta_range_t::meta_range_t(
95
    double start, double stop, double step
96
):
97
    std::vector<range_t > (1, range_t(start, stop, step))
98
{
99
    /* NOP */
100
}
101

    
102
double meta_range_t::start(void) const{
103
    check_meta_range_monotonic(*this);
104
    double min_start = this->front().start();
105
    BOOST_FOREACH(const range_t &r, (*this)){
106
        min_start = std::min(min_start, r.start());
107
    }
108
    return min_start;
109
}
110

    
111
double meta_range_t::stop(void) const{
112
    check_meta_range_monotonic(*this);
113
    double max_stop = this->front().stop();
114
    BOOST_FOREACH(const range_t &r, (*this)){
115
        max_stop = std::max(max_stop, r.stop());
116
    }
117
    return max_stop;
118
}
119

    
120
double meta_range_t::step(void) const{
121
    check_meta_range_monotonic(*this);
122
    std::vector<double> non_zero_steps;
123
    range_t last = this->front();
124
    BOOST_FOREACH(const range_t &r, (*this)){
125
        //steps at each range
126
        if (r.step() > 0) non_zero_steps.push_back(r.step());
127
        //and steps in-between ranges
128
        double ibtw_step = r.start() - last.stop();
129
        if (ibtw_step > 0) non_zero_steps.push_back(ibtw_step);
130
        //store ref to last
131
        last = r;
132
    }
133
    if (non_zero_steps.empty()) return 0; //all zero steps, its zero...
134
    return *std::min_element(non_zero_steps.begin(), non_zero_steps.end());
135
}
136

    
137
double meta_range_t::clip(double value, bool clip_step) const{
138
    check_meta_range_monotonic(*this);
139
    double last_stop = this->front().stop();
140
    BOOST_FOREACH(const range_t &r, (*this)){
141
        //in-between ranges, clip to nearest
142
        if (value < r.start()){
143
            return (std::abs(value - r.start()) < std::abs(value - last_stop))?
144
                r.start() : last_stop;
145
        }
146
        //in this range, clip here
147
        if (value <= r.stop()){
148
            if (not clip_step or r.step() == 0) return value;
149
            return boost::math::round((value - r.start())/r.step())*r.step() + r.start();
150
        }
151
        //continue on to the next range
152
        last_stop = r.stop();
153
    }
154
    return last_stop;
155
}
156

    
157
const std::string meta_range_t::to_pp_string(void) const{
158
    std::stringstream ss;
159
    BOOST_FOREACH(const range_t &r, (*this)){
160
        ss << r.to_pp_string() << std::endl;
161
    }
162
    return ss.str();
163
}