-
Notifications
You must be signed in to change notification settings - Fork 21
/
psk.hh
141 lines (118 loc) · 3.67 KB
/
psk.hh
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
/*
Phase-shift keying
Copyright 2018 Ahmet Inan <[email protected]>
*/
#pragma once
template <int NUM, typename TYPE, typename CODE>
struct PhaseShiftKeying;
template <typename TYPE, typename CODE>
struct PhaseShiftKeying<2, TYPE, CODE>
{
static const int NUM = 2;
static const int BITS = 1;
typedef TYPE complex_type;
typedef typename TYPE::value_type value_type;
typedef CODE code_type;
static constexpr value_type DIST = 2;
static code_type quantize(value_type precision, value_type value)
{
value *= DIST * precision;
if (std::is_integral<code_type>::value)
value = std::nearbyint(value);
if (std::is_same<code_type, int8_t>::value)
value = std::min<value_type>(std::max<value_type>(value, -128), 127);
return value;
}
static void hard(code_type *b, complex_type c)
{
b[0] = c.real() < value_type(0) ? code_type(-1) : code_type(1);
}
static void soft(code_type *b, complex_type c, value_type precision)
{
b[0] = quantize(precision, c.real());
}
static complex_type map(code_type *b)
{
return complex_type(b[0], 0);
}
};
template <typename TYPE, typename CODE>
struct PhaseShiftKeying<4, TYPE, CODE>
{
static const int NUM = 4;
static const int BITS = 2;
typedef TYPE complex_type;
typedef typename TYPE::value_type value_type;
typedef CODE code_type;
// 1/sqrt(2)
static constexpr value_type rcp_sqrt_2 = 0.70710678118654752440;
static constexpr value_type DIST = 2 * rcp_sqrt_2;
static code_type quantize(value_type precision, value_type value)
{
value *= DIST * precision;
if (std::is_integral<code_type>::value)
value = std::nearbyint(value);
if (std::is_same<code_type, int8_t>::value)
value = std::min<value_type>(std::max<value_type>(value, -128), 127);
return value;
}
static void hard(code_type *b, complex_type c)
{
b[0] = c.real() < value_type(0) ? code_type(-1) : code_type(1);
b[1] = c.imag() < value_type(0) ? code_type(-1) : code_type(1);
}
static void soft(code_type *b, complex_type c, value_type precision)
{
b[0] = quantize(precision, c.real());
b[1] = quantize(precision, c.imag());
}
static complex_type map(code_type *b)
{
return rcp_sqrt_2 * complex_type(b[0], b[1]);
}
};
template <typename TYPE, typename CODE>
struct PhaseShiftKeying<8, TYPE, CODE>
{
static const int NUM = 8;
static const int BITS = 3;
typedef TYPE complex_type;
typedef typename TYPE::value_type value_type;
typedef CODE code_type;
// c(a(1)/2)
static constexpr value_type cos_pi_8 = 0.92387953251128675613;
// s(a(1)/2)
static constexpr value_type sin_pi_8 = 0.38268343236508977173;
// 1/sqrt(2)
static constexpr value_type rcp_sqrt_2 = 0.70710678118654752440;
static constexpr value_type DIST = 2 * sin_pi_8;
static code_type quantize(value_type precision, value_type value)
{
value *= DIST * precision;
if (std::is_integral<code_type>::value)
value = std::nearbyint(value);
if (std::is_same<code_type, int8_t>::value)
value = std::min<value_type>(std::max<value_type>(value, -128), 127);
return value;
}
static void hard(code_type *b, complex_type c)
{
b[1] = c.real() < value_type(0) ? code_type(-1) : code_type(1);
b[2] = c.imag() < value_type(0) ? code_type(-1) : code_type(1);
b[0] = std::abs(c.real()) < std::abs(c.imag()) ? code_type(-1) : code_type(1);
}
static void soft(code_type *b, complex_type c, value_type precision)
{
b[1] = quantize(precision, c.real());
b[2] = quantize(precision, c.imag());
b[0] = quantize(precision, rcp_sqrt_2 * (std::abs(c.real()) - std::abs(c.imag())));
}
static complex_type map(code_type *b)
{
value_type real = cos_pi_8;
value_type imag = sin_pi_8;
if (b[0] < code_type(0))
std::swap(real, imag);
return complex_type(real * b[1], imag * b[2]);
}
};