Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-core / src / lib / io / gr_histo_sink_f.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2009 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gr_histo_sink_f.h>
28 #include <gr_io_signature.h>
29
30 static float get_clean_num(float num){
31   if (num == 0) return 0;
32   /* extract sign and exponent from num */
33   int sign = (num < 0) ? -1 : 1; num = fabs(num);
34   float exponent = floor(log10(num));
35   /* search for closest number with base 1, 2, 5, 10 */
36   float closest_num = 10*pow(10, exponent);
37   if (fabs(num - 1*pow(10, exponent)) < fabs(num - closest_num))
38     closest_num = 1*pow(10, exponent);
39   if (fabs(num - 2*pow(10, exponent)) < fabs(num - closest_num))
40     closest_num = 2*pow(10, exponent);
41   if (fabs(num - 5*pow(10, exponent)) < fabs(num - closest_num))
42     closest_num = 5*pow(10, exponent);
43   return sign*closest_num;
44 }
45
46 gr_histo_sink_f_sptr
47 gr_make_histo_sink_f (gr_msg_queue_sptr msgq)
48 {
49   return gr_histo_sink_f_sptr (new gr_histo_sink_f (msgq));
50 }
51
52 gr_histo_sink_f::gr_histo_sink_f (gr_msg_queue_sptr msgq)
53   : gr_sync_block ("histo_sink_f", gr_make_io_signature (1, 1, sizeof (float)), gr_make_io_signature (0, 0, 0)),
54   d_msgq (msgq), d_num_bins(11), d_frame_size(1000), d_sample_count(0), d_bins(NULL), d_samps(NULL)
55 {
56   pthread_mutex_init(&d_mutex, 0);
57   //allocate arrays and clear
58   set_num_bins(d_num_bins);
59   set_frame_size(d_frame_size);
60 }
61
62 gr_histo_sink_f::~gr_histo_sink_f (void)
63 {
64   pthread_mutex_destroy(&d_mutex);
65   delete [] d_samps;
66   delete [] d_bins;
67 }
68
69 int
70 gr_histo_sink_f::work (int noutput_items,
71   gr_vector_const_void_star &input_items,
72   gr_vector_void_star &output_items)
73 {
74   const float *in = (const float *) input_items[0];
75   pthread_mutex_lock(&d_mutex);
76   for (unsigned int i = 0; i < (unsigned int)noutput_items; i++){
77     d_samps[d_sample_count] = in[i];
78     d_sample_count++;
79     /* processed a frame? */
80     if (d_sample_count == d_frame_size){
81       send_frame();
82       clear();
83     }
84   }
85   pthread_mutex_unlock(&d_mutex);
86   return noutput_items;
87 }
88
89 void
90 gr_histo_sink_f::send_frame(void){
91   /* output queue full, drop the data */
92   if (d_msgq->full_p()) return;
93   /* find the minimum and maximum */
94   float minimum = d_samps[0];
95   float maximum = d_samps[0];
96   for (unsigned int i = 0; i < d_frame_size; i++){
97     if (d_samps[i] < minimum) minimum = d_samps[i];
98     if (d_samps[i] > maximum) maximum = d_samps[i];
99   }
100   minimum = get_clean_num(minimum);
101   maximum = get_clean_num(maximum);
102   if (minimum == maximum || minimum > maximum) return; //useless data or screw up?
103   /* load the bins */
104   int index;
105   float bin_width = (maximum - minimum)/(d_num_bins-1);
106   for (unsigned int i = 0; i < d_sample_count; i++){
107     index = round((d_samps[i] - minimum)/bin_width);
108     /* ensure the index range in case a small floating point error is involed */
109     if (index < 0) index = 0;
110     if (index >= (int)d_num_bins) index = d_num_bins-1;
111     d_bins[index]++;
112   }
113   /* Build a message to hold the output records */
114   gr_message_sptr msg = gr_make_message(0, minimum, maximum, d_num_bins*sizeof(float));
115   float *out = (float *)msg->msg(); // get pointer to raw message buffer
116   /* normalize the bins and put into message */
117   for (unsigned int i = 0; i < d_num_bins; i++){
118     out[i] = ((float)d_bins[i])/d_frame_size;
119   }
120   /* send the message */
121   d_msgq->handle(msg);
122 }
123
124 void
125 gr_histo_sink_f::clear(void){
126   d_sample_count = 0;
127   /* zero the bins */
128   for (unsigned int i = 0; i < d_num_bins; i++){
129     d_bins[i] = 0;
130   }
131 }
132
133 /**************************************************
134  * Getters
135  **************************************************/
136 unsigned int
137 gr_histo_sink_f::get_frame_size(void){
138   return d_frame_size;
139 }
140
141 unsigned int
142 gr_histo_sink_f::get_num_bins(void){
143   return d_num_bins;
144 }
145
146 /**************************************************
147  * Setters
148  **************************************************/
149 void
150 gr_histo_sink_f::set_frame_size(unsigned int frame_size){
151   pthread_mutex_lock(&d_mutex);
152   d_frame_size = frame_size;
153   /* allocate a new sample array */
154   delete [] d_samps;
155   d_samps = new float[d_frame_size];
156   clear();
157   pthread_mutex_unlock(&d_mutex);
158 }
159
160 void
161 gr_histo_sink_f::set_num_bins(unsigned int num_bins){
162   pthread_mutex_lock(&d_mutex);
163   d_num_bins = num_bins;
164   /* allocate a new bin array */
165   delete [] d_bins;
166   d_bins = new unsigned int[d_num_bins];
167   clear();
168   pthread_mutex_unlock(&d_mutex);
169 }