summaryrefslogtreecommitdiff
path: root/gr-channels/lib/flat_fader_impl.cc
blob: 2441788186e00550bbed4d2790a8899a39b8f5c8 (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
/* -*- c++ -*- */
/*
 * Copyright 2016,2018 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 3, 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.
 */

#include "flat_fader_impl.h"
#include <gnuradio/math.h>

namespace gr {
namespace channels {

flat_fader_impl::flat_fader_impl(uint32_t N, float fDTs, bool LOS, float K, uint32_t seed)
    : rng_1(seed),
      dist_1(-GR_M_PI, GR_M_PI),
      rng_2(seed + 1),
      dist_2(0, 1),

      d_N(N),
      d_fDTs(fDTs),
      d_theta(dist_1(rng_1)),
      d_theta_los(dist_1(rng_1)),
      d_step(powf(0.00125 * fDTs, 1.1)), // max step size approximated from Table 2
      d_m(0),
      d_K(K),
      d_LOS(LOS),

      d_psi(d_N + 1, 0),
      d_phi(d_N + 1, 0),

      d_table(8 * 1024),

      scale_sin(sqrtf(1.0 / d_N)),
      scale_los(sqrtf(d_K) / sqrtf(d_K + 1)),
      scale_nlos(1 / sqrtf(d_K + 1))
{
    // generate initial phase values
    for (int i = 0; i < d_N + 1; i++) {
        d_psi[i] = dist_1(rng_1);
        d_phi[i] = dist_1(rng_1);
    }
}

#if FASTSINCOS == 1
#define _GRFASTSIN(x) gr::fxpt::sin(gr::fxpt::float_to_fixed(x))
#define _GRFASTCOS(x) gr::fxpt::cos(gr::fxpt::float_to_fixed(x))
#elif FASTSINCOS == 2
#define _GRFASTSIN(x) d_table.sin(x)
#define _GRFASTCOS(x) d_table.cos(x)
#else
#define _GRFASTSIN(x) sin(x)
#define _GRFASTCOS(x) cos(x)
#endif

void flat_fader_impl::next_samples(std::vector<gr_complex>& Hvec, int n_samples)
{
    Hvec.resize(n_samples);
    for (int i = 0; i < n_samples; i++) {
        gr_complex H(0, 0);
        for (int n = 1; n < d_N + 1; n++) {
            float alpha_n = (2 * GR_M_PI * n - GR_M_PI + d_theta) / (4 * d_N);
            d_psi[n] =
                fmod(d_psi[n] + 2 * GR_M_PI * d_fDTs * _GRFASTCOS(alpha_n), 2 * GR_M_PI);
            d_phi[n] =
                fmod(d_phi[n] + 2 * GR_M_PI * d_fDTs * _GRFASTCOS(alpha_n), 2 * GR_M_PI);
            float s_i = scale_sin * _GRFASTCOS(d_psi[n]);
            float s_q = scale_sin * _GRFASTSIN(d_phi[n]);
            H += gr_complex(s_i, s_q);
        }

        if (d_LOS) {
            d_psi[0] = fmod(d_psi[0] + 2 * GR_M_PI * d_fDTs * _GRFASTCOS(d_theta_los),
                            2 * GR_M_PI);
            float los_i = scale_los * _GRFASTCOS(d_psi[0]);
            float los_q = scale_los * _GRFASTSIN(d_psi[0]);
            H = H * scale_nlos + gr_complex(los_i, los_q);
        }

        update_theta();
        Hvec[i] = H;
    }
}

gr_complex flat_fader_impl::next_sample()
{
    std::vector<gr_complex> v(1);
    next_samples(v, 1);
    return v[0];
}

void flat_fader_impl::update_theta()
{
    d_theta += (d_step * dist_2(rng_2));
    if (d_theta > GR_M_PI) {
        d_theta = GR_M_PI;
        d_step = -d_step;
    } else if (d_theta < -GR_M_PI) {
        d_theta = -GR_M_PI;
        d_step = -d_step;
    }
}

} /* namespace channels */
} /* namespace gr */