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: e896453d5b2d
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 297c5d284e01
Choose a head ref
  • 2 commits
  • 8 files changed
  • 1 contributor

Commits on Nov 28, 2020

  1. Copy the full SHA
    371dd6a View commit details
  2. Copy the full SHA
    297c5d2 View commit details
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
I2CEepromDecoder.cpp
IBM8b10bDecoder.cpp
IPv4Decoder.cpp
JitterSpectrumFilter.cpp
JtagDecoder.cpp
MagnitudeFilter.cpp
MDIODecoder.cpp
23 changes: 18 additions & 5 deletions scopeprotocols/FFTFilter.cpp
Original file line number Diff line number Diff line change
@@ -49,6 +49,7 @@ FFTFilter::FFTFilter(const string& color)
CreateInput("din");

m_cachedNumPoints = 0;
m_cachedNumPointsFFT = 0;
m_rdin = NULL;
m_rdout = NULL;
m_plan = NULL;
@@ -144,16 +145,23 @@ void FFTFilter::ReallocateBuffers(size_t npoints_raw, size_t npoints, size_t nou
{
m_cachedNumPoints = npoints_raw;

if(m_cachedNumPointsFFT != npoints)
{
m_cachedNumPointsFFT = npoints;

if(m_plan)
ffts_free(m_plan);

m_plan = ffts_init_1d_real(npoints, FFTS_FORWARD);
}

if(m_rdin)
g_floatVectorAllocator.deallocate(m_rdin);
if(m_rdout)
g_floatVectorAllocator.deallocate(m_rdout);
if(m_plan)
ffts_free(m_plan);

m_rdin = g_floatVectorAllocator.allocate(npoints);
m_rdout = g_floatVectorAllocator.allocate(2*nouts);
m_plan = ffts_init_1d_real(npoints, FFTS_FORWARD);
}

void FFTFilter::Refresh()
@@ -186,6 +194,12 @@ void FFTFilter::Refresh()
static_cast<WindowFunction>(m_parameters[m_windowName].GetIntVal()));
memset(m_rdin + npoints_raw, 0, (npoints - npoints_raw) * sizeof(float));

double ps = din->m_timescale * (din->m_offsets[1] - din->m_offsets[0]);
DoRefresh(din, ps, npoints, nouts);
}

