diff options
Diffstat (limited to 'gr-analog')
-rw-r--r-- | gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t | 3 | ||||
-rw-r--r-- | gr-analog/lib/fastnoise_source_X_impl.cc.t | 34 | ||||
-rw-r--r-- | gr-analog/lib/fastnoise_source_X_impl.h.t | 2 | ||||
-rw-r--r-- | gr-analog/python/analog/qa_fastnoise.py | 120 |
4 files changed, 124 insertions, 35 deletions
diff --git a/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t b/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t index 850633979c..f588299604 100644 --- a/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t +++ b/gr-analog/include/gnuradio/analog/fastnoise_source_X.h.t @@ -29,6 +29,8 @@ #include <gnuradio/analog/noise_type.h> #include <gnuradio/sync_block.h> +#include <vector> + namespace gr { namespace analog { @@ -62,6 +64,7 @@ namespace gr { long seed = 0, long samples=1024*16); virtual @TYPE@ sample() = 0; virtual @TYPE@ sample_unbiased() = 0; + virtual const std::vector<@TYPE@>& samples() const = 0; /*! * Set the noise type. Nominally from the diff --git a/gr-analog/lib/fastnoise_source_X_impl.cc.t b/gr-analog/lib/fastnoise_source_X_impl.cc.t index 940918b11b..72c6cb0582 100644 --- a/gr-analog/lib/fastnoise_source_X_impl.cc.t +++ b/gr-analog/lib/fastnoise_source_X_impl.cc.t @@ -27,6 +27,7 @@ #endif #include "@IMPL_NAME@.h" +#include <gnuradio/xoroshiro128p.h> #include <gnuradio/io_signature.h> #include <stdexcept> @@ -46,13 +47,13 @@ namespace gr { io_signature::make(1, 1, sizeof(@TYPE@))), d_type(type), #if @IS_COMPLEX@ // complex? - d_ampl(ampl/sqrtf(2.0f)), + d_ampl(ampl/sqrtf(2.0f)) #else - d_ampl(ampl), + d_ampl(ampl) #endif - d_rng(seed) { d_samples.resize(samples); + xoroshiro128p_seed(d_state, (uint64_t) seed); generate(); } @@ -144,32 +145,27 @@ namespace gr { @TYPE@ @IMPL_NAME@::sample() { -#ifdef HAVE_RAND48 - size_t idx = lrand48() % d_samples.size(); -#else - size_t idx = rand() % d_samples.size(); -#endif + size_t idx = xoroshiro128p_next(d_state) % d_samples.size(); return d_samples[idx]; } -#ifndef FASTNOISE_RANDOM_SIGN -#ifndef HAVE_RAND48 -#define FASTNOISE_RANDOM_SIGN ((rand()%2==0)?1:-1) -#else -#define FASTNOISE_RANDOM_SIGN ((lrand48()%2==0)?1:-1) -#endif -#endif - @TYPE@ @IMPL_NAME@::sample_unbiased() { + uint64_t random_int = xoroshiro128p_next(d_state); #if @IS_COMPLEX@ gr_complex s(sample()); - return gr_complex(FASTNOISE_RANDOM_SIGN * s.real(), - FASTNOISE_RANDOM_SIGN * s.imag()); + float re = (random_int & (UINT64_C(1)<<23)) ? (- s.real()) : (s.real()); + float im = (random_int & (UINT64_C(1)<<42)) ? (- s.real()) : (s.real()); + return gr_complex(re, im); #else - return FASTNOISE_RANDOM_SIGN * sample(); + float s = sample(); + return (random_int & (1<<23)) ? (-s) : s; #endif } + const std::vector<@TYPE@>& @IMPL_NAME@::samples() const + { + return d_samples; + } } /* namespace analog */ } /* namespace gr */ diff --git a/gr-analog/lib/fastnoise_source_X_impl.h.t b/gr-analog/lib/fastnoise_source_X_impl.h.t index 8ad1e4f8fe..ef0465729d 100644 --- a/gr-analog/lib/fastnoise_source_X_impl.h.t +++ b/gr-analog/lib/fastnoise_source_X_impl.h.t @@ -38,6 +38,7 @@ namespace gr { float d_ampl; gr::random d_rng; std::vector<@TYPE@> d_samples; + uint64_t d_state[2]; public: @IMPL_NAME@(noise_type_t type, float ampl, long seed, long samples); @@ -49,6 +50,7 @@ namespace gr { void set_type(noise_type_t type); void set_amplitude(float ampl); void generate(); + const std::vector<@TYPE@>& samples() const; noise_type_t type() const { return d_type; } float amplitude() const { return d_ampl; } diff --git a/gr-analog/python/analog/qa_fastnoise.py b/gr-analog/python/analog/qa_fastnoise.py index 91e1cb87b7..f712d66ca7 100644 --- a/gr-analog/python/analog/qa_fastnoise.py +++ b/gr-analog/python/analog/qa_fastnoise.py @@ -20,32 +20,120 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, gr_unittest, analog +from gnuradio import gr, gr_unittest, analog, blocks +import numpy + class test_fastnoise_source(gr_unittest.TestCase): def setUp (self): - self.tb = gr.top_block () + + self.num = 2**22 + self.num_items = 10**6 + self.default_args = {"samples": self.num, "seed": 43, "ampl": 1} def tearDown (self): - self.tb = None + pass + + def run_test_real(self, form): + """ Run test case with float input/output + """ + tb = gr.top_block() + src = analog.fastnoise_source_f(type=form, **self.default_args) + head = blocks.head(nitems=self.num_items, sizeof_stream_item=gr.sizeof_float) + sink = blocks.vector_sink_f() + tb.connect(src, head, sink) + tb.run() + return numpy.array(sink.data()) + + def run_test_complex(self, form): + """ Run test case with complex input/output + """ + tb = gr.top_block() + src = analog.fastnoise_source_c(type=form, **self.default_args) + head = blocks.head(nitems=self.num_items, sizeof_stream_item=gr.sizeof_gr_complex) + sink = blocks.vector_sink_c() + tb.connect(src, head, sink) + tb.run() + return numpy.array(sink.data()) + + def test_001_real_uniform_moments(self): + + data = self.run_test_real(analog.GR_UNIFORM) + + self.assertAlmostEqual(min(data), -1, places=4) + self.assertAlmostEqual(max(data), 1, places=4) + + # mean, variance + self.assertAlmostEqual(data.mean(), 0, places=2) + self.assertAlmostEqual(data.var(), (1-(-1))**2./12, places=3) + + def test_001_real_gaussian_moments(self): + data = self.run_test_real(analog.GR_GAUSSIAN) + + # mean, variance + self.assertAlmostEqual(data.mean(), 0, places=2) + self.assertAlmostEqual(data.var(), 1, places=2) - def test_001(self): - # Just confirm that we can instantiate a noise source - op = analog.fastnoise_source_f(analog.GR_GAUSSIAN, 10, 10) + def test_001_real_laplacian_moments(self): + data = self.run_test_real(analog.GR_LAPLACIAN) - def test_002(self): - # Test get methods - set_type = analog.GR_GAUSSIAN - set_ampl = 10 - op = analog.fastnoise_source_f(set_type, set_ampl, 10) - get_type = op.type() - get_ampl = op.amplitude() + # mean, variance + self.assertAlmostEqual(data.mean(), 0, places=2) + self.assertAlmostEqual(data.var(), 2, places=2) - self.assertEqual(get_type, set_type) - self.assertEqual(get_ampl, set_ampl) + def test_001_complex_uniform_moments(self): + data = self.run_test_complex(analog.GR_UNIFORM) + # mean, variance + self.assertAlmostEqual(data.real.mean(), 0, places=2) + self.assertAlmostEqual(data.real.var(), 0.5*(1-(-1))**2./12, places=3) + self.assertAlmostEqual(data.imag.mean(), 0, places=2) + self.assertAlmostEqual(data.imag.var(), 0.5*(1-(-1))**2./12, places=3) + + def test_001_complex_gaussian_moments(self): + data = self.run_test_complex(analog.GR_GAUSSIAN) + + # mean, variance + self.assertAlmostEqual(data.real.mean(), 0, places=2) + self.assertAlmostEqual(data.real.var(), 0.5, places=2) + + self.assertAlmostEqual(data.imag.mean(), 0, places=2) + self.assertAlmostEqual(data.imag.var(), 0.5, places=2) + + def test_002_real_uniform_reproducibility(self): + data1 = self.run_test_real(analog.GR_UNIFORM) + data2 = self.run_test_real(analog.GR_UNIFORM) + + # It's pseudoramdo thus must be equal + self.assertTrue(numpy.array_equal(data1, data2)) + + def test_002_real_gaussian_reproducibility(self): + data1 = self.run_test_real(analog.GR_GAUSSIAN) + data2 = self.run_test_real(analog.GR_GAUSSIAN) + + self.assertTrue(numpy.array_equal(data1, data2)) + + def test_003_real_uniform_pool(self): + src = analog.fastnoise_source_f(type=analog.GR_UNIFORM, **self.default_args) + src2 = analog.fastnoise_source_f(type=analog.GR_UNIFORM, **self.default_args) + self.assertTrue(numpy.array_equal(numpy.array(src.samples()), numpy.array(src2.samples()))) + def test_003_real_gaussian_pool(self): + src = analog.fastnoise_source_f(type=analog.GR_GAUSSIAN, **self.default_args) + src2 = analog.fastnoise_source_f(type=analog.GR_GAUSSIAN, **self.default_args) + self.assertTrue(numpy.array_equal(numpy.array(src.samples()), numpy.array(src2.samples()))) + def test_003_cmplx_gaussian_pool(self): + src = analog.fastnoise_source_c(type=analog.GR_GAUSSIAN, **self.default_args) + src2 = analog.fastnoise_source_c(type=analog.GR_GAUSSIAN, **self.default_args) + self.assertTrue(numpy.array_equal(numpy.array(src.samples()), numpy.array(src2.samples()))) + def test_003_cmplx_uniform_pool(self): + src = analog.fastnoise_source_c(type=analog.GR_UNIFORM, **self.default_args) + src2 = analog.fastnoise_source_c(type=analog.GR_UNIFORM, **self.default_args) + self.assertTrue(numpy.array_equal(numpy.array(src.samples()), numpy.array(src2.samples()))) + def test_003_real_laplacian_pool(self): + src = analog.fastnoise_source_f(type=analog.GR_LAPLACIAN, **self.default_args) + src2 = analog.fastnoise_source_f(type=analog.GR_LAPLACIAN, **self.default_args) + self.assertTrue(numpy.array_equal(numpy.array(src.samples()), numpy.array(src2.samples()))) if __name__ == '__main__': gr_unittest.run(test_fastnoise_source, "test_fastnoise_source.xml") - |