Skip to content

Commit

Permalink
cdd: Add another testcase
Browse files Browse the repository at this point in the history
For the sake of completeness: Add a `remove_cyclic_prefix` function to
the cyclic prefix adder.
  • Loading branch information
jdemel committed Jan 29, 2021
1 parent ae7f806 commit 8b9a322
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 21 deletions.
1 change: 1 addition & 0 deletions include/gfdm/add_cyclic_prefix_cc.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class add_cyclic_prefix_cc
int cyclic_shift = 0);
~add_cyclic_prefix_cc();
void generic_work(gfdm_complex* p_out, const gfdm_complex* p_in);
void remove_cyclic_prefix(gfdm_complex* p_out, const gfdm_complex* p_in);
int block_size() { return d_block_len; };
int frame_size() { return block_size() + d_cp_len + d_cs_len; };
int cyclic_shift() const { return d_cyclic_shift; };
Expand Down
8 changes: 8 additions & 0 deletions lib/add_cyclic_prefix_cc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <gfdm/add_cyclic_prefix_cc.h>
#include <string.h>
#include <volk/volk.h>
#include <algorithm>
#include <iostream>

namespace gr {
Expand Down Expand Up @@ -77,5 +78,12 @@ void add_cyclic_prefix_cc::generic_work(gfdm_complex* p_out, const gfdm_complex*
}
}

void add_cyclic_prefix_cc::remove_cyclic_prefix(gfdm_complex* p_out,
const gfdm_complex* p_in)
{
std::copy(p_in + d_cp_len, p_in + d_cp_len + block_size(), p_out);
}


} /* namespace gfdm */
} /* namespace gr */
30 changes: 26 additions & 4 deletions python/bindings/cyclic_prefix_python.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ void bind_cyclic_prefixer(py::module& m)
throw std::runtime_error("Only ONE-dimensional vectors allowed!");
}
if (inb.size != self.block_size()) {
throw std::runtime_error("Input vector size(" +
std::to_string(inb.size) +
") MUST be equal to Modulator.block_size(" +
std::to_string(self.block_size()) + ")!");
throw std::runtime_error(
"Input vector size(" + std::to_string(inb.size) +
") MUST be equal to Cyclic_prefix.block_size(" +
std::to_string(self.block_size()) + ")!");
}
auto result =
py::array_t<add_cyclic_prefix_cc::gfdm_complex>(self.frame_size());
Expand All @@ -69,5 +69,27 @@ void bind_cyclic_prefixer(py::module& m)
self.generic_work((add_cyclic_prefix_cc::gfdm_complex*)resb.ptr,
(add_cyclic_prefix_cc::gfdm_complex*)inb.ptr);
return result;
})
.def("remove_cyclic_prefix",
[](add_cyclic_prefix_cc& self,
const py::array_t<add_cyclic_prefix_cc::gfdm_complex,
py::array::c_style | py::array::forcecast> array) {
py::buffer_info inb = array.request();
if (inb.ndim != 1) {
throw std::runtime_error("Only ONE-dimensional vectors allowed!");
}
if (inb.size != self.frame_size()) {
throw std::runtime_error(
"Input vector size(" + std::to_string(inb.size) +
") MUST be equal to Cyclic_prefix.frame_size(" +
std::to_string(self.block_size()) + ")!");
}
auto result =
py::array_t<add_cyclic_prefix_cc::gfdm_complex>(self.block_size());
py::buffer_info resb = result.request();

self.remove_cyclic_prefix((add_cyclic_prefix_cc::gfdm_complex*)resb.ptr,
(add_cyclic_prefix_cc::gfdm_complex*)inb.ptr);
return result;
});
}
61 changes: 44 additions & 17 deletions python/qa_python_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ def test_001_prefix(self):
self.assertComplexTuplesAlmostEqual(res, ref, 6)

def test_002_prefix_shifted(self):
print('shifted')
timeslots = 3
subcarriers = 32
cyclic_shift = 4
Expand All @@ -220,6 +219,30 @@ def test_002_prefix_shifted(self):
self.assertEqual(res.size, cp_len + block_len + cs_len)
self.assertComplexTuplesAlmostEqual(res, ref, 5)