void FFTFilter::DoRefresh(AnalogWaveform* din, double ps_per_sample, size_t npoints, size_t nouts)
{
//Calculate the FFT
ffts_execute(m_plan, m_rdin, m_rdout);

@@ -195,8 +209,7 @@ void FFTFilter::Refresh()
cap->m_startPicoseconds = din->m_startPicoseconds;

//Calculate size of each bin
double ps = din->m_timescale * (din->m_offsets[1] - din->m_offsets[0]);
double sample_ghz = 1000 / ps;
double sample_ghz = 1000 / ps_per_sample;
double bin_hz = round((0.5f * sample_ghz * 1e9f) / nouts);
cap->m_timescale = bin_hz;
LogTrace("bin_hz: %f\n", bin_hz);
3 changes: 3 additions & 0 deletions scopeprotocols/FFTFilter.h
Original file line number Diff line number Diff line change
@@ -83,7 +83,10 @@ class FFTFilter : public PeakDetectionFilter

void ReallocateBuffers(size_t npoints_raw, size_t npoints, size_t nouts);

void DoRefresh(AnalogWaveform* din, double ps_per_sample, size_t npoints, size_t nouts);

size_t m_cachedNumPoints;
size_t m_cachedNumPointsFFT;
float* m_rdin;
float* m_rdout;
ffts_plan_t* m_plan;
208 changes: 208 additions & 0 deletions scopeprotocols/JitterSpectrumFilter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/***********************************************************************************************************************
* *
* 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 "JitterSpectrumFilter.h"
#include <immintrin.h>

using namespace std;

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

JitterSpectrumFilter::JitterSpectrumFilter(const string& color)
: FFTFilter(color)
{
m_xAxisUnit = Unit(Unit::UNIT_HZ);
m_yAxisUnit = Unit(Unit::UNIT_PS);
m_category = CAT_ANALYSIS;
}

JitterSpectrumFilter::~JitterSpectrumFilter()
{

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Factory methods


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Accessors

string JitterSpectrumFilter::GetProtocolName()
{
return "Jitter Spectrum";
}

void JitterSpectrumFilter::SetDefaultName()
{
char hwname[256];
snprintf(hwname, sizeof(hwname), "JitterSpectrum(%s)", GetInputDisplayName(0).c_str());
m_hwname = hwname;
m_displayname = m_hwname;
}

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

size_t JitterSpectrumFilter::EstimateUIWidth(AnalogWaveform* din)
{
//Make a histogram of sample durations
size_t inlen = din->m_samples.size();
map<int64_t, size_t> durations;
int64_t maxdur = 0;
for(size_t i=0; i<inlen; i++)
{
int64_t dur = din->m_durations[i];
maxdur = max(dur, maxdur);
if(dur > 0)
durations[dur] ++;
}

//Find peaks in the histogram.
//These should occur at integer multiples of the unit interval.
vector<int64_t> peaks;
for(auto it : durations)
{
//See if this is a peak
int64_t dur = it.first;
int64_t leftbound = dur * 90 / 100;
int64_t rightbound = dur * 110 / 100;
size_t target = it.second;

bool peak = true;
for(int64_t i=leftbound; i<=rightbound; i++)
{
auto jt = durations.find(i);
if(jt == durations.end())
continue;
if(jt->second > target)
peak = false;
}
if(peak)
peaks.push_back(dur);
}

//The lowest peak that's still reasonably tall is our estimated UI.
//This doesn't need to be super precise yet (up to 20% error should be pretty harmless).
//At this point, we just need an approximate threshold for determining how many UIs apart two edges are.
size_t max_height = 0;
for(auto dur : peaks)
max_height = max(max_height, durations[dur]);
int64_t ui_width = 0;
size_t threshold_height = max_height / 10;
for(auto dur : peaks)
{
if(durations[dur] > threshold_height)
{
ui_width = dur;
break;
}
}
LogTrace("Initial UI width estimate: %zu\n", ui_width);

//Take a weighted average to smooth out the peak location somewhat.
int64_t leftbound = ui_width * 90 / 100;
int64_t rightbound = ui_width * 110 / 100;
size_t ui_width_samples = 0;
ui_width = 0;
for(int64_t i=leftbound; i<=rightbound; i++)
{
auto jt = durations.find(i);
if(jt == durations.end())
continue;
ui_width_samples += jt->second;
ui_width += jt->first * jt->second;
}
ui_width /= ui_width_samples;
LogTrace("Averaged UI width estimate: %zu\n", ui_width);

return ui_width;
}

void JitterSpectrumFilter::Refresh()
{
//Make sure we've got valid inputs
if(!VerifyAllInputsOKAndAnalog())
{
SetData(NULL, 0);
return;
}
auto din = GetAnalogInputWaveform(0);

//Get an initial estimate of the UI width for the waveform
size_t inlen = din->m_samples.size();
size_t ui_width = EstimateUIWidth(din);

//Loop over the input and copy samples.
vector<float, AlignedAllocator<float, 64>> extended_samples;
extended_samples.reserve(inlen);
for(size_t i=0; i<inlen; i++)
{
//Add the base sample
extended_samples.push_back(din->m_samples[i]);

//If we have gaps between UIs, fill them with zeroes (no jitter).
//TODO: interpolate?
int64_t nui = round(1.0 * din->m_durations[i] / ui_width);
for(int64_t j=1; j<nui; j++)
extended_samples.push_back(0);
}

//Refine our estimate of the final UI width.
//This needs to be fairly precise as the timebase for converting FFT bins to frequency is derived from it.
size_t capture_duration = din->m_offsets[inlen-1] + din->m_durations[inlen-1];
size_t num_uis = extended_samples.size();
double ui_width_final = static_cast<double>(capture_duration) / num_uis;
LogTrace("Final UI width estimate: %.1f\n", ui_width_final);

//Round size up to next power of two
const size_t npoints_raw = extended_samples.size();
const size_t npoints = pow(2, ceil(log2(npoints_raw)));
LogTrace("JitterSpectrumFilter: processing %zu raw points\n", npoints_raw);
LogTrace("Rounded to %zu\n", npoints);

//Reallocate buffers if size has changed
const size_t nouts = npoints/2 + 1;
if(m_cachedNumPoints != npoints_raw)
ReallocateBuffers(npoints_raw, npoints, nouts);

//Copy the input with windowing, then zero pad to the desired input length
ApplyWindow(
&extended_samples[0],
npoints_raw,
m_rdin,
static_cast<WindowFunction>(m_parameters[m_windowName].GetIntVal()));
memset(m_rdin + npoints_raw, 0, (npoints - npoints_raw) * sizeof(float));

//and do the actual FFT processing
DoRefresh(din, ui_width_final, nouts, npoints);
}
57 changes: 57 additions & 0 deletions scopeprotocols/JitterSpectrumFilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/***********************************************************************************************************************
* *
* 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 JitterSpectrumFilter
*/
#ifndef JitterSpectrumFilter_h
#define JitterSpectrumFilter_h

#include "FFTFilter.h"

class JitterSpectrumFilter : public FFTFilter
{
public:
JitterSpectrumFilter(const std::string& color);
virtual ~JitterSpectrumFilter();

virtual void Refresh();

static std::string GetProtocolName();
virtual void SetDefaultName();

PROTOCOL_DECODER_INITPROC(JitterSpectrumFilter)

protected:
size_t EstimateUIWidth(AnalogWaveform* din);
};

#endif
9 changes: 8 additions & 1 deletion scopeprotocols/TIEMeasurement.cpp
Original file line number Diff line number Diff line change
@@ -128,6 +128,7 @@ void TIEMeasurement::Refresh()

//For each input clock edge, find the closest recovered clock edge
size_t iedge = 0;
size_t tlast = 0;
for(auto atime : edges)
{
if(iedge >= len)
@@ -179,10 +180,16 @@ void TIEMeasurement::Refresh()
golden_center += 1.5*clk->m_timescale; //TODO: why is this needed?
int64_t tie = atime - golden_center;

//Update the last sample
size_t end = cap->m_durations.size();
if(end)
cap->m_durations[end-1] = atime - tlast;

m_maxTie = max(m_maxTie, fabs(tie));
cap->m_offsets.push_back(atime);
cap->m_durations.push_back(golden_period);
cap->m_durations.push_back(0);
cap->m_samples.push_back(tie);
tlast = atime;
}

SetData(cap, 0);
1 change: 1 addition & 0 deletions scopeprotocols/scopeprotocols.cpp
Original file line number Diff line number Diff line change
@@ -87,6 +87,7 @@ void ScopeProtocolStaticInit()
AddDecoderClass(I2CEepromDecoder);
AddDecoderClass(IBM8b10bDecoder);
AddDecoderClass(IPv4Decoder);
AddDecoderClass(JitterSpectrumFilter);
AddDecoderClass(JtagDecoder);
AddDecoderClass(MagnitudeFilter);
AddDecoderClass(MDIODecoder);
1 change: 1 addition & 0 deletions scopeprotocols/scopeprotocols.h
Original file line number Diff line number Diff line change
@@ -87,6 +87,7 @@
#include "I2CDecoder.h"
#include "I2CEepromDecoder.h"
#include "IPv4Decoder.h"
#include "JitterSpectrumFilter.h"
#include "JtagDecoder.h"
#include "MagnitudeFilter.h"
#include "MDIODecoder.h"