GNU Radio's MESA Package
signals_mesa.h
Go to the documentation of this file.
1 /*
2  * signals_mesa.h
3  *
4  * Copyright 2017, Michael Piscopo
5  *
6  *
7  */
8 
9 #ifndef LIB_SIGNALS_MESA_H_
10 #define LIB_SIGNALS_MESA_H_
11 
12 #include "scomplex.h"
13 #include <boost/thread/mutex.hpp>
14 #include <fftw3.h>
15 #include <volk/volk.h>
16 
17 typedef std::vector<float> FloatVector;
18 // These match the FFTW definitions
19 //#define FFTDIRECTION_FORWARD -1
20 // #define FFTDIRECTION_BACKWARD 1
21 #define FFTDIRECTION_FORWARD FFTW_FORWARD
22 #define FFTDIRECTION_BACKWARD FFTW_BACKWARD
23 
24 #define WINDOWTYPE_NONE 0
25 #define WINDOWTYPE_HAMMING 1
26 #define WINDOWTYPE_BLACKMAN_HARRIS 2
27 
28 #define SQUELCH_DISABLE -1000.0
29 #define NOISE_FLOOR -100.0
30 
31 using namespace std;
32 
33 namespace MesaSignals {
34 // global test function
35 void printArray(FloatVector &arr, string name);
36 void printArray(float *arr, int arrSize, string name);
37 
38 /*
39  * FFT Transforms
40  */
41 class FFT {
42 public:
43  // Actually it appears to get better performance, at least for 1024 sample
44  // FFT's with 1 thread The fftw3f doc says multiple threads only really help
45  // for large fft sizes, which may be why.
46  FFT(int FFTDirection, int initFFTSize, int initNumThreads = 1);
47  virtual ~FFT();
48 
49  inline int inputBufferLength() const { return fftSize; }
50  inline int outputBufferLength() const { return fftSize; }
51 
52  inline SComplex *getInputBuffer() { return inputBuffer; };
53  inline SComplex *getOutputBuffer() { return outputBuffer; };
54 
55  virtual void setWindow(int winType);
56  // Note: For this setWindow, the length of newTaps should be fftSize
57  virtual void setWindow(FloatVector &newTaps);
58 
59  virtual void clearWindow();
60 
61  // Execute computes the FFT and if a windowing function has been set for the
62  // class, it is applied appropriately before executing the FFT
63  virtual void execute(bool shift = false);
64 
65  // This execute applies the specified taps rather than the class taps.
66  // NOTE: the length of pTaps must be fftSize.
67  // Passing NULL will disable windowing for this run.
68  inline void execute(float *pTaps, bool shift = false);
69 
70  // So PSD computes power in dBm which is basically the RSSI.
71  // PowerSpectralDensity: Call Execute first, then call this function
72  // to compute PSD and store it in the provided psdBuffer buffer
73  // (note: psdBuffer must be at least fftSize in length and should be aligned
74  // memory) Note: PowerSpectralDensity output is basically the same as RSSI
75  // without squelch void PowerSpectralDensity(float *psdBuffer);
76  void PowerSpectralDensity(float *psdBuffer,
77  float squelchThreshold = SQUELCH_DISABLE,
78  float onSquelchSetRSSI = NOISE_FLOOR);
79 
80  // RSSI is very similar to PSD in terms of the PSD calculations to dBm,
81  // however you can set a squelch threshold Anything below that threshold is
82  // set to onSquelchSetRSSI to to "zero" the bin.
83  void rssi(float *psdBuffer, float squelchThreshold = SQUELCH_DISABLE,
84  float onSquelchSetRSSI = NOISE_FLOOR);
85 
86 protected:
87  boost::mutex d_mutex;
88 
90  float rssi_K_const;
91 
93  int fftSize;
95  void *fftPlan;
97 
99  bool hasTaps = false;
100 
103  float *tmpBuff; // Used for swapping to center DC in spectrums
107 
108  void init();
109  void initThreads();
110  void importWisdom();
111  void exportWisdom();
112 };
113 
114 /*
115  * Waterfall and energy analyzers
116  */
118 public:
120  virtual ~SpectrumOverview(){};
121  SpectrumOverview &operator=(const SpectrumOverview &other);
122 
123  float dutyCycle = 0.0;
124  float maxPower = NOISE_FLOOR;
125  float minPower = 1000.0;
126  float centerAvgPower = NOISE_FLOOR;
127  float avgPower = NOISE_FLOOR;
128  float minPowerOverThreshold = NOISE_FLOOR;
129  bool energyOverThreshold = false;
130 };
131 
132 typedef std::vector<SpectrumOverview> SpectrumOverviewVector;
133 
135 public:
137  virtual ~SignalOverview(){};
138  SignalOverview &operator=(const SignalOverview &other);
139 
140  double widthHz = 0.0;
141  double centerFreqHz = 0.0;
142  float maxPower = NOISE_FLOOR;
143 
144  void print();
145 };
146 
147 typedef std::vector<SignalOverview> SignalOverviewVector;
148 
149 /*
150  * Waterfall Data Class
151  */
152 
154 public:
155  // Waterfall will be fftSize wide by numRows long
157  int fftSize;
158  long numRows;
159 
160  float *data;
161 
162  virtual void reserve(int newFFTSize, long newNumRows);
163  virtual void clear();
164  virtual bool isEmpty();
165 
166  WaterfallData();
167  virtual ~WaterfallData();
168 };
169 
170 typedef std::vector<SignalOverview> SignalOverviewVector;
171 
172 /*
173  * EnergyAnalyzer class
174  */
176 protected:
177  int fftSize;
181 
183  float *psdSpectrum;
184 
185 public:
186  // squelch threshold should be a number like -75.0
187  // min duty cycle should be a fractional percentage (e.g. cycle = 0.1 for 10%)
188  EnergyAnalyzer(int initFFTSize, float initSquelchThreshold,
189  float initMinDutyCycle, bool useWindow = true);
190  virtual ~EnergyAnalyzer();
191 
192  inline void setThreshold(float newThreshold) {
193  squelchThreshold = newThreshold;
194  };
195  inline float getThreshold() { return squelchThreshold; };
196  inline void setDutyCycle(float newDutyCycle) { minDutyCycle = newDutyCycle; };
197  inline float getDutyCycle() { return minDutyCycle; };
198 
199  inline float getFFTSize() { return fftSize; };
200  inline FFT *getFFTProcessor() { return fftProc; };
201 
202  // Analyze chunks through frame and for each FFTSize block returns a
203  // spectrumOverview object which describes duty cycle, max power, avg power,
204  // etc. Think of it as an analysis/summary of each row in a waterfall plot.
205  // return value is the number of samples analyzed (will be an integer multiple
206  // of fftSize and the results of each FFTSize block
207  virtual long analyze(const SComplex *frame, long numSamples,
208  SpectrumOverviewVector &results);
209 
210  // maxHold computes the max spectrum curve for the given frame. Return value
211  // is the number of samples processed.
212  virtual long maxHold(const SComplex *frame, long numSamples,
213  FloatVector &maxSpectrum, bool useSquelch = true);
214 
215  // maxPower will look through a spectrum (something from maxHold or psd/rssi
216  // from FFT and find the max value
217  float maxPower(FloatVector &maxSpectrum);
218 
219  // AnalyzeSpectrum is a bit more generic. It does rely on the local fftSize
220  // and squelch threshold however, it analyzes just a single spectrum line and
221  // returns params about it. Think of it as a 1-line analysis of what analyze
222  // does in bulk. This can be useful in analyzing say a max spectrum line after
223  // maxHold is called.
224  void analyzeSpectrum(const float *spectrum, float &dutyCycle, float &maxPower,
225  float &minPower, float &centerAvgPower, float &avgPower);
226 
227  // findSignals looks through spectrum for signals meeting min/max/edge
228  // requirements assumes spectrum is fftSize long sampleRate is needed to
229  // determine Hz/bin If you don't know the center frequency for the radio, just
230  // use 0.0 then the signal center frequency will be relative to center (0)
231  // representing the frequncy shift off center Note it does use the
232  // squelchThreshold value set in the constructor as well. edgeDBDown defines
233  // required drop-off on edges (e.g. 15 dB for valid signal) Note: It's best to
234  // feed a squelched spectrum (say from FFT::PowerSpectralDensity or from
235  // maxHold) to this.
236  int findSignals(const float *spectrum, double sampleRate,
237  double centerFrequencyHz, double minWidthHz,
238  double maxWidthHz, SignalOverviewVector &signalVector,
239  bool stopOnFirst);
240  // float edgeDBDown, SignalOverviewVector& signalVector, bool stopOnFirst);
241 
242  // findSingleSignal makes some assumptions, first that the potential input
243  // signal has been filtered to the band that may contain the signal. Second,
244  // that there may only be a single signal. Therefore a simple boxing method
245  // can be applied to determine any signal that may be present. The minWidthHz
246  // is used to ensure whatever is found at least meets the minimum.
247  int findSingleSignal(const float *spectrum, double sampleRate,
248  double centerFrequencyHz, double minWidthHz,
249  SignalOverview &signalOverview);
250 
251  long getWaterfall(const SComplex *frame, long numSamples,
252  WaterfallData &waterfallData);
253 
254  // power binary slicer treats the spectrum/waterfall like OOK given the
255  // squelch threshold and duty cycle that have been set. The resulting output
256  // is the bits (on or off) based on duty cycle for a frame rssi will be the
257  // max power observed in any of the blocks that meet the duty cycle
258  // requirement
259  long powerBinarySlicer(const SComplex *frame, long numSamples,
260  FloatVector &bits, float &rssi);
261 
262  // Energy present uses the set squelch threshold and duty cycle to look for an
263  // FFT block with the specified amount of energy present. As soon as it finds
264  // one, it returns. rssi will be the max power observed in any of the blocks
265  // that meet the duty cycle requirement
266  bool energyPresent(const SComplex *frame, long numSamples, float &rssi);
267 
268  // countEnergyBlocks uses the set squelch threshold and duty cycle to look for
269  // FFT blocks with the specified amount of energy present. This function
270  // returns the count of those blocks rssi will be the max power observed in
271  // any of the blocks that meet the duty cycle requirement
272  long countEnergyBlocks(const SComplex *frame, long numSamples, float &rssi);
273 };
274 
275 } // namespace MesaSignals
276 
277 #endif /* LIB_SIGNALS_MESA_H_ */
#define NOISE_FLOOR
Definition: signals_mesa.h:29
int inputBufferLength() const
Definition: signals_mesa.h:49
int centerBucket
Definition: signals_mesa.h:178
FFT * getFFTProcessor()
Definition: signals_mesa.h:200
string wisdomFilename
Definition: signals_mesa.h:92
void setThreshold(float newThreshold)
Definition: signals_mesa.h:192
float getDutyCycle()
Definition: signals_mesa.h:197
float log2To10Factor
Definition: signals_mesa.h:89
STL namespace.
virtual ~SignalOverview()
Definition: signals_mesa.h:137
int numThreads
Definition: signals_mesa.h:94
int outputBufferLength() const
Definition: signals_mesa.h:50
Definition: signals_mesa.h:41
float * data
Definition: signals_mesa.h:160
int fftSize
Definition: signals_mesa.h:93
SComplex * inputBuffer
Definition: signals_mesa.h:101
SpectrumOverview()
Definition: signals_mesa.h:119
float * alignedWindowTaps
Definition: signals_mesa.h:98
std::vector< SpectrumOverview > SpectrumOverviewVector
Definition: signals_mesa.h:132
int fftLenBytes
Definition: signals_mesa.h:104
boost::mutex d_mutex
Definition: signals_mesa.h:87
FFT * fftProc
Definition: signals_mesa.h:182
float getFFTSize()
Definition: signals_mesa.h:199
SignalOverview()
Definition: signals_mesa.h:136
Definition: signals_mesa.h:117
float squelchThreshold
Definition: signals_mesa.h:179
void printArray(float *arr, int arrSize, string name)
int fftSize
Definition: signals_mesa.h:177
float * tmpBuff
Definition: signals_mesa.h:103
float getThreshold()
Definition: signals_mesa.h:195
Definition: signals_mesa.h:153
float minDutyCycle
Definition: signals_mesa.h:180
float rssi_K_const
Definition: signals_mesa.h:90
double centerFrequency
Definition: signals_mesa.h:156
std::vector< float > FloatVector
Definition: signals_mesa.h:17
void * fftPlan
Definition: signals_mesa.h:95
float * psdSpectrum
Definition: signals_mesa.h:183
int fftSize
Definition: signals_mesa.h:157
SComplex * outputBuffer
Definition: signals_mesa.h:102
std::vector< SignalOverview > SignalOverviewVector
Definition: signals_mesa.h:147
int halfFFTSize
Definition: signals_mesa.h:106
Definition: signals_mesa.h:134
virtual ~SpectrumOverview()
Definition: signals_mesa.h:120
SComplex * getInputBuffer()
Definition: signals_mesa.h:52
Definition: signals_mesa.h:33
SComplex * getOutputBuffer()
Definition: signals_mesa.h:53
int fftDirection
Definition: signals_mesa.h:96
std::complex< float > SComplex
Definition: scomplex.h:15
void setDutyCycle(float newDutyCycle)
Definition: signals_mesa.h:196
#define SQUELCH_DISABLE
Definition: signals_mesa.h:28
long numRows
Definition: signals_mesa.h:158
int halfFFTSizeBytes
Definition: signals_mesa.h:105
Definition: signals_mesa.h:175