def test_003_prefix_removed(self):
timeslots = 3
subcarriers = 32
cyclic_shift = 4

block_len = timeslots * subcarriers
cp_len = 16
cs_len = cp_len // 2
ramp_len = 4
frame_len = cp_len + block_len + cs_len
window_len = get_window_len(cp_len, timeslots, subcarriers,
cs_len)
window_taps = get_raised_cosine_ramp(ramp_len, window_len)

prefixer = Cyclic_prefixer(block_len, cp_len, cs_len, ramp_len,
window_taps, cyclic_shift)

data = np.arange(frame_len, dtype=np.complex64)
ref = data[cp_len:-cs_len]

res = prefixer.remove_cyclic_prefix(data)
self.assertEqual(res.size, block_len)
self.assertComplexTuplesAlmostEqual(res, ref, 5)


class ModulatorTests(gr_unittest.TestCase):
def setUp(self):
Expand Down Expand Up @@ -507,6 +530,14 @@ def test_002_snr(self):


class CyclicDelayDiversityTests(gr_unittest.TestCase):
'''CyclicDelayDiversityTests
This test basically just confirms if CDD works as expected.
Can we estimate a channel? Are signs correct?
Do not expect numerical accuracy. This is not even intended.
The estimator employs a Gaussian filter on the channel estimate
before interpolation to smoothen over noise estimates.
'''

def setUp(self):
self.filtertype = 'rrc'
self.filteralpha = .5
Expand Down Expand Up @@ -553,8 +584,8 @@ def test_001_selective(self):
active_subcarriers = 52
cp_len = subcarriers // 2
ramp_len = cp_len // 2
# cyclic_shift = [0, 2, 4, 6, ]
cyclic_shift = [0, 4, 8, 12, ]
cyclic_shift = [0, 2, 4, 6, ]
# cyclic_shift = [0, 4, 8, 12, ]
active_symbols = timeslots * active_subcarriers
preambles = [self.generate_preamble(
subcarriers, active_subcarriers, cp_len, ramp_len, cs) for cs in cyclic_shift]
Expand All @@ -581,25 +612,21 @@ def test_001_selective(self):
fh = np.fft.fft(effective_channel, timeslots * subcarriers)
lowfh = fh[0:active_symbols // 2]
hifh = fh[-active_symbols // 2:]
import matplotlib.pyplot as plt
plt.plot(res.real)
plt.plot(res.imag)
plt.plot(fh.real, ls='dashed')
plt.plot(fh.imag, ls='dashed')
# plt.plot(np.abs(lowres))
# plt.plot(np.angle(lowres))
# plt.plot(np.abs(lowfh), ls='dashed')
# plt.plot(np.angle(lowfh), ls='dashed')
plt.show()

# Be careful here!
# These tests confirm that everything is kinda close.
# Though, some internal settings, e.g. a smoothening filter for noise estimates
# Does not allow for higher accuracy!
self.assertFloatTuplesAlmostEqual(np.unwrap(np.angle(lowres)),
np.unwrap(np.angle(lowfh)), 0)
self.assertFloatTuplesAlmostEqual(np.unwrap(np.angle(hires)),
np.unwrap(np.angle(hifh)), 0)
# self.assertFloatTuplesAlmostEqual(np.abs(hires),
# np.abs(hifh), 0)
# self.assertComplexTuplesAlmostEqual(lowres, lowfh, 1)
self.assertComplexTuplesAlmostEqual(hires, hifh, 0)
self.assertFloatTuplesAlmostEqual(np.abs(hires),
np.abs(hifh), -1)
self.assertFloatTuplesAlmostEqual(np.abs(lowres),
np.abs(lowfh), -1)
self.assertComplexTuplesAlmostEqual(lowres, lowfh, -1)
self.assertComplexTuplesAlmostEqual(hires, hifh, -1)

def generate_preamble(self, subcarriers, active_subcarriers, cp_len,
ramp_len, cyclic_shift):
Expand Down

0 comments on commit 8b9a322

Please sign in to comment.