SoDaRadio-5.0.3-master:8901fb5
soda_wfall_data.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2017 Matthew H. Reilly (kb1vc)
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 
9  Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in
13  the documentation and/or other materials provided with the
14  distribution.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include "soda_wfall_data.hpp"
30 #include <iostream>
31 #include <boost/format.hpp>
32 
34  clearReady();
35  num_rows = 300;
36  min_time = -1.0 * ((double) num_rows);
37 
38  setInterval( Qt::XAxis, QwtInterval(0.0, 100e9)); // I don't think we'll see too many 100GHz scans
39  setInterval( Qt::YAxis, QwtInterval(-1.0 * ((double) num_rows), 0.0)); // store the last 300 rows
40 
41  ref_level = -80.0;
42  dynamic_range = 80.0;
43  setZRange();
44 
45  start_freq = new double[num_rows];
46  cur_freq_idx = 0;
47  cur_row_idx = 0;
48  last_cidx = 0;
49 
50  f_lo_marker = f_hi_marker = 0.0;
51 
52  heatmap = NULL;
53  num_buckets = 0;
54 
55 }
56 
58  delete[] heatmap;
59 }
60 
61 void GUISoDa::WFallData::setSpectrumDimensions(double cfreq, double span, long buckets)
62 {
63  (void) cfreq;
64  clearReady();
65 
66  if((heatmap != NULL) && (buckets != num_buckets)) {
67  delete[] heatmap;
68  heatmap = NULL;
69  }
70  if(heatmap == NULL) {
71  heatmap_size = buckets * num_rows;
72  heatmap = new double[heatmap_size];
73  }
74 
75  num_buckets = buckets;
76 
77  // these are the dimensions for the input data -- it may
78  span_in_freq = span;
79 
80  r_fbucket_size = ((double) num_buckets) / span;
81  setReady();
82 }
83 
84 double GUISoDa::WFallData::value(double f, double t) const
85 {
86  // if we don't have the scales setup, then report a very negative number
87  if(!is_ready) return -1e6;
88 
89  // first, see if this is a marker position.
90  if(((last_freq < f_lo_marker) && (f >= f_lo_marker)) ||
91  ((last_freq < f_hi_marker) && (f >= f_hi_marker))) {
92  last_freq = f;
93  return 1e6; // bright line
94  }
95  last_freq = f;
96 
97  // t goes back in time. 0 is now, min_time is "back there"
98  // cur_row_idx in the heatmap is the latest entry.
99  //
100  long rowidx;
101  long freqidx;
102  if(t == 0.0) {
103  rowidx = cur_row_idx;
104  freqidx = cur_freq_idx;
105  }
106  else {
107  long tidx = ((long) (t - min_time));
108  rowidx = cur_row_idx - num_buckets * tidx;
109  freqidx = cur_freq_idx - tidx;
110  if(rowidx < 0) {
111  rowidx += heatmap_size;
112  freqidx += num_rows;
113  }
114  if(rowidx > (heatmap_size - num_buckets)) {
115  rowidx -= heatmap_size;
116  freqidx -= num_rows;
117  }
118  }
119  // now find the index for the frequency.
120  double min_spect_freq = start_freq[freqidx];
121  // if the frequency is out of range, return nosignal
122  if((f < min_spect_freq) || (f > (min_spect_freq + span_in_freq))) return -1e6;
123 
124 
125 
126  long cidx = ((long) ((f - min_spect_freq) * r_fbucket_size));
127  // since the data points requested are at intervals that don't match
128  // our actual bucket size, we sample the range of values from the point
129  // of the last sample to this one... (pixels will then show the max value
130  // in the region to the pixel's left.)
131  double ret;
132  if(cidx > last_cidx) {
133  // report out the max value;
134  ret = heatmap[rowidx + cidx];
135  for(int i = rowidx + last_cidx + 1; i <= rowidx + cidx; i++) {
136  if(ret < heatmap[i]) ret = heatmap[i];
137  }
138  }
139  else {
140  ret = heatmap[rowidx + cidx];
141  }
142  last_cidx = cidx;
143 
144  return ret;
145 }
146 
148  setInterval( Qt::ZAxis, QwtInterval(ref_level, ref_level + dynamic_range));
149 }
150 
152  dynamic_range = drange;
153  setZRange();
154 }
155 
156 void GUISoDa::WFallData::setRefLevel(double reflvl) {
157  ref_level = reflvl;
158  setZRange();
159 }
160 
161 void GUISoDa::WFallData::updateData(double cfreq, float * spect) {
162  if(!is_ready) return;
164  cur_freq_idx++;
166  cur_row_idx = 0;
167  cur_freq_idx = 0;
168  }
169 
170  double * vec = heatmap + cur_row_idx;
171  for(int i = 0; i < num_buckets; i++) {
172  vec[i] = spect[i];
173  }
174  start_freq[cur_freq_idx] = cfreq - 0.5 * span_in_freq;
175 }
double * start_freq
for each row in the heat map, this is the centerfreq.
double min_time
earliest time relative to "now"
virtual double value(double f, double t) const
virtual void updateData(double cfreq, float *spect)
void setDynamicRange(double drange)
void setSpectrumDimensions(double cfreq, double span, long buckets)
void setRefLevel(double reflvl)