summaryrefslogtreecommitdiff
path: root/gnuradio-examples/python/hier/digital/pick_bitrate.py
blob: 42aefa94e3376804c165aeedf3096d704fc376dc (plain)
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
#
# Copyright 2005,2006 Free Software Foundation, Inc.
# 
# This file is part of GNU Radio
# 
# GNU Radio 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 2, or (at your option)
# any later version.
# 
# GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
# 

_default_bitrate = 500e3

_valid_samples_per_symbol = (2,3,4,5,6,7)

def _gen_tx_info(converter_rate):
    results = []
    for samples_per_symbol in _valid_samples_per_symbol:
        for interp in range(16, 512 + 1, 4):
            bitrate = converter_rate / interp / samples_per_symbol
            results.append((bitrate, samples_per_symbol, interp))
    results.sort()
    return results

def _gen_rx_info(converter_rate):
    results = []
    for samples_per_symbol in _valid_samples_per_symbol:
        for decim in range(8, 256 + 1, 2):
            bitrate = converter_rate / decim / samples_per_symbol
            results.append((bitrate, samples_per_symbol, decim))
    results.sort()
    return results
    
def _filter_info(info, samples_per_symbol, xrate):
    if samples_per_symbol is not None:
        info = [x for x in info if x[1] == samples_per_symbol]
    if xrate is not None:
        info = [x for x in info if x[2] == xrate]
    return info

def _pick_best(target_bitrate, bits_per_symbol, info):
    """
    @returns tuple (bitrate, samples_per_symbol, interp_rate_or_decim_rate)
    """
    if len(info) == 0:
        raise RuntimeError, "info is zero length!"

    if target_bitrate is None:     # return the fastest one
        return info[-1]
    
    # convert bit rate to symbol rate
    target_symbolrate = target_bitrate / bits_per_symbol
    
    # Find the closest matching symbol rate.
    # In the event of a tie, the one with the lowest samples_per_symbol wins.
    # (We already sorted them, so the first one is the one we take)

    best = info[0]
    best_delta = abs(target_symbolrate - best[0])
    for x in info[1:]:
        delta = abs(target_symbolrate - x[0])
        if delta < best_delta:
            best_delta = delta
            best = x

    # convert symbol rate back to bit rate
    return ((best[0] * bits_per_symbol),) + best[1:]

def _pick_bitrate(bitrate, bits_per_symbol, samples_per_symbol,
                  xrate, converter_rate, gen_info):
    """
    @returns tuple (bitrate, samples_per_symbol, interp_rate_or_decim_rate)
    """
    if not isinstance(bits_per_symbol, int) or bits_per_symbol < 1:
        raise ValueError, "bits_per_symbol must be an int >= 1"
    
    if samples_per_symbol is not None and xrate is not None:  # completely determined
        return (float(converter_rate) / xrate / samples_per_symbol,
                samples_per_symbol, xrate)

    if bitrate is None and samples_per_symbol is None and xrate is None:
        bitrate = _default_bitrate

    # now we have a target bitrate and possibly an xrate or
    # samples_per_symbol constraint, but not both of them.

    return _pick_best(bitrate, bits_per_symbol,
                      _filter_info(gen_info(converter_rate), samples_per_symbol, xrate))
    
# ---------------------------------------------------------------------------------------

def pick_tx_bitrate(bitrate, bits_per_symbol, samples_per_symbol,
                    interp_rate, converter_rate=128e6):
    """
    Given the 4 input parameters, return at configuration that matches

    @param bitrate: desired bitrate or None
    @type bitrate: number or None
    @param bits_per_symbol: E.g., BPSK -> 1, QPSK -> 2, 8-PSK -> 3
    @type bits_per_symbol: integer >= 1
    @param samples_per_symbol: samples/baud (aka samples/symbol)
    @type samples_per_symbol: number or None
    @param interp_rate: USRP interpolation factor
    @type interp_rate: integer or None
    @param converter_rate: converter sample rate in Hz
    @type converter_rate: number

    @returns tuple (bitrate, samples_per_symbol, interp_rate)
    """
    return _pick_bitrate(bitrate, bits_per_symbol, samples_per_symbol,
                         interp_rate, converter_rate, _gen_tx_info)


def pick_rx_bitrate(bitrate, bits_per_symbol, samples_per_symbol,
                    decim_rate, converter_rate=64e6):
    """
    Given the 4 input parameters, return at configuration that matches

    @param bitrate: desired bitrate or None
    @type bitrate: number or None
    @param bits_per_symbol: E.g., BPSK -> 1, QPSK -> 2, 8-PSK -> 3
    @type bits_per_symbol: integer >= 1
    @param samples_per_symbol: samples/baud (aka samples/symbol)
    @type samples_per_symbol: number or None
    @param decim_rate: USRP decimation factor
    @type decim_rate: integer or None
    @param converter_rate: converter sample rate in Hz
    @type converter_rate: number

    @returns tuple (bitrate, samples_per_symbol, decim_rate)
    """
    return _pick_bitrate(bitrate, bits_per_symbol, samples_per_symbol,
                         decim_rate, converter_rate, _gen_rx_info)