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