diff options
author | Tom Rondeau <trondeau@vt.edu> | 2013-02-17 11:04:02 -0500 |
---|---|---|
committer | Tom Rondeau <trondeau@vt.edu> | 2013-02-17 11:04:02 -0500 |
commit | 9ca6c72a04991a0ec41afcc04b60a85eae52e921 (patch) | |
tree | 88c22d2fff68e2e8c3d3b46ce5c7556e2e4f5a95 | |
parent | f8175a626bb477d92b0d46164d30399e12e2ac09 (diff) | |
parent | 226bb6ad1f524b3556f3fc2be83a6093875e50f0 (diff) |
Merge branch 'next' of gnuradio.org:gnuradio into next
66 files changed, 2234 insertions, 214 deletions
diff --git a/gnuradio-core/src/examples/ctrlport/pfb_sync_test-qt.grc b/gnuradio-core/src/examples/ctrlport/pfb_sync_test-qt.grc index 2dadddb6df..5891500860 100644 --- a/gnuradio-core/src/examples/ctrlport/pfb_sync_test-qt.grc +++ b/gnuradio-core/src/examples/ctrlport/pfb_sync_test-qt.grc @@ -1,6 +1,6 @@ <?xml version='1.0' encoding='ASCII'?> <flow_graph> - <timestamp>Wed Feb 6 17:01:06 2013</timestamp> + <timestamp>Thu Feb 14 15:27:16 2013</timestamp> <block> <key>options</key> <param> @@ -161,76 +161,6 @@ </param> </block> <block> - <key>gr_file_source</key> - <param> - <key>id</key> - <value>gr_file_source_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>file</key> - <value>/dev/urandom</value> - </param> - <param> - <key>type</key> - <value>byte</value> - </param> - <param> - <key>repeat</key> - <value>True</value> - </param> - <param> - <key>vlen</key> - <value>1</value> - </param> - <param> - <key>_coordinate</key> - <value>(228, 56)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>gr_packed_to_unpacked_xx</key> - <param> - <key>id</key> - <value>gr_packed_to_unpacked_xx_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>byte</value> - </param> - <param> - <key>bits_per_chunk</key> - <value>8</value> - </param> - <param> - <key>endianness</key> - <value>gr.GR_MSB_FIRST</value> - </param> - <param> - <key>num_ports</key> - <value>1</value> - </param> - <param> - <key>_coordinate</key> - <value>(408, 56)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> <key>variable</key> <param> <key>id</key> @@ -709,6 +639,111 @@ <value>0</value> </param> </block> + <block> + <key>gr_file_source</key> + <param> + <key>id</key> + <value>gr_file_source_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>file</key> + <value>/dev/urandom</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>repeat</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(228, 56)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_vector_source_x</key> + <param> + <key>id</key> + <value>gr_vector_source_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>vector</key> + <value>0,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</value> + </param> + <param> + <key>repeat</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(235, 126)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_packed_to_unpacked_xx</key> + <param> + <key>id</key> + <value>gr_packed_to_unpacked_xx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>bits_per_chunk</key> + <value>8</value> + </param> + <param> + <key>endianness</key> + <value>gr.GR_MSB_FIRST</value> + </param> + <param> + <key>num_ports</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(408, 56)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> <connection> <source_block_id>gr_packed_to_unpacked_xx_0</source_block_id> <sink_block_id>gr_throttle_0</sink_block_id> @@ -769,4 +804,10 @@ <source_key>0</source_key> <sink_key>0</sink_key> </connection> + <connection> + <source_block_id>gr_vector_source_x_0</source_block_id> + <sink_block_id>gr_packed_to_unpacked_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> </flow_graph> diff --git a/gnuradio-core/src/lib/runtime/gr_block.cc b/gnuradio-core/src/lib/runtime/gr_block.cc index 83bbea37e6..c736d0f058 100644 --- a/gnuradio-core/src/lib/runtime/gr_block.cc +++ b/gnuradio-core/src/lib/runtime/gr_block.cc @@ -283,6 +283,17 @@ gr_block::pc_noutput_items() } float +gr_block::pc_noutput_items_var() +{ + if(d_detail) { + return d_detail->pc_noutput_items_var(); + } + else { + return 0; + } +} + +float gr_block::pc_nproduced() { if(d_detail) { @@ -294,6 +305,17 @@ gr_block::pc_nproduced() } float +gr_block::pc_nproduced_var() +{ + if(d_detail) { + return d_detail->pc_nproduced_var(); + } + else { + return 0; + } +} + +float gr_block::pc_input_buffers_full(int which) { if(d_detail) { @@ -304,6 +326,17 @@ gr_block::pc_input_buffers_full(int which) } } +float +gr_block::pc_input_buffers_full_var(int which) +{ + if(d_detail) { + return d_detail->pc_input_buffers_full_var(static_cast<size_t>(which)); + } + else { + return 0; + } +} + std::vector<float> gr_block::pc_input_buffers_full() { @@ -315,6 +348,17 @@ gr_block::pc_input_buffers_full() } } +std::vector<float> +gr_block::pc_input_buffers_full_var() +{ + if(d_detail) { + return d_detail->pc_input_buffers_full_var(); + } + else { + return std::vector<float>(1,0); + } +} + float gr_block::pc_output_buffers_full(int which) { @@ -326,6 +370,17 @@ gr_block::pc_output_buffers_full(int which) } } +float +gr_block::pc_output_buffers_full_var(int which) +{ + if(d_detail) { + return d_detail->pc_output_buffers_full_var(static_cast<size_t>(which)); + } + else { + return 0; + } +} + std::vector<float> gr_block::pc_output_buffers_full() { @@ -337,6 +392,17 @@ gr_block::pc_output_buffers_full() } } +std::vector<float> +gr_block::pc_output_buffers_full_var() +{ + if(d_detail) { + return d_detail->pc_output_buffers_full_var(); + } + else { + return std::vector<float>(1,0); + } +} + float gr_block::pc_work_time() { @@ -348,6 +414,25 @@ gr_block::pc_work_time() } } +float +gr_block::pc_work_time_var() +{ + if(d_detail) { + return d_detail->pc_work_time_var(); + } + else { + return 0; + } +} + +void +gr_block::reset_perf_counters() +{ + if(d_detail) { + d_detail->reset_perf_counters(); + } +} + void gr_block::setup_pc_rpc() { @@ -355,33 +440,63 @@ gr_block::setup_pc_rpc() #ifdef GR_CTRLPORT d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "noutput_items", &gr_block::pc_noutput_items, + alias(), "avg noutput_items", &gr_block::pc_noutput_items, pmt::mp(0), pmt::mp(32768), pmt::mp(0), "", "Average noutput items", RPC_PRIVLVL_MIN, DISPTIMESERIESF))); d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "nproduced", &gr_block::pc_nproduced, + alias(), "var noutput_items", &gr_block::pc_noutput_items_var, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "Var. noutput items", RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "avg nproduced", &gr_block::pc_nproduced, pmt::mp(0), pmt::mp(32768), pmt::mp(0), "", "Average items produced", RPC_PRIVLVL_MIN, DISPTIMESERIESF))); d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "work time", &gr_block::pc_work_time, + alias(), "var nproduced", &gr_block::pc_nproduced_var, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "Var. items produced", RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "avg work time", &gr_block::pc_work_time, pmt::mp(0), pmt::mp(1e9), pmt::mp(0), "", "Average clock cycles in call to work", RPC_PRIVLVL_MIN, DISPTIMESERIESF))); d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "var work time", &gr_block::pc_work_time_var, + pmt::mp(0), pmt::mp(1e9), pmt::mp(0), + "", "Var. clock cycles in call to work", RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + + d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( - alias(), "input \% full", &gr_block::pc_input_buffers_full, + alias(), "avg input \% full", &gr_block::pc_input_buffers_full, pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), "", "Average of how full input buffers are", RPC_PRIVLVL_MIN, DISPTIMESERIESF))); d_rpc_vars.push_back( rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( - alias(), "output \% full", &gr_block::pc_output_buffers_full, + alias(), "var input \% full", &gr_block::pc_input_buffers_full_var, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "Var. of how full input buffers are", RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( + alias(), "avg output \% full", &gr_block::pc_output_buffers_full, pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), "", "Average of how full output buffers are", RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( + alias(), "var output \% full", &gr_block::pc_output_buffers_full_var, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "Var. of how full output buffers are", RPC_PRIVLVL_MIN, DISPTIMESERIESF))); #endif /* GR_CTRLPORT */ } diff --git a/gnuradio-core/src/lib/runtime/gr_block.h b/gnuradio-core/src/lib/runtime/gr_block.h index 8b8851ee92..034f6136d9 100644 --- a/gnuradio-core/src/lib/runtime/gr_block.h +++ b/gnuradio-core/src/lib/runtime/gr_block.h @@ -383,29 +383,58 @@ class GR_CORE_API gr_block : public gr_basic_block { float pc_noutput_items(); /*! + * \brief Gets variance of noutput_items performance counter. + */ + float pc_noutput_items_var(); + + /*! * \brief Gets average num items produced performance counter. */ float pc_nproduced(); /*! - * \brief Gets average average fullness of \p which input buffer. + * \brief Gets variance of num items produced performance counter. + */ + float pc_nproduced_var(); + + /*! + * \brief Gets average fullness of \p which input buffer. */ float pc_input_buffers_full(int which); /*! + * \brief Gets variance of fullness of \p which input buffer. + */ + float pc_input_buffers_full_var(int which); + + /*! * \brief Gets average fullness of all input buffers. */ std::vector<float> pc_input_buffers_full(); /*! + * \brief Gets variance of fullness of all input buffers. + */ + std::vector<float> pc_input_buffers_full_var(); + + /*! * \brief Gets average fullness of \p which input buffer. */ float pc_output_buffers_full(int which); /*! + * \brief Gets variance of fullness of \p which input buffer. + */ + float pc_output_buffers_full_var(int which); + + /*! * \brief Gets average fullness of all output buffers. */ std::vector<float> pc_output_buffers_full(); + /*! + * \brief Gets variance of fullness of all output buffers. + */ + std::vector<float> pc_output_buffers_full_var(); /*! * \brief Gets average clock cycles spent in work. @@ -413,6 +442,16 @@ class GR_CORE_API gr_block : public gr_basic_block { float pc_work_time(); /*! + * \brief Gets average clock cycles spent in work. + */ + float pc_work_time_var(); + + /*! + * \brief Resets the performance counters + */ + void reset_perf_counters(); + + /*! * \brief Sets up export of perf. counters to ControlPort. Only * called by the scheduler. */ diff --git a/gnuradio-core/src/lib/runtime/gr_block.i b/gnuradio-core/src/lib/runtime/gr_block.i index c016f2c28e..a80f64d027 100644 --- a/gnuradio-core/src/lib/runtime/gr_block.i +++ b/gnuradio-core/src/lib/runtime/gr_block.i @@ -68,13 +68,20 @@ class gr_block : public gr_basic_block { // Methods to access performance counters float pc_noutput_items(); + float pc_noutput_items_var(); float pc_nproduced(); + float pc_nproduced_var(); float pc_input_buffers_full(int which); + float pc_input_buffers_full_var(int which); std::vector<float> pc_input_buffers_full(); + std::vector<float> pc_input_buffers_full_var(); float pc_output_buffers_full(int which); + float pc_output_buffers_full_var(int which); std::vector<float> pc_output_buffers_full(); + std::vector<float> pc_output_buffers_full_var(); float pc_work_time(); - + float pc_work_time_var(); + // Methods to manage processor affinity. void set_processor_affinity(const gr_vector_uint &mask); void unset_processor_affinity(); diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.cc b/gnuradio-core/src/lib/runtime/gr_block_detail.cc index b151bd96d2..c05b7b96a0 100644 --- a/gnuradio-core/src/lib/runtime/gr_block_detail.cc +++ b/gnuradio-core/src/lib/runtime/gr_block_detail.cc @@ -41,10 +41,17 @@ gr_block_detail::gr_block_detail (unsigned int ninputs, unsigned int noutputs) d_ninputs (ninputs), d_noutputs (noutputs), d_input (ninputs), d_output (noutputs), d_done (false), - d_avg_noutput_items(0), d_avg_nproduced(0), + d_avg_noutput_items(0), + d_var_noutput_items(0), + d_avg_nproduced(0), + d_var_nproduced(0), d_avg_input_buffers_full(ninputs, 0), + d_var_input_buffers_full(ninputs, 0), d_avg_output_buffers_full(noutputs, 0), - d_avg_work_time(0) + d_var_output_buffers_full(noutputs, 0), + d_avg_work_time(0), + d_var_work_time(0), + d_pc_counter(0) { s_ncurrently_allocated++; } @@ -235,27 +242,68 @@ gr_block_detail::start_perf_counters() void gr_block_detail::stop_perf_counters(int noutput_items, int nproduced) { - float alpha = 0.05; - float beta = 1.0-alpha; - d_end_of_work = gruel::high_res_timer_now(); gruel::high_res_timer_type diff = d_end_of_work - d_start_of_work; - d_avg_work_time = beta*d_avg_work_time + alpha*diff; - - d_avg_nproduced = beta*d_avg_nproduced + alpha*nproduced; - d_avg_noutput_items = beta*d_avg_noutput_items + alpha*noutput_items; - for(size_t i=0; i < d_input.size(); i++) { - float pfull = static_cast<float>(d_input[i]->items_available()) / - static_cast<float>(d_input[i]->max_possible_items_available()); - d_avg_input_buffers_full[i] = beta*d_avg_input_buffers_full[i] + alpha*pfull; + if(d_pc_counter == 0) { + d_avg_work_time = diff; + d_var_work_time = 0; + d_avg_nproduced = nproduced; + d_var_nproduced = 0; + d_avg_noutput_items = noutput_items; + d_var_noutput_items = 0; + for(size_t i=0; i < d_input.size(); i++) { + float pfull = static_cast<float>(d_input[i]->items_available()) / + static_cast<float>(d_input[i]->max_possible_items_available()); + d_avg_input_buffers_full[i] = pfull; + d_var_input_buffers_full[i] = 0; + } + for(size_t i=0; i < d_output.size(); i++) { + float pfull = 1.0f - static_cast<float>(d_output[i]->space_available()) / + static_cast<float>(d_output[i]->bufsize()); + d_avg_output_buffers_full[i] = pfull; + d_var_output_buffers_full[i] = 0; + } } + else { + float d = diff - d_avg_work_time; + d_avg_work_time = d_avg_work_time + d/d_pc_counter; + d_var_work_time = d_var_work_time + d*d; + + d = nproduced - d_avg_nproduced; + d_avg_nproduced = d_avg_nproduced + d/d_pc_counter; + d_var_nproduced = d_var_nproduced + d*d; + + d = noutput_items - d_avg_noutput_items; + d_avg_noutput_items = d_avg_noutput_items + d/d_pc_counter; + d_var_noutput_items = d_var_noutput_items + d*d; + + for(size_t i=0; i < d_input.size(); i++) { + float pfull = static_cast<float>(d_input[i]->items_available()) / + static_cast<float>(d_input[i]->max_possible_items_available()); + + d = pfull - d_avg_input_buffers_full[i]; + d_avg_input_buffers_full[i] = d_avg_input_buffers_full[i] + d/d_pc_counter; + d_var_input_buffers_full[i] = d_var_input_buffers_full[i] + d*d; + } - for(size_t i=0; i < d_output.size(); i++) { - float pfull = 1.0f - static_cast<float>(d_output[i]->space_available()) / - static_cast<float>(d_output[i]->bufsize()); - d_avg_output_buffers_full[i] = beta*d_avg_output_buffers_full[i] + alpha*pfull; + for(size_t i=0; i < d_output.size(); i++) { + float pfull = 1.0f - static_cast<float>(d_output[i]->space_available()) / + static_cast<float>(d_output[i]->bufsize()); + + d = pfull - d_avg_output_buffers_full[i]; + d_avg_output_buffers_full[i] = d_avg_output_buffers_full[i] + d/d_pc_counter; + d_var_output_buffers_full[i] = d_var_output_buffers_full[i] + d*d; + } } + + d_pc_counter++; +} + +void +gr_block_detail::reset_perf_counters() +{ + d_pc_counter = 0; } float @@ -305,3 +353,58 @@ gr_block_detail::pc_work_time() { return d_avg_work_time; } + + +float +gr_block_detail::pc_noutput_items_var() +{ + return d_var_noutput_items/(d_pc_counter-1); +} + +float +gr_block_detail::pc_nproduced_var() +{ + return d_var_nproduced/(d_pc_counter-1); +} + +float +gr_block_detail::pc_input_buffers_full_var(size_t which) +{ + if(which < d_avg_input_buffers_full.size()) + return d_var_input_buffers_full[which]/(d_pc_counter-1); + else + return 0; +} + +std::vector<float> +gr_block_detail::pc_input_buffers_full_var() +{ + std::vector<float> var(d_avg_input_buffers_full.size(), 0); + for(size_t i = 0; i < d_avg_input_buffers_full.size(); i++) + var[i] = d_avg_input_buffers_full[i]/(d_pc_counter-1); + return var; +} + +float +gr_block_detail::pc_output_buffers_full_var(size_t which) +{ + if(which < d_avg_output_buffers_full.size()) + return d_var_output_buffers_full[which]/(d_pc_counter-1); + else + return 0; +} + +std::vector<float> +gr_block_detail::pc_output_buffers_full_var() +{ + std::vector<float> var(d_avg_output_buffers_full.size(), 0); + for(size_t i = 0; i < d_avg_output_buffers_full.size(); i++) + var[i] = d_avg_output_buffers_full[i]/(d_pc_counter-1); + return var; +} + +float +gr_block_detail::pc_work_time_var() +{ + return d_var_work_time/(d_pc_counter-1); +} diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.h b/gnuradio-core/src/lib/runtime/gr_block_detail.h index dd8be71c9c..32a01e763a 100644 --- a/gnuradio-core/src/lib/runtime/gr_block_detail.h +++ b/gnuradio-core/src/lib/runtime/gr_block_detail.h @@ -173,6 +173,7 @@ class GR_CORE_API gr_block_detail { void start_perf_counters(); void stop_perf_counters(int noutput_items, int nproduced); + void reset_perf_counters(); // Calls to get performance counter items float pc_noutput_items(); @@ -183,6 +184,14 @@ class GR_CORE_API gr_block_detail { std::vector<float> pc_output_buffers_full(); float pc_work_time(); + float pc_noutput_items_var(); + float pc_nproduced_var(); + float pc_input_buffers_full_var(size_t which); + std::vector<float> pc_input_buffers_full_var(); + float pc_output_buffers_full_var(size_t which); + std::vector<float> pc_output_buffers_full_var(); + float pc_work_time_var(); + gr_tpb_detail d_tpb; // used by thread-per-block scheduler int d_produce_or; @@ -197,11 +206,17 @@ class GR_CORE_API gr_block_detail { // Performance counters float d_avg_noutput_items; + float d_var_noutput_items; float d_avg_nproduced; + float d_var_nproduced; std::vector<float> d_avg_input_buffers_full; + std::vector<float> d_var_input_buffers_full; std::vector<float> d_avg_output_buffers_full; + std::vector<float> d_var_output_buffers_full; gruel::high_res_timer_type d_start_of_work, d_end_of_work; float d_avg_work_time; + float d_var_work_time; + float d_pc_counter; gr_block_detail (unsigned int ninputs, unsigned int noutputs); diff --git a/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py b/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py index f33160aca2..e2844b8bad 100644 --- a/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py +++ b/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py @@ -46,9 +46,7 @@ class GrDataPlotterC(gr.top_block): self.thr = gr.throttle(gr.sizeof_gr_complex, rate) self.snk = qtgui.time_sink_c(self._npts, samp_rate, self._name, 1) - - if(pmin is not None or not pmax is None): - self.snk.set_y_axis(pmin, pmax) + self.snk.enable_autoscale(True) self.connect(self.src, self.thr, (self.snk, 0)) @@ -121,9 +119,7 @@ class GrDataPlotterF(gr.top_block): self.thr = gr.throttle(gr.sizeof_float, rate) self.snk = qtgui.time_sink_f(self._npts, samp_rate, self._name, 1) - - if(pmin is not None or not pmax is None): - self.snk.set_y_axis(pmin, pmax) + self.snk.enable_autoscale(True) self.connect(self.src, self.thr, (self.snk, 0)) @@ -191,10 +187,7 @@ class GrDataPlotterConst(gr.top_block): self.thr = gr.throttle(gr.sizeof_gr_complex, rate) self.snk = qtgui.const_sink_c(self._npts, self._name, 1) - - if(pmin is not None or not pmax is None): - self.snk.set_x_axis(pmin, pmax) - self.snk.set_y_axis(pmin, pmax) + self.snk.enable_autoscale(True) self.connect(self.src, self.thr, (self.snk, 0)) @@ -268,9 +261,7 @@ class GrDataPlotterPsdC(gr.top_block): self.snk = qtgui.freq_sink_c(self._fftsize, self._wintype, self._fc, self._samp_rate, self._name, 1) - - if(pmin is not None or not pmax is None): - self.snk.set_y_axis(pmin, pmax) + self.snk.enable_autoscale(True) self.connect(self.src, self.thr, (self.snk, 0)) @@ -343,9 +334,7 @@ class GrDataPlotterPsdF(gr.top_block): self.snk = qtgui.freq_sink_f(self._fftsize, self._wintype, self._fc, self._samp_rate, self._name, 1) - - if(pmin is not None or not pmax is None): - self.snk.set_y_axis(pmin, pmax) + self.snk.enable_autoscale(True) self.connect(self.src, self.thr, (self.snk, 0)) @@ -401,6 +390,141 @@ class GrDataPlotterPsdF(gr.top_block): self.src.set_data(self._last_data) +class GrTimeRasterF(gr.top_block): + def __init__(self, name, rate, pmin=None, pmax=None): + gr.top_block.__init__(self) + + self._name = name + self._npts = 100 + self._rows = 100 + samp_rate = 1.0 + + self._last_data = self._npts*[0,] + self._data_len = 0 + + self.src = gr.vector_source_f([]) + self.thr = gr.throttle(gr.sizeof_float, rate) + self.snk = qtgui.time_raster_sink_f(samp_rate, self._npts, self._rows, + [], [], self._name, 1) + + self.connect(self.src, self.thr, (self.snk, 0)) + + self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + + def __del__(self): + pass + + def qwidget(self): + return self.py_window + + def name(self): + return self._name + + def update(self, data): + # Ask GUI if there has been a change in nsamps + npts = int(self.snk.num_cols()) + if(self._npts != npts): + + # Adjust buffers to accomodate new settings + if(npts < self._npts): + if(self._data_len < npts): + self._last_data = self._last_data[0:npts] + else: + self._last_data = self._last_data[self._data_len-npts:self._data_len] + self._data_len = npts + else: + self._last_data += (npts - self._npts)*[0,] + self._npts = npts + self.snk.reset() + + # Update the plot data depending on type + if(type(data) == list): + if(len(data) > self._npts): + self.src.set_data(data) + self._last_data = data[-self._npts:] + else: + newdata = self._last_data[-(self._npts-len(data)):] + newdata += data + self.src.set_data(newdata) + self._last_data = newdata + + else: # single value update + if(self._data_len < self._npts): + self._last_data[self._data_len] = data + self._data_len += 1 + else: + self._last_data = self._last_data[1:] + self._last_data.append(data) + self.src.set_data(self._last_data) + +class GrTimeRasterB(gr.top_block): + def __init__(self, name, rate, pmin=None, pmax=None): + gr.top_block.__init__(self) + + self._name = name + self._npts = 100 + self._rows = 100 + samp_rate = 1.0 + + self._last_data = self._npts*[0,] + self._data_len = 0 + + self.src = gr.vector_source_b([]) + self.thr = gr.throttle(gr.sizeof_char, rate) + self.snk = qtgui.time_raster_sink_b(samp_rate, self._npts, self._rows, + [], [], self._name, 1) + + self.connect(self.src, self.thr, (self.snk, 0)) + + self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + + def __del__(self): + pass + + def qwidget(self): + return self.py_window + + def name(self): + return self._name + + def update(self, data): + # Ask GUI if there has been a change in nsamps + npts = self.snk.num_cols() + if(self._npts != npts): + + # Adjust buffers to accomodate new settings + if(npts < self._npts): + if(self._data_len < npts): + self._last_data = self._last_data[0:npts] + else: + self._last_data = self._last_data[self._data_len-npts:self._data_len] + self._data_len = npts + else: + self._last_data += (npts - self._npts)*[0,] + self._npts = npts + self.snk.reset() + + # Update the plot data depending on type + if(type(data) == list): + if(len(data) > self._npts): + self.src.set_data(data) + self._last_data = data[-self._npts:] + else: + newdata = self._last_data[-(self._npts-len(data)):] + newdata += data + self.src.set_data(newdata) + self._last_data = newdata + + else: # single value update + if(self._data_len < self._npts): + self._last_data[self._data_len] = data + self._data_len += 1 + else: + self._last_data = self._last_data[1:] + self._last_data.append(data) + self.src.set_data(self._last_data) + + class GrDataPlotterValueTable: def __init__(self, uid, parent, x, y, xsize, ysize, headers=['Statistic Key ( Source Block :: Stat Name ) ', diff --git a/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor b/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor index b51888527b..ec31be209f 100755 --- a/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor +++ b/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor @@ -133,6 +133,12 @@ class MAINWindow(QtGui.QMainWindow): def newPlotterPsdCProxy(): self.newPlotPsdC(key, uid, title) + def newPlotterRasterFProxy(): + self.newPlotRasterF(key, uid, title, pmin, pmax) + + def newPlotterRasterBProxy(): + self.newPlotRasterB(key, uid, title, pmin, pmax) + menu = QtGui.QMenu(self) menu.setTitle("Item Actions") menu.setTearOffEnabled(False) @@ -140,14 +146,14 @@ class MAINWindow(QtGui.QMainWindow): # object properties menu.addAction("Properties", newUpdaterProxy) - # displays available if not complex + # displays available menu.addAction("Plot Time", newPlotterFProxy) - menu.addAction("Plot PSD", newPlotterPsdFProxy) - - # displays available if complex menu.addAction("Plot Time (cpx)", newPlotterCProxy) - menu.addAction("Plot Constellation", newPlotterConstProxy) + menu.addAction("Plot PSD", newPlotterPsdFProxy) menu.addAction("Plot PSD cpx", newPlotterPsdCProxy) + menu.addAction("Plot Constellation", newPlotterConstProxy) + menu.addAction("Plot Raster (real)", newPlotterRasterFProxy) + #menu.addAction("Plot Raster (bits)", newPlotterRasterBProxy) menu.popup(QtGui.QCursor.pos()) @@ -222,6 +228,14 @@ class MAINWindow(QtGui.QMainWindow): plot = GrDataPlotterPsdC(tag, 32e6, pmin, pmax) self.createPlot(plot, uid, title) + def newPlotRasterF(self, tag, uid, title="", pmin=None, pmax=None): + plot = GrTimeRasterF(tag, 32e6, pmin, pmax) + self.createPlot(plot, uid, title) + + def newPlotRasterB(self, tag, uid, title="", pmin=None, pmax=None): + plot = GrTimeRasterB(tag, 32e6, pmin, pmax) + self.createPlot(plot, uid, title) + def update(self, knobs, uid): #sys.stderr.write("KNOB KEYS: {0}\n".format(knobs.keys())) for plot in self.plots[uid]: diff --git a/gr-channels/examples/channel_tone_response.grc b/gr-channels/examples/channel_tone_response.grc new file mode 100644 index 0000000000..bd02f6000a --- /dev/null +++ b/gr-channels/examples/channel_tone_response.grc @@ -0,0 +1,762 @@ +<?xml version='1.0' encoding='ASCII'?> +<flow_graph> + <timestamp>Fri Feb 15 15:13:55 2013</timestamp> + <block> + <key>import</key> + <param> + <key>id</key> + <value>import_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>import</key> + <value>import math</value> + </param> + <param> + <key>_coordinate</key> + <value>(181, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>100e3</value> + </param> + <param> + <key>_coordinate</key> + <value>(273, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>ctrlport_monitor</key> + <param> + <key>id</key> + <value>ctrlport_monitor_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>en</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(374, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>qtgui_freq_sink_x</key> + <param> + <key>id</key> + <value>qtgui_freq_sink_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>name</key> + <value>QT GUI Plot</value> + </param> + <param> + <key>fftsize</key> + <value>1024</value> + </param> + <param> + <key>wintype</key> + <value>firdes.WIN_BLACKMAN_hARRIS</value> + </param> + <param> + <key>fc</key> + <value>0</value> + </param> + <param> + <key>bw</key> + <value>samp_rate</value> + </param> + <param> + <key>ymin</key> + <value>-140</value> + </param> + <param> + <key>ymax</key> + <value>10</value> + </param> + <param> + <key>nconnections</key> + <value>1</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1011, 21)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>channels_channel_model</key> + <param> + <key>id</key> + <value>channels_channel_model_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>noise_voltage</key> + <value>math.pow(10,n/10.0)</value> + </param> + <param> + <key>freq_offset</key> + <value>cfo</value> + </param> + <param> + <key>epsilon</key> + <value>fso</value> + </param> + <param> + <key>taps</key> + <value>1.0 + 1.0j</value> + </param> + <param> + <key>seed</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(737, 106)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>analog_sig_source_x</key> + <param> + <key>id</key> + <value>analog_sig_source_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>waveform</key> + <value>analog.GR_COS_WAVE</value> + </param> + <param> + <key>freq</key> + <value>samp_rate/4</value> + </param> + <param> + <key>amp</key> + <value>math.pow(10,amp/10)</value> + </param> + <param> + <key>offset</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(12, 106)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_throttle</key> + <param> + <key>id</key> + <value>gr_throttle_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>samples_per_second</key> + <value>samp_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(218, 138)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>qtgui_waterfall_sink_x</key> + <param> + <key>id</key> + <value>qtgui_waterfall_sink_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>name</key> + <value>QT GUI Plot</value> + </param> + <param> + <key>fftsize</key> + <value>1024</value> + </param> + <param> + <key>wintype</key> + <value>firdes.WIN_BLACKMAN_hARRIS</value> + </param> + <param> + <key>fc</key> + <value>0</value> + </param> + <param> + <key>bw</key> + <value>samp_rate</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(1011, 130)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>amp</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Sine Amplitude (dB)</value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>start</key> + <value>-100</value> + </param> + <param> + <key>stop</key> + <value>100</value> + </param> + <param> + <key>step</key> + <value>1</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(785, 227)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>fso</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Sampling Frequency Relative Offset</value> + </param> + <param> + <key>value</key> + <value>1.0</value> + </param> + <param> + <key>start</key> + <value>0.9</value> + </param> + <param> + <key>stop</key> + <value>1.1</value> + </param> + <param> + <key>step</key> + <value>.001</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(621, 227)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>n</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Noise Level (dB)</value> + </param> + <param> + <key>value</key> + <value>-12</value> + </param> + <param> + <key>start</key> + <value>-30</value> + </param> + <param> + <key>stop</key> + <value>30</value> + </param> + <param> + <key>step</key> + <value>.5</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(342, 226)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>fD</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Max Doppler Frequency (Hz)</value> + </param> + <param> + <key>value</key> + <value>125</value> + </param> + <param> + <key>start</key> + <value>0</value> + </param> + <param> + <key>stop</key> + <value>1000</value> + </param> + <param> + <key>step</key> + <value>1</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(13, 226)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>cfo</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Frequency Offset</value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>start</key> + <value>-20e3</value> + </param> + <param> + <key>stop</key> + <value>20e3</value> + </param> + <param> + <key>step</key> + <value>1</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(480, 225)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>id</key> + <value>K</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>K (Rician Factor)</value> + </param> + <param> + <key>value</key> + <value>4</value> + </param> + <param> + <key>start</key> + <value>0</value> + </param> + <param> + <key>stop</key> + <value>30</value> + </param> + <param> + <key>step</key> + <value>.1</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>gui_hint</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(195, 226)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>options</key> + <param> + <key>id</key> + <value>channel_tone_response</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value>Channel Tone Response</value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>qt_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>pre_hook</key> + <value>None</value> + </param> + <param> + <key>post_hook</key> + <value>None</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>channels_fading_model</key> + <param> + <key>id</key> + <value>channels_fading_model_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>N</key> + <value>8</value> + </param> + <param> + <key>fDTs</key> + <value>fD/samp_rate</value> + </param> + <param> + <key>LOS</key> + <value>True</value> + </param> + <param> + <key>K</key> + <value>K</value> + </param> + <param> + <key>seed</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(415, 106)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>channels_channel_model_0</source_block_id> + <sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>channels_channel_model_0</source_block_id> + <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>channels_fading_model_0</source_block_id> + <sink_block_id>channels_channel_model_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_throttle_0</source_block_id> + <sink_block_id>channels_fading_model_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>analog_sig_source_x_0</source_block_id> + <sink_block_id>gr_throttle_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-channels/grc/CMakeLists.txt b/gr-channels/grc/CMakeLists.txt index 9e77fcc4ef..cbbf75901c 100644 --- a/gr-channels/grc/CMakeLists.txt +++ b/gr-channels/grc/CMakeLists.txt @@ -20,6 +20,7 @@ install(FILES channels_block_tree.xml channels_channel_model.xml + channels_fading_model.xml DESTINATION ${GRC_BLOCKS_DIR} COMPONENT "channels_python" ) diff --git a/gr-channels/grc/channels_block_tree.xml b/gr-channels/grc/channels_block_tree.xml index 587eebb6e9..efa808fd53 100644 --- a/gr-channels/grc/channels_block_tree.xml +++ b/gr-channels/grc/channels_block_tree.xml @@ -31,5 +31,6 @@ <cat> <name>Channel Models</name> <block>channels_channel_model</block> + <block>channels_fading_model</block> </cat> </cat> diff --git a/gr-channels/grc/channels_fading_model.xml b/gr-channels/grc/channels_fading_model.xml new file mode 100644 index 0000000000..2b68cfa2ec --- /dev/null +++ b/gr-channels/grc/channels_fading_model.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Fading Model +################################################### + --> +<block> + <name>Fading Model</name> + <key>channels_fading_model</key> + <import>from gnuradio import channels</import> + <make>channels.fading_model( $N, $fDTs, $LOS, $K, $seed )</make> + <callback>set_fDTs($fDTs)</callback> + <callback>set_K($K)</callback> + <param> + <name>Num Sinusoids (SoS model)</name> + <key>N</key> + <value>8</value> + <type>int</type> + </param> + <param> + <name>Normalized Max Doppler (fD*Ts)</name> + <key>fDTs</key> + <value>10.0/samp_rate</value> + <type>real</type> + </param> + <param> + <name>LOS Model</name> + <key>LOS</key> + <type>enum</type> + <option> + <name>Rayleigh/NLOS</name> + <key>False</key> + <opt>hide_K:all</opt> + </option> + <option> + <name>Rician/LOS</name> + <key>True</key> + <opt>hide_K:</opt> + </option> + </param> + <param> + <name>Rician factor (K)</name> + <key>K</key> + <value>4.0</value> + <type>real</type> + <hide>$LOS.hide_K</hide> + </param> + <param> + <name>Seed</name> + <key>seed</key> + <value>0</value> + <type>int</type> + </param> + + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> + <doc> + This algorithm implements the method described in + Compact Rayleigh and Rician fading simulator based on random walk processes + A. Alimohammad S.F. Fard B.F. Cockburn C. Schlegel + 26th November 2008 + + int d_N=8; // number of sinusoids + float d_fDTs=0.01 // normalized maximum doppler frequency (f_doppler / f_samprate) + float d_K=4; // Rician factor (ratio of the specular power to the scattered power) + bool d_LOS=true; // LOS path exists? chooses Rician (LOS) vs Rayleigh (NLOS) model. + int seed=0; // noise seed + </doc> +</block> diff --git a/gr-channels/include/channels/CMakeLists.txt b/gr-channels/include/channels/CMakeLists.txt index a913b96819..c0c70e2b00 100644 --- a/gr-channels/include/channels/CMakeLists.txt +++ b/gr-channels/include/channels/CMakeLists.txt @@ -23,6 +23,7 @@ install(FILES api.h channel_model.h + fading_model.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/channels COMPONENT "channels_devel" ) diff --git a/gr-channels/include/channels/fading_model.h b/gr-channels/include/channels/fading_model.h new file mode 100644 index 0000000000..651b087eb7 --- /dev/null +++ b/gr-channels/include/channels/fading_model.h @@ -0,0 +1,75 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 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. + */ + +#ifndef INCLUDED_CHANNELS_FADING_MODEL_H +#define INCLUDED_CHANNELS_FADING_MODEL_H + +#include <channels/api.h> +#include <gr_sync_block.h> +#include <gr_types.h> + +namespace gr { + namespace channels { + + /*! + * \brief fading simulator + * \ingroup misc_blk + * + * This block implements a basic fading model simulator that can + * be used to help evaluate, design, and test various signals, + * waveforms, and algorithms. + * + */ + class CHANNELS_API fading_model : virtual public gr_sync_block + { + public: + // gr::channels::channel_model::sptr + typedef boost::shared_ptr<fading_model> sptr; + + /*! \brief Build the channel simulator. + * + * \param N The number of sinusiods to use in simulating the channel 8 is a good value + * \param fDTs normalized maximum doppler frequency, fD * Ts + * \param LOS include Line-of-Site path? selects between Rayleigh (NLOS) and Rician (LOS) models + * \param K Rician factor (ratio of the specular power to the scattered power) + * \param seed a random number to seed the noise generators + */ + static sptr make(unsigned int N, + float fDTs=0.01, + bool LOS=true, + float K=4, + int seed=0); + + virtual float fDTs() = 0; + virtual float K() = 0; + virtual float step() = 0; + + virtual void set_fDTs(float fDTs) = 0; + virtual void set_K(float K) = 0; + virtual void set_step(float step) = 0; + + }; + + } /* namespace channels */ +} /* namespace gr */ + +#endif /* INCLUDED_CHANNELS_FADING_MODEL_H */ diff --git a/gr-channels/lib/CMakeLists.txt b/gr-channels/lib/CMakeLists.txt index f895f25806..fe28d41672 100644 --- a/gr-channels/lib/CMakeLists.txt +++ b/gr-channels/lib/CMakeLists.txt @@ -44,6 +44,7 @@ endif(ENABLE_GR_CTRLPORT) ######################################################################## list(APPEND channels_sources channel_model_impl.cc + fading_model_impl.cc ) list(APPEND channels_libs diff --git a/gr-channels/lib/fading_model_impl.cc b/gr-channels/lib/fading_model_impl.cc new file mode 100644 index 0000000000..709c1c5713 --- /dev/null +++ b/gr-channels/lib/fading_model_impl.cc @@ -0,0 +1,207 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 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 "fading_model_impl.h" +#include <gr_io_signature.h> +#include <iostream> + +#include <boost/format.hpp> +#include <boost/random.hpp> + +#include <gr_fxpt.h> +#include <sincostable.h> + + +// FASTSINCOS: 0 = slow native, 1 = gr_fxpt impl, 2 = sincostable.h +#define FASTSINCOS 2 + + +namespace gr { + namespace channels { + + fading_model::sptr + fading_model::make( unsigned int N, float fDTs, bool LOS, float K, int seed ) + { + return gnuradio::get_initial_sptr + (new fading_model_impl( N, fDTs, LOS, K, seed)); + } + + // Block constructor + fading_model_impl::fading_model_impl( unsigned int N, float fDTs, bool LOS, float K, int seed ) + : gr_sync_block("fading_model", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex))), + seed_1((int)seed), + dist_1(-M_PI, M_PI), + rv_1( seed_1, dist_1 ), // U(-pi,pi) + + seed_2((int)seed+1), + dist_2(0, 1), + rv_2( seed_2, dist_2 ), // U(0,1) + + d_N(N), + d_fDTs(fDTs), + d_theta(rv_1()), + d_theta_los(rv_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(2.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] = rv_1(); + d_phi[i] = rv_1(); + } + } + + fading_model_impl::~fading_model_impl() + { + } + + void + fading_model_impl::setup_rpc() + { +#ifdef GR_CTRLPORT + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<fading_model, float >( + alias(), "fDTs", + &fading_model::fDTs, + pmt::mp(0), pmt::mp(1), pmt::mp(0.01), + "Hz*Sec", "normalized maximum doppler frequency (fD*Ts)", + RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<fading_model, float >( + alias(), "fDTs", + &fading_model::set_fDTs, + pmt::mp(0), pmt::mp(1), pmt::mp(0.01), + "Hz*Sec", "normalized maximum doppler frequency (fD*Ts)", + RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<fading_model, float >( + alias(), "K", + &fading_model::K, + pmt::mp(0), pmt::mp(8), pmt::mp(4), + "Ratio", "Rician factor (ratio of the specular power to the scattered power)", + RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<fading_model, float >( + alias(), "K", + &fading_model::set_K, + pmt::mp(0), pmt::mp(8), pmt::mp(4), + "Ratio", "Rician factor (ratio of the specular power to the scattered power)", + RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<fading_model, float >( + alias(), "step", + &fading_model::step, + pmt::mp(0), pmt::mp(8), pmt::mp(4), + "radians", "Maximum step size for random walk angle per sample", + RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<fading_model, float >( + alias(), "step", + &fading_model::set_step, + pmt::mp(0), pmt::mp(1), pmt::mp(0.00001), + "radians", "Maximum step size for random walk angle per sample", + RPC_PRIVLVL_MIN, DISPTIMESERIESF))); + +#endif /* GR_CTRLPORT */ + } + + void + fading_model_impl::update_theta() + { + d_theta += (d_step*rv_2()); + if(d_theta > M_PI){ + d_theta = M_PI; d_step = -d_step; + } else if(d_theta < -M_PI){ + d_theta = -M_PI; d_step = -d_step; + } + } + + int + fading_model_impl::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex* in = (const gr_complex*) input_items[0]; + gr_complex* out = (gr_complex*) output_items[0]; + + for(int i=0; i<noutput_items; i++){ + gr_complex H(0,0); + + for(int n=1; n<d_N; n++){ + float alpha_n = (2*M_PI*n - M_PI + d_theta)/4*d_N; +#if FASTSINCOS == 1 + float s_i = scale_sin*gr_fxpt::cos(gr_fxpt::float_to_fixed(2*M_PI*d_fDTs*d_m*gr_fxpt::cos(gr_fxpt::float_to_fixed(alpha_n))+d_psi[n+1])); + float s_q = scale_sin*gr_fxpt::cos(gr_fxpt::float_to_fixed(2*M_PI*d_fDTs*d_m*gr_fxpt::sin(gr_fxpt::float_to_fixed(alpha_n))+d_phi[n+1])); +#elif FASTSINCOS == 2 + float s_i = scale_sin*d_table.cos(2*M_PI*d_fDTs*d_m*d_table.cos(alpha_n)+d_psi[n+1]); + float s_q = scale_sin*d_table.cos(2*M_PI*d_fDTs*d_m*d_table.sin(alpha_n)+d_phi[n+1]); + +#else + float s_i = scale_sin*cos(2*M_PI*d_fDTs*d_m*cos(alpha_n)+d_psi[n+1]); + float s_q = scale_sin*cos(2*M_PI*d_fDTs*d_m*sin(alpha_n)+d_phi[n+1]); +#endif + + H += gr_complex(s_i, s_q); + } + + if(d_LOS){ +#if FASTSINCOS == 1 + float los_i = gr_fxpt::cos(gr_fxpt::float_to_fixed(2*M_PI*d_fDTs*d_m*gr_fxpt::cos(gr_fxpt::float_to_fixed(d_theta_los)) + d_psi[0])); + float los_q = gr_fxpt::sin(gr_fxpt::float_to_fixed(2*M_PI*d_fDTs*d_m*gr_fxpt::cos(gr_fxpt::float_to_fixed(d_theta_los)) + d_psi[0])); +#elif FASTSINCOS == 2 + float los_i = d_table.cos(2*M_PI*d_fDTs*d_m*d_table.cos(d_theta_los) + d_psi[0]); + float los_q = d_table.sin(2*M_PI*d_fDTs*d_m*d_table.cos(d_theta_los) + d_psi[0]); +#else + float los_i = cos(2*M_PI*d_fDTs*d_m*cos(d_theta_los) + d_psi[0]); + float los_q = sin(2*M_PI*d_fDTs*d_m*cos(d_theta_los) + d_psi[0]); +#endif + + H = H*scale_nlos + gr_complex(los_i,los_q)*scale_los; + } + + out[i] = in[i]*H; + d_m++; + update_theta(); + + } + + return noutput_items; + } + + + } /* namespace channels */ +} /* namespace gr */ diff --git a/gr-channels/lib/fading_model_impl.h b/gr-channels/lib/fading_model_impl.h new file mode 100644 index 0000000000..5c2d7f3877 --- /dev/null +++ b/gr-channels/lib/fading_model_impl.h @@ -0,0 +1,94 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 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. + */ + +#ifndef INCLUDED_CHANNELS_CHANNEL_MODEL_IMPL_H +#define INCLUDED_CHANNELS_CHANNEL_MODEL_IMPL_H + +#include <gr_sync_block.h> +#include <channels/fading_model.h> + +//#include <iostream> +#include <boost/format.hpp> +#include <boost/random.hpp> + +#include <gr_fxpt.h> +#include <sincostable.h> + +namespace gr { + namespace channels { + + class CHANNELS_API fading_model_impl : public fading_model + { + private: + // initial theta variate generator + boost::mt19937 seed_1; + boost::uniform_real<> dist_1; // U(-pi,pi) + boost::variate_generator<boost::mt19937&, boost::uniform_real<> > rv_1; + + // random walk variate + boost::mt19937 seed_2; + boost::uniform_real<> dist_2; // U(-pi,pi) + boost::variate_generator<boost::mt19937&, boost::uniform_real<> > rv_2; + + int d_N; // number of sinusoids + float d_fDTs; // normalized maximum doppler frequency + double d_theta; // random walk variable (RWP) + float d_theta_los; + float d_step; // maximum random walk step size + uint64_t d_m; // sample counter + + float d_K; // Rician factor (ratio of the specular power to the scattered power) + bool d_LOS; // LOS path exists? chooses Rician (LOS) vs Rayleigh (NLOS) model. + + std::vector<float> d_psi; // in-phase initial phase + std::vector<float> d_phi; // quadrature initial phase + + std::vector<float> d_costable; + + sincostable d_table; + + float scale_sin, scale_los, scale_nlos; + + void update_theta(); + + public: + fading_model_impl(unsigned int N, float fDTs, bool LOS, float K, int seed); + ~fading_model_impl(); + void setup_rpc(); + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + virtual float fDTs(){ return d_fDTs; } + virtual float K(){ return d_K; } + virtual float step(){ return d_step; } + + virtual void set_fDTs(float fDTs){ d_fDTs = fDTs; d_step = powf(0.00125*fDTs, 1.1); } + virtual void set_K(float K){ d_K = K; scale_los = sqrtf(d_K)/sqrtf(d_K+1); scale_nlos = (1/sqrtf(d_K+1)); } + virtual void set_step(float step){ d_step = step; } + + }; + + } /* namespace channels */ +} /* namespace gr */ + +#endif /* INCLUDED_CHANNELS_CHANNEL_MODEL_IMPL_H */ diff --git a/gr-channels/lib/sincostable.h b/gr-channels/lib/sincostable.h new file mode 100644 index 0000000000..ca4bc4688b --- /dev/null +++ b/gr-channels/lib/sincostable.h @@ -0,0 +1,30 @@ +#ifndef SINCOSTABLE_H +#define SINCOSTABLE_H + +#include <math.h> + +class sincostable { + std::vector<float> d_cos; + size_t d_sz; + float d_scale; + public: + sincostable(size_t tbl_size) : + d_cos(tbl_size,1), + d_sz(tbl_size), + d_scale(tbl_size/(M_PI*2)) + { + for(size_t i=0; i<tbl_size; i++){ + d_cos[i] = ::cos(2*M_PI*i/tbl_size); + } + } + const float sin(float x){ + int idx = (((int)(x*d_scale)) + d_sz - d_sz/4 )% d_sz; + return d_cos[idx]; + } + const float cos(float x){ + int idx = (((int)(x*d_scale)) + d_sz) % d_sz; + return d_cos[idx]; + } +}; + +#endif diff --git a/gr-channels/python/qa_fading_model.py b/gr-channels/python/qa_fading_model.py new file mode 100644 index 0000000000..e8a066ccb5 --- /dev/null +++ b/gr-channels/python/qa_fading_model.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# Copyright 2012 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. +# + +from gnuradio import gr, gr_unittest +import analog_swig as analog +import channels_swig as channels +import math + +class test_fading_model(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_000(self): + N = 1000 # number of samples to use + fs = 1000 # baseband sampling rate + freq = 100 + + fDTs = 0.01 + K = 4 + signal = analog.sig_source_c(fs, analog.GR_SIN_WAVE, freq, 1) + head = gr.head(gr.sizeof_gr_complex, N) + op = channels.fading_model(8, fDTs=fDTs, LOS=True, + K=K, seed=0) + snk = gr.vector_sink_c() + snk1 = gr.vector_sink_c() + + self.assertAlmostEqual(K, op.K(), 4) + self.assertAlmostEqual(fDTs, op.fDTs(), 4) + + #self.tb.connect(signal, head, op, snk) + #self.tb.connect(op, snk1) + #self.tb.run() + + #dst_data = snk.data() + #exp_data = snk1.data() + #self.assertComplexTuplesAlmostEqual(exp_data, dst_data, 5) + +if __name__ == '__main__': + gr_unittest.run(test_fading_model, "test_fading_model.xml") diff --git a/gr-channels/swig/channels_swig.i b/gr-channels/swig/channels_swig.i index 364f8d0fbd..fb284a74bd 100644 --- a/gr-channels/swig/channels_swig.i +++ b/gr-channels/swig/channels_swig.i @@ -29,8 +29,11 @@ %{ #include "channels/channel_model.h" +#include "channels/fading_model.h" %} %include "channels/channel_model.h" +%include "channels/fading_model.h" GR_SWIG_BLOCK_MAGIC2(channels, channel_model); +GR_SWIG_BLOCK_MAGIC2(channels, fading_model); diff --git a/gr-filter/lib/pfb_synthesizer_ccf_impl.cc b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc index 9dd519d57c..f89b48b125 100644 --- a/gr-filter/lib/pfb_synthesizer_ccf_impl.cc +++ b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc @@ -47,8 +47,8 @@ namespace gr { : gr_sync_interpolator("pfb_synthesizer_ccf", gr_make_io_signature(1, numchans, sizeof(gr_complex)), gr_make_io_signature(1, 1, sizeof(gr_complex)), - numchans), - d_updated (false), d_numchans(numchans), d_state(0) + (twox ? numchans/2 : numchans)), + d_updated(false), d_numchans(numchans), d_state(0) { // set up 2x multiplier; if twox==True, set to 2, otherwise to 1 d_twox = (twox ? 2 : 1); @@ -56,12 +56,12 @@ namespace gr { throw std::invalid_argument("pfb_synthesizer_ccf: number of channels must be even for 2x oversampling.\n"); } - d_filters = std::vector<kernel::fir_filter_with_buffer_ccf*>(d_twox*d_numchans); - d_channel_map.resize(d_twox*d_numchans); + d_filters = std::vector<kernel::fir_filter_with_buffer_ccf*>(d_numchans); + d_channel_map.resize(d_numchans); // Create a FIR filter for each channel and zero out the taps - std::vector<float> vtaps(0, d_twox*d_numchans); - for(unsigned int i = 0; i < d_twox*d_numchans; i++) { + std::vector<float> vtaps(0, d_numchans); + for(unsigned int i = 0; i < d_numchans; i++) { d_filters[i] = new kernel::fir_filter_with_buffer_ccf(vtaps); d_channel_map[i] = i; } @@ -70,15 +70,15 @@ namespace gr { set_taps(taps); // Create the IFFT to handle the input channel rotations - d_fft = new fft::fft_complex(d_twox*d_numchans, false); - memset(d_fft->get_inbuf(), 0, d_twox*d_numchans*sizeof(gr_complex)); + d_fft = new fft::fft_complex(d_numchans, false); + memset(d_fft->get_inbuf(), 0, d_numchans*sizeof(gr_complex)); set_output_multiple(d_numchans); } pfb_synthesizer_ccf_impl::~pfb_synthesizer_ccf_impl() { - for(unsigned int i = 0; i < d_twox*d_numchans; i++) { + for(unsigned int i = 0; i < d_numchans; i++) { delete d_filters[i]; } } @@ -137,11 +137,11 @@ namespace gr { unsigned int i,j; int state = 0; - unsigned int ntaps = taps.size(); + unsigned int ntaps = 2*taps.size(); d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_numchans); // Create d_numchan vectors to store each channel's taps - d_taps.resize(d_twox*d_numchans); + d_taps.resize(d_numchans); // Make a vector of the taps plus fill it out with 0's to fill // each polyphase filter with exactly d_taps_per_filter @@ -152,29 +152,30 @@ namespace gr { } // Partition the filter - for(i = 0; i < d_numchans; i++) { + unsigned int halfchans = d_numchans/2; + for(i = 0; i < halfchans; i++) { // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out d_taps[i] = std::vector<float>(d_taps_per_filter, 0); - d_taps[d_numchans+i] = std::vector<float>(d_taps_per_filter, 0); + d_taps[halfchans+i] = std::vector<float>(d_taps_per_filter, 0); state = 0; for(j = 0; j < d_taps_per_filter; j++) { // add taps to channels in reverse order // Zero out every other tap if(state == 0) { - d_taps[i][j] = tmp_taps[i + j*d_numchans]; - d_taps[d_numchans + i][j] = 0; + d_taps[i][j] = tmp_taps[i + j*halfchans]; + d_taps[halfchans + i][j] = 0; state = 1; } else { d_taps[i][j] = 0; - d_taps[d_numchans + i][j] = tmp_taps[i + j*d_numchans]; + d_taps[halfchans + i][j] = tmp_taps[i + j*halfchans]; state = 0; } } // Build a filter for each channel and add it's taps to it d_filters[i]->set_taps(d_taps[i]); - d_filters[d_numchans + i]->set_taps(d_taps[d_numchans + i]); + d_filters[halfchans + i]->set_taps(d_taps[halfchans + i]); } } @@ -182,7 +183,7 @@ namespace gr { pfb_synthesizer_ccf_impl::print_taps() { unsigned int i, j; - for(i = 0; i < d_twox*d_numchans; i++) { + for(i = 0; i < d_numchans; i++) { printf("filter[%d]: [", i); for(j = 0; j < d_taps_per_filter; j++) { printf(" %.4e", d_taps[i][j]); @@ -204,13 +205,13 @@ namespace gr { if(map.size() > 0) { unsigned int max = (unsigned int)*std::max_element(map.begin(), map.end()); - if(max >= d_twox*d_numchans) { + if(max >= d_numchans) { throw std::invalid_argument("gr_pfb_synthesizer_ccf::set_channel_map: map range out of bounds.\n"); } d_channel_map = map; // Zero out fft buffer so that unused channels are always 0 - memset(d_fft->get_inbuf(), 0,d_twox*d_numchans*sizeof(gr_complex)); + memset(d_fft->get_inbuf(), 0, d_numchans*sizeof(gr_complex)); } } @@ -258,7 +259,8 @@ namespace gr { // Algorithm for oversampling by 2x else { - for(n = 0; n < noutput_items/d_numchans; n++) { + unsigned int halfchans = d_numchans/2; + for(n = 0; n < noutput_items/halfchans; n++) { for(i = 0; i < ninputs; i++) { in = (gr_complex*)input_items[i]; d_fft->get_inbuf()[d_channel_map[i]] = in[n]; @@ -270,13 +272,13 @@ namespace gr { // Output is sum of two filters, but the input buffer to the filters must be circularly // shifted by numchans every time through, done by using d_state to determine which IFFT // buffer position to pull from. - for(i = 0; i < d_numchans; i++) { - out[i] = d_filters[i]->filter(d_fft->get_outbuf()[d_state*d_numchans+i]); - out[i] += d_filters[d_numchans+i]->filter(d_fft->get_outbuf()[(d_state^1)*d_numchans+i]); + for(i = 0; i < halfchans; i++) { + out[i] = d_filters[i]->filter(d_fft->get_outbuf()[d_state*halfchans+i]); + out[i] += d_filters[halfchans+i]->filter(d_fft->get_outbuf()[(d_state^1)*halfchans+i]); } d_state ^= 1; - out += d_numchans; + out += halfchans; } } diff --git a/gr-qtgui/grc/qtgui_const_sink_x.xml b/gr-qtgui/grc/qtgui_const_sink_x.xml index 31b13fe136..c751c89437 100644 --- a/gr-qtgui/grc/qtgui_const_sink_x.xml +++ b/gr-qtgui/grc/qtgui_const_sink_x.xml @@ -16,12 +16,13 @@ qtgui.$(type.fcn)( $name, \#name $nconnections \#number of inputs ) +self.$(id).set_update_time($update_time) self.$(id).set_y_axis($ymin, $ymax) self.$(id).set_x_axis($xmin, $xmax) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) $(gui_hint()($win))</make> <callback>set_resize($width, $height)</callback> - <callback>set_update_time($t)</callback> + <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> <callback>set_color($which, $color)</callback> <param> @@ -80,6 +81,13 @@ $(gui_hint()($win))</make> <hide>part</hide> </param> <param> + <name>Update Period</name> + <key>update_time</key> + <value>0.10</value> + <type>real</type> + <hide>part</hide> + </param> + <param> <name>GUI Hint</name> <key>gui_hint</key> <value></value> diff --git a/gr-qtgui/grc/qtgui_freq_sink_x.xml b/gr-qtgui/grc/qtgui_freq_sink_x.xml index 0844a7cbc9..ce229b03de 100644 --- a/gr-qtgui/grc/qtgui_freq_sink_x.xml +++ b/gr-qtgui/grc/qtgui_freq_sink_x.xml @@ -20,11 +20,12 @@ qtgui.$(type.fcn)( $name, \#name $nconnections \#number of inputs ) +self.$(id).set_update_time($update_time) self.$(id).set_y_axis($ymin, $ymax) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) $(gui_hint()($win))</make> <callback>set_frequency_range($fc, $bw)</callback> - <callback>set_update_time($t)</callback> + <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> <callback>set_color($which, $color)</callback> <param> @@ -91,12 +92,6 @@ $(gui_hint()($win))</make> <type>real</type> </param> <param> - <name>Update Rate</name> - <key>rate</key> - <value>10</value> - <type>real</type> - </param> - <param> <name>Y min</name> <key>ymin</key> <value>-140</value> @@ -118,6 +113,13 @@ $(gui_hint()($win))</make> <hide>part</hide> </param> <param> + <name>Update Period</name> + <key>update_time</key> + <value>0.10</value> + <type>real</type> + <hide>part</hide> + </param> + <param> <name>GUI Hint</name> <key>gui_hint</key> <value></value> diff --git a/gr-qtgui/grc/qtgui_time_raster_x.xml b/gr-qtgui/grc/qtgui_time_raster_x.xml index e50810f29a..7d880ab084 100644 --- a/gr-qtgui/grc/qtgui_time_raster_x.xml +++ b/gr-qtgui/grc/qtgui_time_raster_x.xml @@ -20,13 +20,14 @@ qtgui.$(type.fcn)( $name, $nconnections, ) +self.$(id).set_update_time($update_time) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) $(gui_hint()($win))</make> <callback>set_num_rows($nrows)</callback> <callback>set_num_cols($ncols)</callback> <callback>set_multiplier($mult)</callback> <callback>set_offset($offset)</callback> - <callback>set_update_time($t)</callback> + <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> <callback>set_color($which, $color)</callback> <param> @@ -46,7 +47,7 @@ $(gui_hint()($win))</make> <param> <name>Sample Rate</name> <key>samp_rate</key> - <value>1</value> + <value>samp_rate</value> <type>real</type> </param> <param> @@ -81,10 +82,11 @@ $(gui_hint()($win))</make> <hide>part</hide> </param> <param> - <name>Update Rate</name> - <key>rate</key> - <value>10</value> + <name>Update Period</name> + <key>update_time</key> + <value>0.10</value> <type>real</type> + <hide>part</hide> </param> <param> <name>GUI Hint</name> diff --git a/gr-qtgui/grc/qtgui_time_sink_x.xml b/gr-qtgui/grc/qtgui_time_sink_x.xml index 7b15aa840a..b02555b733 100644 --- a/gr-qtgui/grc/qtgui_time_sink_x.xml +++ b/gr-qtgui/grc/qtgui_time_sink_x.xml @@ -18,11 +18,12 @@ qtgui.$(type.fcn)( $name, \#name $nconnections \#number of inputs ) +self.$(id).set_update_time($update_time) self.$(id).set_y_axis($ymin, $ymax) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) $(gui_hint()($win))</make> <callback>set_time_domain_axis($min, $max)</callback> - <callback>set_update_time($t)</callback> + <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> <callback>set_color($which, $color)</callback> <callback>set_y_axis($ymin, $ymax)</callback> @@ -75,6 +76,13 @@ $(gui_hint()($win))</make> <hide>part</hide> </param> <param> + <name>Update Period</name> + <key>update_time</key> + <value>0.10</value> + <type>real</type> + <hide>part</hide> + </param> + <param> <name>GUI Hint</name> <key>gui_hint</key> <value></value> diff --git a/gr-qtgui/grc/qtgui_waterfall_sink_x.xml b/gr-qtgui/grc/qtgui_waterfall_sink_x.xml index 47de5b593c..d49b4db224 100644 --- a/gr-qtgui/grc/qtgui_waterfall_sink_x.xml +++ b/gr-qtgui/grc/qtgui_waterfall_sink_x.xml @@ -19,10 +19,11 @@ qtgui.$(type.fcn)( $bw, \#bw $name, \#name ) +self.$(id).set_update_time($update_time) self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) $(gui_hint()($win))</make> <callback>set_frequency_range($fc, $bw)</callback> - <callback>set_update_time($t)</callback> + <callback>set_update_time($update_time)</callback> <callback>set_title($which, $title)</callback> <callback>set_color($which, $color)</callback> <param> @@ -89,10 +90,11 @@ $(gui_hint()($win))</make> <type>real</type> </param> <param> - <name>Update Rate</name> - <key>rate</key> - <value>10</value> + <name>Update Period</name> + <key>update_time</key> + <value>0.10</value> <type>real</type> + <hide>part</hide> </param> <param> <name>GUI Hint</name> diff --git a/gr-qtgui/include/qtgui/const_sink_c.h b/gr-qtgui/include/qtgui/const_sink_c.h index 9a9783bed4..e0c358bcad 100644 --- a/gr-qtgui/include/qtgui/const_sink_c.h +++ b/gr-qtgui/include/qtgui/const_sink_c.h @@ -84,6 +84,7 @@ namespace gr { virtual void set_size(int width, int height) = 0; virtual void enable_menu(bool en=true) = 0; + virtual void enable_autoscale(bool en) = 0; virtual int nsamps() const = 0; virtual void reset() = 0; diff --git a/gr-qtgui/include/qtgui/freq_sink_c.h b/gr-qtgui/include/qtgui/freq_sink_c.h index 37a12440a0..79d3f2e8f0 100644 --- a/gr-qtgui/include/qtgui/freq_sink_c.h +++ b/gr-qtgui/include/qtgui/freq_sink_c.h @@ -100,6 +100,7 @@ namespace gr { virtual void enable_menu(bool en=true) = 0; virtual void enable_grid(bool en=true) = 0; + virtual void enable_autoscale(bool en=true) = 0; virtual void reset() = 0; QApplication *d_qApplication; diff --git a/gr-qtgui/include/qtgui/freq_sink_f.h b/gr-qtgui/include/qtgui/freq_sink_f.h index 4682f73c10..131801f531 100644 --- a/gr-qtgui/include/qtgui/freq_sink_f.h +++ b/gr-qtgui/include/qtgui/freq_sink_f.h @@ -99,6 +99,7 @@ namespace gr { virtual void enable_menu(bool en=true) = 0; virtual void enable_grid(bool en=true) = 0; + virtual void enable_autoscale(bool en=true) = 0; virtual void reset() = 0; QApplication *d_qApplication; diff --git a/gr-qtgui/include/qtgui/time_raster_sink_b.h b/gr-qtgui/include/qtgui/time_raster_sink_b.h index 51de65c9cf..1b65646b81 100644 --- a/gr-qtgui/include/qtgui/time_raster_sink_b.h +++ b/gr-qtgui/include/qtgui/time_raster_sink_b.h @@ -86,11 +86,16 @@ namespace gr { virtual void set_num_rows(double rows) = 0; virtual void set_num_cols(double cols) = 0; + virtual double num_rows() = 0; + virtual double num_cols() = 0; + virtual void set_multiplier(const std::vector<float> &mult) = 0; virtual void set_offset(const std::vector<float> &offset) = 0; virtual void set_intensity_range(float min, float max) = 0; + virtual void reset() = 0; + QApplication *d_qApplication; }; diff --git a/gr-qtgui/include/qtgui/time_raster_sink_f.h b/gr-qtgui/include/qtgui/time_raster_sink_f.h index 075b4239cc..1ae4d79bda 100644 --- a/gr-qtgui/include/qtgui/time_raster_sink_f.h +++ b/gr-qtgui/include/qtgui/time_raster_sink_f.h @@ -83,11 +83,16 @@ namespace gr { virtual void set_num_rows(double rows) = 0; virtual void set_num_cols(double cols) = 0; + virtual double num_rows() = 0; + virtual double num_cols() = 0; + virtual void set_multiplier(const std::vector<float> &mult) = 0; virtual void set_offset(const std::vector<float> &offset) = 0; virtual void set_intensity_range(float min, float max) = 0; + virtual void reset() = 0; + QApplication *d_qApplication; }; diff --git a/gr-qtgui/include/qtgui/time_sink_c.h b/gr-qtgui/include/qtgui/time_sink_c.h index ef72f7df58..c6a9a5f4f3 100644 --- a/gr-qtgui/include/qtgui/time_sink_c.h +++ b/gr-qtgui/include/qtgui/time_sink_c.h @@ -89,6 +89,7 @@ namespace gr { virtual void enable_menu(bool en=true) = 0; virtual void enable_grid(bool en=true) = 0; + virtual void enable_autoscale(bool en=true) = 0; virtual void toggle_stem_plot() = 0; virtual int nsamps() const = 0; virtual void reset() = 0; diff --git a/gr-qtgui/include/qtgui/time_sink_f.h b/gr-qtgui/include/qtgui/time_sink_f.h index 6f689e7b60..c17d60c820 100644 --- a/gr-qtgui/include/qtgui/time_sink_f.h +++ b/gr-qtgui/include/qtgui/time_sink_f.h @@ -87,6 +87,7 @@ namespace gr { virtual void enable_menu(bool en=true) = 0; virtual void enable_grid(bool en=true) = 0; + virtual void enable_autoscale(bool en=true) = 0; virtual void toggle_stem_plot() = 0; virtual int nsamps() const = 0; virtual void reset() = 0; diff --git a/gr-qtgui/lib/FrequencyDisplayPlot.cc b/gr-qtgui/lib/FrequencyDisplayPlot.cc index a04a9886d4..e279155544 100644 --- a/gr-qtgui/lib/FrequencyDisplayPlot.cc +++ b/gr-qtgui/lib/FrequencyDisplayPlot.cc @@ -393,7 +393,7 @@ FrequencyDisplayPlot::plotNewData(const double* dataPoints, plotNewData(vecDataPoints, numDataPoints, noiseFloorAmplitude, peakFrequency, peakAmplitude, timeInterval); } - + void FrequencyDisplayPlot::clearMaxData() { diff --git a/gr-qtgui/lib/TimeRasterDisplayPlot.cc b/gr-qtgui/lib/TimeRasterDisplayPlot.cc index 84ec31f6ef..537a7e4ef7 100644 --- a/gr-qtgui/lib/TimeRasterDisplayPlot.cc +++ b/gr-qtgui/lib/TimeRasterDisplayPlot.cc @@ -93,15 +93,41 @@ private: double _rows; }; +class TimePrecisionClass +{ +public: + TimePrecisionClass(const int timePrecision) + { + _timePrecision = timePrecision; + } + + virtual ~TimePrecisionClass() + { + } + + virtual unsigned int getTimePrecision() const + { + return _timePrecision; + } + + virtual void setTimePrecision(const unsigned int newPrecision) + { + _timePrecision = newPrecision; + } +protected: + unsigned int _timePrecision; +}; /*********************************************************************** * Widget to provide mouse pointer coordinate text **********************************************************************/ -class TimeRasterZoomer: public QwtPlotZoomer, public TimeScaleData +class TimeRasterZoomer: public QwtPlotZoomer, public TimePrecisionClass, + public TimeScaleData { public: - TimeRasterZoomer(QwtPlotCanvas* canvas, double rows, double cols) - : QwtPlotZoomer(canvas), TimeScaleData(), + TimeRasterZoomer(QwtPlotCanvas* canvas, double rows, double cols, + const unsigned int timePrecision) + : QwtPlotZoomer(canvas), TimePrecisionClass(timePrecision), TimeScaleData(), d_rows(static_cast<double>(rows)), d_cols(static_cast<double>(cols)) { setTrackerMode(QwtPicker::AlwaysOn); @@ -139,8 +165,9 @@ protected: double x = dp.x() * getSecondsPerLine(); //double y = dp.y() * getSecondsPerLine() * d_cols; double y = floor(d_rows - dp.y()); - QwtText t(QString("%1 s, %2") - .arg(x, 0, 'f', 2) + QwtText t(QString("%1 %2, %3") + .arg(x, 0, 'f', getTimePrecision()) + .arg(_unitType.c_str()) .arg(y, 0, 'f', 0)); return t; } @@ -171,13 +198,6 @@ TimeRasterDisplayPlot::TimeRasterDisplayPlot(int nplots, setAxisScaleDraw(QwtPlot::xBottom, new QwtXScaleDraw()); setAxisScaleDraw(QwtPlot::yLeft, new QwtYScaleDraw()); - double sec_per_samp = 1.0/d_samp_rate; - QwtYScaleDraw* yScale = (QwtYScaleDraw*)axisScaleDraw(QwtPlot::yLeft); - yScale->setRows(d_rows); - - QwtXScaleDraw* xScale = (QwtXScaleDraw*)axisScaleDraw(QwtPlot::xBottom); - xScale->setSecondsPerLine(sec_per_samp); - for(int i = 0; i < _nplots; i++) { d_data.push_back(new TimeRasterData(d_rows, d_cols)); d_raster.push_back(new PlotTimeRaster("Raster")); @@ -200,7 +220,7 @@ TimeRasterDisplayPlot::TimeRasterDisplayPlot(int nplots, // MidButton for the panning // RightButton: zoom out by 1 // Ctrl+RighButton: zoom out to full size - _zoomer = new TimeRasterZoomer(canvas(), d_rows, d_cols); + _zoomer = new TimeRasterZoomer(canvas(), d_rows, d_cols, 0); #if QWT_VERSION < 0x060000 _zoomer->setSelectionFlags(QwtPicker::RectSelection | QwtPicker::DragSelection); #endif @@ -238,22 +258,32 @@ TimeRasterDisplayPlot::reset() d_data[i]->reset(); } - setAxisScale(QwtPlot::xBottom, 0, d_rows); - setAxisScale(QwtPlot::yLeft, 0, d_cols); + // Update zoomer/picker text units + std::string strunits[4] = {"sec", "ms", "us", "ns"}; + double units10 = floor(log10(d_samp_rate)); + double units3 = std::max(floor(units10/3), 0.0); + double units = pow(10, (units10-fmod(units10, 3.0))); + int iunit = static_cast<int>(units3); + + double sec_per_samp = units/d_samp_rate; - double sec_per_samp = 1.0/d_samp_rate; QwtYScaleDraw* yScale = (QwtYScaleDraw*)axisScaleDraw(QwtPlot::yLeft); yScale->setRows(d_rows); QwtXScaleDraw* xScale = (QwtXScaleDraw*)axisScaleDraw(QwtPlot::xBottom); xScale->setSecondsPerLine(sec_per_samp); + setAxisTitle(QwtPlot::xBottom, QString("Time (%1)") + .arg(strunits[iunit].c_str())); + xScale->initiateUpdate(); // Load up the new base zoom settings if(_zoomer) { + double display_units = 4; ((TimeRasterZoomer*)_zoomer)->setColumns(d_cols); ((TimeRasterZoomer*)_zoomer)->setRows(d_rows); ((TimeRasterZoomer*)_zoomer)->setSecondsPerLine(sec_per_samp); - //((TimeRasterZoomer*)_zoomer)-sSetUnitType(strunits); + ((TimeRasterZoomer*)_zoomer)->setTimePrecision(display_units); + ((TimeRasterZoomer*)_zoomer)->setUnitType(strunits[iunit]); QwtDoubleRect newSize = _zoomer->zoomBase(); newSize.setLeft(0); @@ -287,6 +317,13 @@ TimeRasterDisplayPlot::setAlpha(int which, int alpha) d_raster[which]->setAlpha(alpha); } +void +TimeRasterDisplayPlot::setSampleRate(double samprate) +{ + d_samp_rate = samprate; + reset(); +} + double TimeRasterDisplayPlot::numRows() const { diff --git a/gr-qtgui/lib/TimeRasterDisplayPlot.h b/gr-qtgui/lib/TimeRasterDisplayPlot.h index 3e0ac1cfdb..fca9672b91 100644 --- a/gr-qtgui/lib/TimeRasterDisplayPlot.h +++ b/gr-qtgui/lib/TimeRasterDisplayPlot.h @@ -54,6 +54,7 @@ public: void setNumRows(double rows); void setNumCols(double cols); void setAlpha(int which, int alpha); + void setSampleRate(double samprate); double numRows() const; double numCols() const; diff --git a/gr-qtgui/lib/const_sink_c_impl.cc b/gr-qtgui/lib/const_sink_c_impl.cc index 2490e9a618..9b01d1659e 100644 --- a/gr-qtgui/lib/const_sink_c_impl.cc +++ b/gr-qtgui/lib/const_sink_c_impl.cc @@ -104,7 +104,6 @@ namespace gr { d_main_gui->setNPoints(d_size); // initialize update time to 10 times a second set_update_time(0.1); - d_last_time = 0; } void @@ -146,6 +145,7 @@ namespace gr { gruel::high_res_timer_type tps = gruel::high_res_timer_tps(); d_update_time = t * tps; d_main_gui->setUpdateTime(t); + d_last_time = 0; } void @@ -284,6 +284,12 @@ namespace gr { } void + const_sink_c_impl::enable_autoscale(bool en) + { + d_main_gui->autoScale(en); + } + + void const_sink_c_impl::reset() { d_index = 0; diff --git a/gr-qtgui/lib/const_sink_c_impl.h b/gr-qtgui/lib/const_sink_c_impl.h index 3e90d00429..81cdb9881f 100644 --- a/gr-qtgui/lib/const_sink_c_impl.h +++ b/gr-qtgui/lib/const_sink_c_impl.h @@ -92,6 +92,7 @@ namespace gr { int nsamps() const; void enable_menu(bool en); + void enable_autoscale(bool en); void reset(); int work(int noutput_items, diff --git a/gr-qtgui/lib/constellationdisplayform.cc b/gr-qtgui/lib/constellationdisplayform.cc index 361c5a71c9..9fa22cb306 100644 --- a/gr-qtgui/lib/constellationdisplayform.cc +++ b/gr-qtgui/lib/constellationdisplayform.cc @@ -122,3 +122,24 @@ ConstellationDisplayForm::autoScale() getPlot()->setAutoScale(_autoscale_state); getPlot()->replot(); } + +void +ConstellationDisplayForm::autoScale(bool en) +{ + if(en) { + _autoscale_act->setText(tr("Auto Scale Off")); + _autoscale_state = true; + } + else { + _autoscale_act->setText(tr("Auto Scale On")); + _autoscale_state = false; + } + + getPlot()->setAutoScale(_autoscale_state); + getPlot()->replot(); +} + +void +ConstellationDisplayForm::setSampleRate(const QString &samprate) +{ +} diff --git a/gr-qtgui/lib/constellationdisplayform.h b/gr-qtgui/lib/constellationdisplayform.h index d9779515a1..f9f8dab175 100644 --- a/gr-qtgui/lib/constellationdisplayform.h +++ b/gr-qtgui/lib/constellationdisplayform.h @@ -46,9 +46,11 @@ public slots: void customEvent(QEvent * e); void setNPoints(const int); + void setSampleRate(const QString &samprate); void setYaxis(double min, double max); void setXaxis(double min, double max); void autoScale(); + void autoScale(bool en); private slots: void newData(const QEvent*); diff --git a/gr-qtgui/lib/displayform.cc b/gr-qtgui/lib/displayform.cc index 444fa95858..e4a70c209a 100644 --- a/gr-qtgui/lib/displayform.cc +++ b/gr-qtgui/lib/displayform.cc @@ -98,6 +98,12 @@ DisplayForm::DisplayForm(int nplots, QWidget* parent) _menu->addMenu(_lines_menu[i]); } + _samp_rate_act = new PopupMenu("Sample Rate", this); + _samp_rate_act->setStatusTip(tr("Set Sample Rate")); + connect(_samp_rate_act, SIGNAL(whichTrigger(QString)), + this, SLOT(setSampleRate(QString))); + _menu->addAction(_samp_rate_act); + _autoscale_act = new QAction("Auto Scale On", this); _autoscale_act->setStatusTip(tr("Autoscale Plot")); connect(_autoscale_act, SIGNAL(triggered()), this, SLOT(autoScale())); diff --git a/gr-qtgui/lib/displayform.h b/gr-qtgui/lib/displayform.h index bd64407863..14f385796b 100644 --- a/gr-qtgui/lib/displayform.h +++ b/gr-qtgui/lib/displayform.h @@ -71,6 +71,8 @@ public slots: QwtSymbol::Style lineMarker(int which); int markerAlpha(int which); + virtual void setSampleRate(const QString &rate) = 0; + void setStop(bool on); void setStop(); @@ -117,6 +119,7 @@ protected: QList<LineMarkerMenu*> _line_marker_menu; QList<MarkerAlphaMenu*> _marker_alpha_menu; + PopupMenu *_samp_rate_act; QAction *_save_act; QTimer *d_displayTimer; diff --git a/gr-qtgui/lib/freq_sink_c_impl.cc b/gr-qtgui/lib/freq_sink_c_impl.cc index 78d7431b20..3755df0552 100644 --- a/gr-qtgui/lib/freq_sink_c_impl.cc +++ b/gr-qtgui/lib/freq_sink_c_impl.cc @@ -128,7 +128,6 @@ namespace gr { // initialize update time to 10 times a second set_update_time(0.1); - d_last_time = 0; } void @@ -209,6 +208,7 @@ namespace gr { gruel::high_res_timer_type tps = gruel::high_res_timer_tps(); d_update_time = t * tps; d_main_gui->setUpdateTime(t); + d_last_time = 0; } void @@ -314,6 +314,12 @@ namespace gr { } void + freq_sink_c_impl::enable_autoscale(bool en) + { + d_main_gui->autoScale(en); + } + + void freq_sink_c_impl::reset() { d_index = 0; diff --git a/gr-qtgui/lib/freq_sink_c_impl.h b/gr-qtgui/lib/freq_sink_c_impl.h index 77a625eb13..0567b914c8 100644 --- a/gr-qtgui/lib/freq_sink_c_impl.h +++ b/gr-qtgui/lib/freq_sink_c_impl.h @@ -116,6 +116,7 @@ namespace gr { void enable_menu(bool en); void enable_grid(bool en); + void enable_autoscale(bool en); void reset(); int work(int noutput_items, diff --git a/gr-qtgui/lib/freq_sink_f_impl.cc b/gr-qtgui/lib/freq_sink_f_impl.cc index 457235df6f..807be83948 100644 --- a/gr-qtgui/lib/freq_sink_f_impl.cc +++ b/gr-qtgui/lib/freq_sink_f_impl.cc @@ -128,7 +128,6 @@ namespace gr { // initialize update time to 10 times a second set_update_time(0.1); - d_last_time = 0; } void @@ -209,6 +208,7 @@ namespace gr { gruel::high_res_timer_type tps = gruel::high_res_timer_tps(); d_update_time = t * tps; d_main_gui->setUpdateTime(t); + d_last_time = 0; } void @@ -314,6 +314,12 @@ namespace gr { } void + freq_sink_f_impl::enable_autoscale(bool en) + { + d_main_gui->autoScale(en); + } + + void freq_sink_f_impl::reset() { d_index = 0; diff --git a/gr-qtgui/lib/freq_sink_f_impl.h b/gr-qtgui/lib/freq_sink_f_impl.h index d0a6b2c14b..b79127f3dd 100644 --- a/gr-qtgui/lib/freq_sink_f_impl.h +++ b/gr-qtgui/lib/freq_sink_f_impl.h @@ -115,6 +115,7 @@ namespace gr { void enable_menu(bool en); void enable_grid(bool en); + void enable_autoscale(bool en); void reset(); int work(int noutput_items, diff --git a/gr-qtgui/lib/freqdisplayform.cc b/gr-qtgui/lib/freqdisplayform.cc index 50c5a9d258..9015b79618 100644 --- a/gr-qtgui/lib/freqdisplayform.cc +++ b/gr-qtgui/lib/freqdisplayform.cc @@ -111,6 +111,12 @@ FreqDisplayForm::getFFTWindowType() const } void +FreqDisplayForm::setSampleRate(const QString &samprate) +{ + setFrequencyRange(_center_freq, samprate.toDouble()); +} + +void FreqDisplayForm::setFFTSize(const int newsize) { _fftsize = newsize; @@ -141,6 +147,9 @@ FreqDisplayForm::setFrequencyRange(const double centerfreq, double units = pow(10, (units10-fmod(units10, 3.0))); int iunit = static_cast<int>(units3); + _center_freq = centerfreq; + _samp_rate = bandwidth; + getPlot()->setFrequencyRange(centerfreq, bandwidth, units, strunits[iunit]); } @@ -166,3 +175,19 @@ FreqDisplayForm::autoScale() getPlot()->setAutoScale(_autoscale_state); getPlot()->replot(); } + +void +FreqDisplayForm::autoScale(bool en) +{ + if(en) { + _autoscale_act->setText(tr("Auto Scale Off")); + _autoscale_state = true; + } + else { + _autoscale_act->setText(tr("Auto Scale On")); + _autoscale_state = false; + } + + getPlot()->setAutoScale(_autoscale_state); + getPlot()->replot(); +} diff --git a/gr-qtgui/lib/freqdisplayform.h b/gr-qtgui/lib/freqdisplayform.h index 93967a23c3..f635fb5f33 100644 --- a/gr-qtgui/lib/freqdisplayform.h +++ b/gr-qtgui/lib/freqdisplayform.h @@ -48,6 +48,7 @@ class FreqDisplayForm : public DisplayForm public slots: void customEvent(QEvent *e); + void setSampleRate(const QString &samprate); void setFFTSize(const int); void setFFTAverage(const float); void setFFTWindowType(const gr::filter::firdes::win_type); @@ -56,6 +57,7 @@ public slots: const double bandwidth); void setYaxis(double min, double max); void autoScale(); + void autoScale(bool en); private slots: void newData(const QEvent *updateEvent); @@ -64,6 +66,7 @@ private: uint64_t _numRealDataPoints; QIntValidator* _intValidator; + double _samp_rate, _center_freq; int _fftsize; float _fftavg; gr::filter::firdes::win_type _fftwintype; diff --git a/gr-qtgui/lib/timeRasterGlobalData.cc b/gr-qtgui/lib/timeRasterGlobalData.cc index 10ba7ececc..556196f644 100644 --- a/gr-qtgui/lib/timeRasterGlobalData.cc +++ b/gr-qtgui/lib/timeRasterGlobalData.cc @@ -65,7 +65,8 @@ TimeRasterData::~TimeRasterData() void TimeRasterData::reset() { d_resid = 0; - memset(d_data, 0x0, d_totalitems*sizeof(double)); + d_nitems = 0; + memset(d_data, 0x0, d_data_size*sizeof(double)); } void TimeRasterData::copy(const TimeRasterData* rhs) @@ -93,7 +94,6 @@ void TimeRasterData::copy(const TimeRasterData* rhs) #endif reset(); - setDataBuffer(rhs->getDataBuffer()); #if QWT_VERSION < 0x060000 setRange(rhs->range()); @@ -231,22 +231,10 @@ TimeRasterData::addData(const double* data, d_nitems += cols; } else { - memmove(d_data, &d_data[cols], d_totalitems*sizeof(double)); memcpy(&d_data[d_nitems], data, cols*sizeof(double)); + memmove(d_data, &d_data[cols], d_totalitems*sizeof(double)); } } } -double* -TimeRasterData::getDataBuffer() const -{ - return d_data; -} - -void -TimeRasterData::setDataBuffer(const double* newData) -{ - memcpy(d_data, newData, d_totalitems*sizeof(double)); -} - #endif /* TIMERASTER_GLOBAL_DATA_CPP */ diff --git a/gr-qtgui/lib/timeRasterGlobalData.h b/gr-qtgui/lib/timeRasterGlobalData.h index 7b450c033b..0a414432d1 100644 --- a/gr-qtgui/lib/timeRasterGlobalData.h +++ b/gr-qtgui/lib/timeRasterGlobalData.h @@ -56,9 +56,6 @@ public: virtual void addData(const double*, const int); - virtual double* getDataBuffer()const; - virtual void setDataBuffer(const double*); - void incrementResidual(); protected: diff --git a/gr-qtgui/lib/time_raster_sink_b_impl.cc b/gr-qtgui/lib/time_raster_sink_b_impl.cc index 46d60ba3f5..e79b2f1ff4 100644 --- a/gr-qtgui/lib/time_raster_sink_b_impl.cc +++ b/gr-qtgui/lib/time_raster_sink_b_impl.cc @@ -124,7 +124,6 @@ namespace gr { // initialize update time to 10 times a second set_update_time(0.1); - d_last_time = 0; } void @@ -154,6 +153,7 @@ namespace gr { gruel::high_res_timer_type tps = gruel::high_res_timer_tps(); d_update_time = t * tps; d_main_gui->setUpdateTime(t); + d_last_time = 0; } void @@ -210,6 +210,18 @@ namespace gr { d_main_gui->setNumCols(cols); } + double + time_raster_sink_b_impl::num_rows() + { + return d_main_gui->numRows(); + } + + double + time_raster_sink_b_impl::num_cols() + { + return d_main_gui->numCols(); + } + void time_raster_sink_b_impl::set_multiplier(const std::vector<float> &mult) { @@ -252,6 +264,12 @@ namespace gr { d_main_gui->setIntensityRange(min, max); } + void + time_raster_sink_b_impl::reset() + { + d_index = 0; + } + int time_raster_sink_b_impl::work(int noutput_items, gr_vector_const_void_star &input_items, @@ -298,8 +316,11 @@ namespace gr { d_tmpflt, resid); } - d_qApplication->postEvent(d_main_gui, - new TimeRasterUpdateEvent(d_residbufs, d_icols)); + if(gruel::high_res_timer_now() - d_last_time > d_update_time) { + d_last_time = gruel::high_res_timer_now(); + d_qApplication->postEvent(d_main_gui, + new TimeRasterUpdateEvent(d_residbufs, d_icols)); + } d_index = 0; j += resid; diff --git a/gr-qtgui/lib/time_raster_sink_b_impl.h b/gr-qtgui/lib/time_raster_sink_b_impl.h index 248eb8dd67..1997bacd93 100644 --- a/gr-qtgui/lib/time_raster_sink_b_impl.h +++ b/gr-qtgui/lib/time_raster_sink_b_impl.h @@ -88,11 +88,16 @@ namespace gr { void set_num_rows(double rows); void set_num_cols(double cols); + double num_rows(); + double num_cols(); + void set_multiplier(const std::vector<float> &mult); void set_offset(const std::vector<float> &offset); void set_intensity_range(float min, float max); + void reset(); + int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); diff --git a/gr-qtgui/lib/time_raster_sink_f_impl.cc b/gr-qtgui/lib/time_raster_sink_f_impl.cc index be1e66da12..61d1436529 100644 --- a/gr-qtgui/lib/time_raster_sink_f_impl.cc +++ b/gr-qtgui/lib/time_raster_sink_f_impl.cc @@ -122,7 +122,6 @@ namespace gr { // initialize update time to 10 times a second set_update_time(0.1); - d_last_time = 0; } void @@ -152,6 +151,7 @@ namespace gr { gruel::high_res_timer_type tps = gruel::high_res_timer_tps(); d_update_time = t * tps; d_main_gui->setUpdateTime(t); + d_last_time = 0; } void @@ -208,6 +208,18 @@ namespace gr { d_main_gui->setNumCols(cols); } + double + time_raster_sink_f_impl::num_rows() + { + return d_main_gui->numRows(); + } + + double + time_raster_sink_f_impl::num_cols() + { + return d_main_gui->numCols(); + } + void time_raster_sink_f_impl::set_multiplier(const std::vector<float> &mult) { @@ -250,6 +262,12 @@ namespace gr { d_main_gui->setIntensityRange(min, max); } + void + time_raster_sink_f_impl::reset() + { + d_index = 0; + } + int time_raster_sink_f_impl::work(int noutput_items, gr_vector_const_void_star &input_items, @@ -258,7 +276,7 @@ namespace gr { int n=0, j=0, idx=0; const float *in = (const float*)input_items[0]; - unsigned int cols = d_main_gui->numCols(); + double cols = d_main_gui->numCols(); if(d_cols != cols) { d_cols = cols; d_index = 0; @@ -294,8 +312,12 @@ namespace gr { d_tmpflt, resid); } - d_qApplication->postEvent(d_main_gui, - new TimeRasterUpdateEvent(d_residbufs, d_cols)); + // Update the plot if its time + if(gruel::high_res_timer_now() - d_last_time > d_update_time) { + d_last_time = gruel::high_res_timer_now(); + d_qApplication->postEvent(d_main_gui, + new TimeRasterUpdateEvent(d_residbufs, d_cols)); + } d_index = 0; j += resid; diff --git a/gr-qtgui/lib/time_raster_sink_f_impl.h b/gr-qtgui/lib/time_raster_sink_f_impl.h index c14a5c1147..9c00ac89ba 100644 --- a/gr-qtgui/lib/time_raster_sink_f_impl.h +++ b/gr-qtgui/lib/time_raster_sink_f_impl.h @@ -87,11 +87,16 @@ namespace gr { void set_num_rows(double rows); void set_num_cols(double cols); + double num_rows(); + double num_cols(); + void set_multiplier(const std::vector<float> &mult); void set_offset(const std::vector<float> &offset); void set_intensity_range(float min, float max); + void reset(); + int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); diff --git a/gr-qtgui/lib/time_sink_c_impl.cc b/gr-qtgui/lib/time_sink_c_impl.cc index 46db6315eb..c6fe4ae168 100644 --- a/gr-qtgui/lib/time_sink_c_impl.cc +++ b/gr-qtgui/lib/time_sink_c_impl.cc @@ -103,7 +103,6 @@ namespace gr { // initialize update time to 10 times a second set_update_time(0.1); - d_last_time = 0; } void @@ -139,6 +138,7 @@ namespace gr { gruel::high_res_timer_type tps = gruel::high_res_timer_tps(); d_update_time = t * tps; d_main_gui->setUpdateTime(t); + d_last_time = 0; } void @@ -288,6 +288,12 @@ namespace gr { } void + time_sink_c_impl::enable_autoscale(bool en) + { + d_main_gui->autoScale(en); + } + + void time_sink_c_impl::toggle_stem_plot() { d_main_gui->setStem(); diff --git a/gr-qtgui/lib/time_sink_c_impl.h b/gr-qtgui/lib/time_sink_c_impl.h index bccb7b1197..6e35844c59 100644 --- a/gr-qtgui/lib/time_sink_c_impl.h +++ b/gr-qtgui/lib/time_sink_c_impl.h @@ -93,6 +93,7 @@ namespace gr { void enable_menu(bool en); void enable_grid(bool en); + void enable_autoscale(bool en); void toggle_stem_plot(); void reset(); diff --git a/gr-qtgui/lib/time_sink_f_impl.cc b/gr-qtgui/lib/time_sink_f_impl.cc index 06854c71e7..329af89dde 100644 --- a/gr-qtgui/lib/time_sink_f_impl.cc +++ b/gr-qtgui/lib/time_sink_f_impl.cc @@ -103,7 +103,6 @@ namespace gr { // initialize update time to 10 times a second set_update_time(0.1); - d_last_time = 0; } void @@ -139,6 +138,7 @@ namespace gr { gruel::high_res_timer_type tps = gruel::high_res_timer_tps(); d_update_time = t * tps; d_main_gui->setUpdateTime(t); + d_last_time = 0; } void @@ -294,6 +294,12 @@ namespace gr { } void + time_sink_f_impl::enable_autoscale(bool en) + { + d_main_gui->autoScale(en); + } + + void time_sink_f_impl::reset() { d_index = 0; diff --git a/gr-qtgui/lib/time_sink_f_impl.h b/gr-qtgui/lib/time_sink_f_impl.h index b6aafb19b7..f15841429b 100644 --- a/gr-qtgui/lib/time_sink_f_impl.h +++ b/gr-qtgui/lib/time_sink_f_impl.h @@ -93,6 +93,7 @@ namespace gr { void enable_menu(bool en); void enable_grid(bool en); + void enable_autoscale(bool en); void toggle_stem_plot(); void reset(); diff --git a/gr-qtgui/lib/timedisplayform.cc b/gr-qtgui/lib/timedisplayform.cc index 7bc30aee7a..8fe149a61a 100644 --- a/gr-qtgui/lib/timedisplayform.cc +++ b/gr-qtgui/lib/timedisplayform.cc @@ -89,6 +89,12 @@ TimeDisplayForm::customEvent(QEvent * e) } void +TimeDisplayForm::setSampleRate(const QString &samprate) +{ + setSampleRate(samprate.toDouble()); +} + +void TimeDisplayForm::setSampleRate(const double samprate) { if(samprate > 0) { @@ -145,3 +151,19 @@ TimeDisplayForm::autoScale() getPlot()->setAutoScale(_autoscale_state); getPlot()->replot(); } + +void +TimeDisplayForm::autoScale(bool en) +{ + if(en) { + _autoscale_act->setText(tr("Auto Scale Off")); + _autoscale_state = true; + } + else { + _autoscale_act->setText(tr("Auto Scale On")); + _autoscale_state = false; + } + + getPlot()->setAutoScale(_autoscale_state); + getPlot()->replot(); +} diff --git a/gr-qtgui/lib/timedisplayform.h b/gr-qtgui/lib/timedisplayform.h index 5734d3b1e5..8c5682cde2 100644 --- a/gr-qtgui/lib/timedisplayform.h +++ b/gr-qtgui/lib/timedisplayform.h @@ -46,10 +46,12 @@ public slots: void customEvent(QEvent * e); void setSampleRate(const double samprate); + void setSampleRate(const QString &samprate); void setYaxis(double min, double max); void setNPoints(const int); void setStem(bool trig=false); void autoScale(); + void autoScale(bool en); private slots: void newData(const QEvent*); diff --git a/gr-qtgui/lib/timerasterdisplayform.cc b/gr-qtgui/lib/timerasterdisplayform.cc index 1fbad090ca..2f9c8aaf0f 100644 --- a/gr-qtgui/lib/timerasterdisplayform.cc +++ b/gr-qtgui/lib/timerasterdisplayform.cc @@ -72,10 +72,7 @@ TimeRasterDisplayForm::TimeRasterDisplayForm(int nplots, _lines_menu[i]->addMenu(_marker_alpha_menu[i]); } - QAction *autoscale_act = new QAction("Auto Scale", this); - autoscale_act->setStatusTip(tr("Autoscale intensity range")); - connect(autoscale_act, SIGNAL(triggered()), this, SLOT(autoScale())); - _menu->addAction(autoscale_act); + _autoscale_act->setText(tr("Auto Scale")); PopupMenu *colsmenu = new PopupMenu("Num. Columns", this); _menu->addAction(colsmenu); @@ -173,6 +170,12 @@ TimeRasterDisplayForm::setNumCols(QString cols) } void +TimeRasterDisplayForm::setSampleRate(const QString &rate) +{ + getPlot()->setSampleRate(rate.toDouble()); +} + +void TimeRasterDisplayForm::setColorMap(int which, const int newType, const QColor lowColor, diff --git a/gr-qtgui/lib/timerasterdisplayform.h b/gr-qtgui/lib/timerasterdisplayform.h index e136f5faf8..e28183ffcb 100644 --- a/gr-qtgui/lib/timerasterdisplayform.h +++ b/gr-qtgui/lib/timerasterdisplayform.h @@ -58,6 +58,8 @@ public slots: void setNumRows(QString rows); void setNumCols(QString cols); + void setSampleRate(const QString &rate); + void setIntensityRange(const double minIntensity, const double maxIntensity); diff --git a/gr-qtgui/lib/waterfall_sink_c_impl.cc b/gr-qtgui/lib/waterfall_sink_c_impl.cc index e182d3c141..617d6b5442 100644 --- a/gr-qtgui/lib/waterfall_sink_c_impl.cc +++ b/gr-qtgui/lib/waterfall_sink_c_impl.cc @@ -127,7 +127,6 @@ namespace gr { // initialize update time to 10 times a second set_update_time(0.1); - d_last_time = 0; } void @@ -215,6 +214,7 @@ namespace gr { gruel::high_res_timer_type tps = gruel::high_res_timer_tps(); d_update_time = t * tps; d_main_gui->setUpdateTime(t); + d_last_time = 0; } void diff --git a/gr-qtgui/lib/waterfall_sink_f_impl.cc b/gr-qtgui/lib/waterfall_sink_f_impl.cc index d59319fd27..a17f73a248 100644 --- a/gr-qtgui/lib/waterfall_sink_f_impl.cc +++ b/gr-qtgui/lib/waterfall_sink_f_impl.cc @@ -126,7 +126,6 @@ namespace gr { // initialize update time to 10 times a second set_update_time(0.1); - d_last_time = 0; } void @@ -214,6 +213,7 @@ namespace gr { gruel::high_res_timer_type tps = gruel::high_res_timer_tps(); d_update_time = t * tps; d_main_gui->setUpdateTime(t); + d_last_time = 0; } void diff --git a/gr-qtgui/lib/waterfalldisplayform.cc b/gr-qtgui/lib/waterfalldisplayform.cc index d45af04248..d8160d0d85 100644 --- a/gr-qtgui/lib/waterfalldisplayform.cc +++ b/gr-qtgui/lib/waterfalldisplayform.cc @@ -37,6 +37,9 @@ WaterfallDisplayForm::WaterfallDisplayForm(int nplots, QWidget* parent) _layout->addWidget(_displayPlot, 0, 0); setLayout(_layout); + _center_freq = 0; + _samp_rate = 0; + _numRealDataPoints = 1024; _fftsize = 1024; _fftavg = 1.0; @@ -178,6 +181,12 @@ WaterfallDisplayForm::getMaxIntensity(int which) } void +WaterfallDisplayForm::setSampleRate(const QString &samprate) +{ + setFrequencyRange(_center_freq, samprate.toDouble()); +} + +void WaterfallDisplayForm::setFFTSize(const int newsize) { _fftsize = newsize; @@ -205,6 +214,7 @@ WaterfallDisplayForm::setFrequencyRange(const double centerfreq, double units = pow(10, (units10-fmod(units10, 3.0))); int iunit = static_cast<int>(units3); + _center_freq = centerfreq; _samp_rate = bandwidth; _time_per_slice = (1.0/bandwidth)*_fftsize; diff --git a/gr-qtgui/lib/waterfalldisplayform.h b/gr-qtgui/lib/waterfalldisplayform.h index a6add831fd..aba64bda57 100644 --- a/gr-qtgui/lib/waterfalldisplayform.h +++ b/gr-qtgui/lib/waterfalldisplayform.h @@ -55,6 +55,7 @@ class WaterfallDisplayForm : public DisplayForm public slots: void customEvent(QEvent *e); + void setSampleRate(const QString &samprate); void setFFTSize(const int); void setFFTAverage(const float); void setFFTWindowType(const gr::filter::firdes::win_type); @@ -81,7 +82,7 @@ private: uint64_t _numRealDataPoints; QIntValidator* _intValidator; - double _samp_rate; + double _samp_rate, _center_freq; double _time_per_slice; int _fftsize; float _fftavg; |