Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1a8cb3691c36
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f41c8addf2ac
Choose a head ref
  • 2 commits
  • 11 files changed
  • 1 contributor

Commits on Sep 20, 2020

  1. Copy the full SHA
    1afc0d4 View commit details
  2. Copy the full SHA
    f41c8ad View commit details
1 change: 1 addition & 0 deletions scopehal/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -69,6 +69,7 @@ set(SCOPEHAL_SOURCES
Filter.cpp
FilterParameter.cpp
PacketDecoder.cpp
PeakDetectionFilter.cpp
Statistic.cpp
)

105 changes: 105 additions & 0 deletions scopehal/PeakDetectionFilter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/***********************************************************************************************************************
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2020 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
* following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials provided with the distribution. *
* *
* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
***********************************************************************************************************************/

#include "../scopehal/scopehal.h"
#include "../scopehal/AlignedAllocator.h"
#include "PeakDetectionFilter.h"
#include <immintrin.h>

using namespace std;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

PeakDetectionFilter::PeakDetectionFilter(OscilloscopeChannel::ChannelType type, string color, Category cat)
: Filter(type, color, cat)
{
m_numpeaksname = "Number of Peaks";
m_parameters[m_numpeaksname] = FilterParameter(FilterParameter::TYPE_INT, Unit(Unit::UNIT_COUNTS));
m_parameters[m_numpeaksname].SetIntVal(10);

m_peakwindowname = "Peak Window";
m_parameters[m_peakwindowname] = FilterParameter(FilterParameter::TYPE_FLOAT, Unit(Unit::UNIT_HZ));
m_parameters[m_peakwindowname].SetFloatVal(500000); //500 kHz between peaks
}

