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
17typedef 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
31using namespace std;
32
33namespace MesaSignals {
34// global test function
35void printArray(FloatVector &arr, string name);
36void printArray(float *arr, int arrSize, string name);
37
38/*
39 * FFT Transforms
40 */
41class FFT {
42public:
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
86protected:
87 boost::mutex d_mutex;
88
91
95 void *fftPlan;
97
99 bool hasTaps = false;
100
103 float *tmpBuff; // Used for swapping to center DC in spectrums
107
108 void init();
112};
113
114/*
115 * Waterfall and energy analyzers
116 */
131
132typedef std::vector<SpectrumOverview> SpectrumOverviewVector;
133
135public:
137 virtual ~SignalOverview(){};
139
140 double widthHz = 0.0;
141 double centerFreqHz = 0.0;
143
144 void print();
145};
146
147typedef std::vector<SignalOverview> SignalOverviewVector;
148
149/*
150 * Waterfall Data Class
151 */
152
154public:
155 // Waterfall will be fftSize wide by numRows long
159
160 float *data;
161
162 virtual void reserve(int newFFTSize, long newNumRows);
163 virtual void clear();
164 virtual bool isEmpty();
165
167 virtual ~WaterfallData();
168};
169
170typedef std::vector<SignalOverview> SignalOverviewVector;
171
172/*
173 * EnergyAnalyzer class
174 */
176protected:
181
184
185public:
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);
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_ */
float getDutyCycle()
Definition signals_mesa.h:197
void setDutyCycle(float newDutyCycle)
Definition signals_mesa.h:196
bool energyPresent(const SComplex *frame, long numSamples, float &rssi)
float * psdSpectrum
Definition signals_mesa.h:183
long powerBinarySlicer(const SComplex *frame, long numSamples, FloatVector &bits, float &rssi)
float squelchThreshold
Definition signals_mesa.h:179
int findSingleSignal(const float *spectrum, double sampleRate, double centerFrequencyHz, double minWidthHz, SignalOverview &signalOverview)
float maxPower(FloatVector &maxSpectrum)
float getFFTSize()
Definition signals_mesa.h:199
int fftSize
Definition signals_mesa.h:177
float getThreshold()
Definition signals_mesa.h:195
EnergyAnalyzer(int initFFTSize, float initSquelchThreshold, float initMinDutyCycle, bool useWindow=true)
void analyzeSpectrum(const float *spectrum, float &dutyCycle, float &maxPower, float &minPower, float &centerAvgPower, float &avgPower)
FFT * fftProc
Definition signals_mesa.h:182
virtual long maxHold(const SComplex *frame, long numSamples, FloatVector &maxSpectrum, bool useSquelch=true)
FFT * getFFTProcessor()
Definition signals_mesa.h:200
void setThreshold(float newThreshold)
Definition signals_mesa.h:192
long getWaterfall(const SComplex *frame, long numSamples, WaterfallData &waterfallData)
int centerBucket
Definition signals_mesa.h:178
float minDutyCycle
Definition signals_mesa.h:180
virtual long analyze(const SComplex *frame, long numSamples, SpectrumOverviewVector &results)
int findSignals(const float *spectrum, double sampleRate, double centerFrequencyHz, double minWidthHz, double maxWidthHz, SignalOverviewVector &signalVector, bool stopOnFirst)
long countEnergyBlocks(const SComplex *frame, long numSamples, float &rssi)
Definition signals_mesa.h:41
virtual void execute(bool shift=false)
bool hasTaps
Definition signals_mesa.h:99
int outputBufferLength() const
Definition signals_mesa.h:50
boost::mutex d_mutex
Definition signals_mesa.h:87
SComplex * outputBuffer
Definition signals_mesa.h:102
float * alignedWindowTaps
Definition signals_mesa.h:98
SComplex * getOutputBuffer()
Definition signals_mesa.h:53
string wisdomFilename
Definition signals_mesa.h:92
int fftLenBytes
Definition signals_mesa.h:104
float log2To10Factor
Definition signals_mesa.h:89
void rssi(float *psdBuffer, float squelchThreshold=SQUELCH_DISABLE, float onSquelchSetRSSI=NOISE_FLOOR)
float rssi_K_const
Definition signals_mesa.h:90
int inputBufferLength() const
Definition signals_mesa.h:49
void PowerSpectralDensity(float *psdBuffer, float squelchThreshold=SQUELCH_DISABLE, float onSquelchSetRSSI=NOISE_FLOOR)
int halfFFTSize
Definition signals_mesa.h:106
float * tmpBuff
Definition signals_mesa.h:103
SComplex * getInputBuffer()
Definition signals_mesa.h:52
void * fftPlan
Definition signals_mesa.h:95
FFT(int FFTDirection, int initFFTSize, int initNumThreads=1)
virtual void setWindow(FloatVector &newTaps)
SComplex * inputBuffer
Definition signals_mesa.h:101
int fftDirection
Definition signals_mesa.h:96
virtual void clearWindow()
int numThreads
Definition signals_mesa.h:94
int halfFFTSizeBytes
Definition signals_mesa.h:105
int fftSize
Definition signals_mesa.h:93
void execute(float *pTaps, bool shift=false)
virtual void setWindow(int winType)
Definition signals_mesa.h:134
SignalOverview & operator=(const SignalOverview &other)
SignalOverview()
Definition signals_mesa.h:136
double centerFreqHz
Definition signals_mesa.h:141
float maxPower
Definition signals_mesa.h:142
double widthHz
Definition signals_mesa.h:140
virtual ~SignalOverview()
Definition signals_mesa.h:137
float dutyCycle
Definition signals_mesa.h:123
float minPowerOverThreshold
Definition signals_mesa.h:128
virtual ~SpectrumOverview()
Definition signals_mesa.h:120
SpectrumOverview & operator=(const SpectrumOverview &other)
float avgPower
Definition signals_mesa.h:127
SpectrumOverview()
Definition signals_mesa.h:119
float centerAvgPower
Definition signals_mesa.h:126
float maxPower
Definition signals_mesa.h:124
float minPower
Definition signals_mesa.h:125
bool energyOverThreshold
Definition signals_mesa.h:129
Definition signals_mesa.h:153
int fftSize
Definition signals_mesa.h:157
long numRows
Definition signals_mesa.h:158
float * data
Definition signals_mesa.h:160
virtual void reserve(int newFFTSize, long newNumRows)
double centerFrequency
Definition signals_mesa.h:156
Definition signals_mesa.h:33
std::vector< SpectrumOverview > SpectrumOverviewVector
Definition signals_mesa.h:132
std::vector< SignalOverview > SignalOverviewVector
Definition signals_mesa.h:147
void printArray(FloatVector &arr, string name)
std::complex< float > SComplex
Definition scomplex.h:15
std::vector< float > FloatVector
Definition signals_mesa.h:17
#define NOISE_FLOOR
Definition signals_mesa.h:29
#define SQUELCH_DISABLE
Definition signals_mesa.h:28