Skip to content

Commit

Permalink
DM: update level detector to use SPL
Browse files Browse the repository at this point in the history
  • Loading branch information
deanm1278 committed Feb 8, 2018
1 parent 9e75d9e commit a4e9a36
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 43 deletions.
25 changes: 15 additions & 10 deletions inc/streams/LevelDetector.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,13 @@ namespace codal{

// The stream component that is serving our data
DataSource &upstream; // The component producing data to process
int highThreshold; // threshold at which a HIGH event is generated
int lowThreshold; // threshold at which a LOW event is generated
float highThreshold; // threshold at which a HIGH event is generated
float lowThreshold; // threshold at which a LOW event is generated
int windowSize; // The number of samples the make up a level detection window.
int windowPosition; // The number of samples used so far in the calculation of a window.
int level; // The current, instantaneous level.
float level; // The current, instantaneous level.
int sigma; // Running total of the samples in the current window.
float gain;
float minValue;


/**
Expand All @@ -70,7 +71,9 @@ namespace codal{
* @param lowThreshold the HIGH threshold at which a LEVEL_THRESHOLD_LOW event will be generated
* @param id The id to use for the message bus when transmitting events.
*/
LevelDetector(DataSource &source, int highThreshold, int lowThreshold, uint16_t id = DEVICE_ID_SYSTEM_LEVEL_DETECTOR);
LevelDetector(DataSource &source, float highThreshold, float lowThreshold, float gain,
float minValue = 52,
uint16_t id = DEVICE_ID_SYSTEM_LEVEL_DETECTOR);

/**
* Callback provided when data is ready.
Expand All @@ -82,7 +85,7 @@ namespace codal{
*
* @return The current value of the sensor.
*/
int getValue();
float getValue();

/**
* Set threshold to the given value. Events will be generated when these thresholds are crossed.
Expand All @@ -91,7 +94,7 @@ namespace codal{
*
* @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails.
*/
int setLowThreshold(int value);
int setLowThreshold(float value);

/**
* Set threshold to the given value. Events will be generated when these thresholds are crossed.
Expand All @@ -100,21 +103,21 @@ namespace codal{
*
* @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails.
*/
int setHighThreshold(int value);
int setHighThreshold(float value);

/**
* Determines the currently defined low threshold.
*
* @return The current low threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined.
*/
int getLowThreshold();
float getLowThreshold();

/**
* Determines the currently defined high threshold.
*
* @return The current high threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined.
*/
int getHighThreshold();
float getHighThreshold();

/**
* Set the window size to the given value. The window size defines the number of samples used to determine a sound level.
Expand All @@ -127,6 +130,8 @@ namespace codal{
*/
int setWindowSize(int size);

int setGain(float gain);

/**
* Destructor.
*/
Expand Down
102 changes: 69 additions & 33 deletions source/streams/LevelDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,14 @@ DEALINGS IN THE SOFTWARE.

using namespace codal;

LevelDetector::LevelDetector(DataSource &source, int highThreshold, int lowThreshold, uint16_t id) : upstream(source)
LevelDetector::LevelDetector(DataSource &source, float highThreshold, float lowThreshold, float gain, float minValue, uint16_t id) : upstream(source)
{
this->id = id;
this->level = 0;
this->sigma = 0;
this->windowPosition = 0;
this->windowSize = LEVEL_DETECTOR_DEFAULT_WINDOW_SIZE;
this->lowThreshold = lowThreshold;
this->highThreshold = highThreshold;
this->gain = gain;
this->status |= LEVEL_DETECTOR_INITIALISED;

// Register with our upstream component
Expand All @@ -56,44 +55,75 @@ int LevelDetector::pullRequest()

int samples = b.length() / 2;

for (int i=0; i < samples; i++)
{
sigma += abs(*data);
windowPosition++;
while(samples){

if (windowPosition == windowSize)
//ensure we use at least windowSize number of samples
int16_t *end, *ptr;
if(samples < windowSize)
break;

end = data + windowSize;

float pref = 0.00002;

/*******************************
* REMOVE DC OFFSET
******************************/
int32_t avg = 0;
ptr = data;
while(ptr < end) avg += *ptr++;
avg = avg/windowSize;

ptr = data;
while(ptr < end) *ptr++ -= avg;

/*******************************
* GET MAX VALUE
******************************/

int16_t maxVal = 0;
ptr = data;
while(ptr < end){
int32_t v = abs(*ptr++);
if(v > maxVal) maxVal = v;
}

float conv = ((float)maxVal)/((1 << 15)-1) * gain;

/*******************************
* CALCULATE SPL
******************************/
conv = 20 * log10(conv/pref);

if(isfinite(conv)) level = conv;
else level = minValue;

samples -= windowSize;

if ((!(status & LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED)) && level > highThreshold)
{
level = sigma / windowSize;
sigma = 0;
windowPosition = 0;

if ((!(status & LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED)) && level > highThreshold)
{
Event(id, LEVEL_THRESHOLD_HIGH);
status |= LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED;
status &= ~LEVEL_DETECTOR_LOW_THRESHOLD_PASSED;
}

if ((!(status & LEVEL_DETECTOR_LOW_THRESHOLD_PASSED)) && level < lowThreshold)
{
Event(id, LEVEL_THRESHOLD_LOW);
status |= LEVEL_DETECTOR_LOW_THRESHOLD_PASSED;
status &= ~LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED;
}
Event(id, LEVEL_THRESHOLD_HIGH);
status |= LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED;
status &= ~LEVEL_DETECTOR_LOW_THRESHOLD_PASSED;
}

data++;
}
if ((!(status & LEVEL_DETECTOR_LOW_THRESHOLD_PASSED)) && level < lowThreshold)
{
Event(id, LEVEL_THRESHOLD_LOW);
status |= LEVEL_DETECTOR_LOW_THRESHOLD_PASSED;
status &= ~LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED;
}
}

return DEVICE_OK;
return DEVICE_OK;
}

/*
* Determines the instantaneous value of the sensor, in SI units, and returns it.
*
* @return The current value of the sensor.
*/
int LevelDetector::getValue()
float LevelDetector::getValue()
{
return level;
}
Expand All @@ -106,7 +136,7 @@ int LevelDetector::getValue()
*
* @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails.
*/
int LevelDetector::setLowThreshold(int value)
int LevelDetector::setLowThreshold(float value)
{
// Protect against churn if the same threshold is set repeatedly.
if (lowThreshold == value)
Expand All @@ -132,7 +162,7 @@ int LevelDetector::setLowThreshold(int value)
*
* @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails.
*/
int LevelDetector::setHighThreshold(int value)
int LevelDetector::setHighThreshold(float value)
{
// Protect against churn if the same threshold is set repeatedly.
if (highThreshold == value)
Expand All @@ -156,7 +186,7 @@ int LevelDetector::setHighThreshold(int value)
*
* @return The current low threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined.
*/
int LevelDetector::getLowThreshold()
float LevelDetector::getLowThreshold()
{
return lowThreshold;
}
Expand All @@ -166,7 +196,7 @@ int LevelDetector::getLowThreshold()
*
* @return The current high threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined.
*/
int LevelDetector::getHighThreshold()
float LevelDetector::getHighThreshold()
{
return highThreshold;
}
Expand All @@ -189,6 +219,12 @@ int LevelDetector::setWindowSize(int size)
return DEVICE_OK;
}

int LevelDetector::setGain(float gain)
{
this->gain = gain;
return DEVICE_OK;
}

/**
* Destructor.
*/
Expand Down

0 comments on commit a4e9a36

Please sign in to comment.