PeakDetectionFilter::~PeakDetectionFilter()
{

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Actual decoder logic

void PeakDetectionFilter::FindPeaks(AnalogWaveform* cap)
{
int64_t max_peaks = m_parameters[m_numpeaksname].GetIntVal();
size_t nouts = cap->m_samples.size();
if(max_peaks > 0)
{
//Get peak search width in bins
float search_hz = m_parameters[m_peakwindowname].GetIntVal();
int64_t search_bins = ceil(search_hz / cap->m_timescale);
search_bins = min(search_bins, (int64_t)512); //TODO: reasonable limit
int64_t search_rad = search_bins/2;

//Find peaks (TODO: can we vectorize/multithread this?)
//Start at index 1 so we don't waste a marker on the DC peak
vector<Peak> peaks;
for(ssize_t i=1; i<(ssize_t)nouts; i++)
{
ssize_t max_delta = 0;
float max_value = -FLT_MAX;

for(ssize_t delta = -search_rad; delta <= search_rad; delta ++)
{
ssize_t index = i+delta ;
if( (index < 0) || (index >= (ssize_t)nouts) )
continue;

float amp = cap->m_samples[index];
if(amp > max_value)
{
max_value = amp;
max_delta = delta;
}
}

//If the highest point in the search window is at our location, we're a peak
if(max_delta == 0)
peaks.push_back(Peak(i, max_value));
}

//Sort the peak table and pluck out the requested count
sort(peaks.rbegin(), peaks.rend(), less<Peak>());
m_peaks.clear();
for(size_t i=0; i<(size_t)max_peaks && i<peaks.size(); i++)
m_peaks.push_back(peaks[i]);
}
}
74 changes: 74 additions & 0 deletions scopehal/PeakDetectionFilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/***********************************************************************************************************************
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2020 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
* following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials provided with the distribution. *
* *
* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
***********************************************************************************************************************/

/**
@file
@author Andrew D. Zonenberg
@brief Declaration of PeakDetectionFilter
*/
#ifndef PeakDetectionFilter_h
#define PeakDetectionFilter_h

class Peak
{
public:
Peak(int64_t x, float y)
: m_x(x)
, m_y(y)
{}

bool operator<(const Peak& rhs) const
{ return (m_y < rhs.m_y); }

int64_t m_x;
float m_y;
};

/**
*/
class PeakDetectionFilter : public Filter
{
public:
PeakDetectionFilter(OscilloscopeChannel::ChannelType type, std::string color, Category cat);
virtual ~PeakDetectionFilter();

const std::vector<Peak>& GetPeaks()
{ return m_peaks; }

protected:
void FindPeaks(AnalogWaveform* cap);

std::string m_numpeaksname;
std::string m_peakwindowname;

std::vector<Peak> m_peaks;
};

#endif

1 change: 1 addition & 0 deletions scopehal/scopehal.h
Original file line number Diff line number Diff line change
@@ -76,6 +76,7 @@
#include "Statistic.h"
#include "FilterParameter.h"
#include "Filter.h"
#include "PeakDetectionFilter.h"

#include "TouchstoneParser.h"
#include "IBISParser.h"
1 change: 1 addition & 0 deletions scopeprotocols/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -51,6 +51,7 @@ set(SCOPEPROTOCOLS_SOURCES
OFDMDemodulator.cpp
OvershootMeasurement.cpp
ParallelBus.cpp
PeakHoldFilter.cpp
PeriodMeasurement.cpp
PkPkMeasurement.cpp
QuadratureDecoder.cpp
53 changes: 3 additions & 50 deletions scopeprotocols/FFTFilter.cpp
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ using namespace std;
// Construction / destruction

FFTFilter::FFTFilter(string color)
: Filter(OscilloscopeChannel::CHANNEL_TYPE_ANALOG, color, CAT_RF)
: PeakDetectionFilter(OscilloscopeChannel::CHANNEL_TYPE_ANALOG, color, CAT_RF)
{
m_xAxisUnit = Unit(Unit::UNIT_HZ);
m_yAxisUnit = Unit(Unit::UNIT_DBM);
@@ -54,14 +54,6 @@ FFTFilter::FFTFilter(string color)
//Default config
m_range = 70;
m_offset = 35;

m_numpeaksname = "Number of Peaks";
m_parameters[m_numpeaksname] = FilterParameter(FilterParameter::TYPE_INT, Unit(Unit::UNIT_COUNTS));
m_parameters[m_numpeaksname].SetIntVal(10);

m_peakwindowname = "Peak Window";
m_parameters[m_peakwindowname] = FilterParameter(FilterParameter::TYPE_FLOAT, Unit(Unit::UNIT_HZ));
m_parameters[m_peakwindowname].SetFloatVal(500000); //500 kHz between peaks
}

FFTFilter::~FFTFilter()
@@ -199,48 +191,9 @@ void FFTFilter::Refresh()
NormalizeOutput(cap, nouts, npoints);

//Peak search
int64_t max_peaks = m_parameters[m_numpeaksname].GetIntVal();
if(max_peaks > 0)
{
//Get peak search width in bins
float search_hz = m_parameters[m_peakwindowname].GetIntVal();
int64_t search_bins = ceil(search_hz / bin_hz);
int64_t search_rad = search_bins/2;

//Find peaks (TODO: can we vectorize/multithread this?)
//Start at index 1 so we don't waste a marker on the DC peak
vector<FFTPeak> peaks;
for(ssize_t i=1; i<(ssize_t)nouts; i++)
{
ssize_t max_delta = 0;
float max_value = -FLT_MAX;

for(ssize_t delta = -search_rad; delta <= search_rad; delta ++)
{
ssize_t index = i+delta ;
if( (index < 0) || (index >= (ssize_t)nouts) )
continue;

float amp = cap->m_samples[index];
if(amp > max_value)
{
max_value = amp;
max_delta = delta;
}
}

//If the highest point in the search window is at our location, we're a peak
if(max_delta == 0)
peaks.push_back(FFTPeak(bin_hz * i, max_value));
}

//Sort the peak table and pluck out the requested count
sort(peaks.rbegin(), peaks.rend(), less<FFTPeak>());
m_peaks.clear();
for(size_t i=0; i<(size_t)max_peaks && i<peaks.size(); i++)
m_peaks.push_back(peaks[i]);
}
FindPeaks(cap);

//Done
SetData(cap, 0);
}

25 changes: 1 addition & 24 deletions scopeprotocols/FFTFilter.h
Original file line number Diff line number Diff line change
@@ -37,22 +37,7 @@

#include <ffts.h>

class FFTPeak
{
public:
FFTPeak(int64_t freq, float mag)
: m_freq(freq)
, m_mag(mag)
{}

bool operator<(const FFTPeak& rhs) const
{ return (m_mag < rhs.m_mag); }

int64_t m_freq;
float m_mag;
};

class FFTFilter : public Filter
class FFTFilter : public PeakDetectionFilter
{
public:
FFTFilter(std::string color);
@@ -73,9 +58,6 @@ class FFTFilter : public Filter
virtual void SetVoltageRange(double range);
virtual void SetOffset(double offset);

const std::vector<FFTPeak>& GetPeaks()
{ return m_peaks; }

PROTOCOL_DECODER_INITPROC(FFTFilter)

protected:
@@ -89,11 +71,6 @@ class FFTFilter : public Filter

float m_range;
float m_offset;

std::string m_numpeaksname;
std::string m_peakwindowname;

std::vector<FFTPeak> m_peaks;
};

#endif
Loading