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

Commits on Nov 28, 2020

  1. Copy the full SHA
    f3b768a View commit details
  2. Fixed several bugs from refactoring. Initial support for loading lega…

    …cy picosecond-resolution files as well as loading and saving femtosecond-resolution.
    azonenberg committed Nov 28, 2020
    Copy the full SHA
    6bbaf39 View commit details
2 changes: 1 addition & 1 deletion lib
Submodule lib updated 114 files
18 changes: 9 additions & 9 deletions src/examples/impulse/main.cpp
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ int main(int argc, char* argv[])
//Initialize
AlignedAllocator< float, 64 > allocator;
size_t npoints = 131072;
size_t ps_per_sample = 1;
size_t fs_per_sample = 1000;
double sample_ghz = 1000;
double bin_hz = round((0.5f * sample_ghz * 1e9f) / npoints);
ffts_plan_t* forwardPlan = ffts_init_1d_real(npoints, FFTS_FORWARD);
@@ -147,20 +147,20 @@ int main(int argc, char* argv[])
}

//Calculate maximum group delay for the first few S21 bins (approx propagation delay of the channel)
int64_t groupdelay_samples = ceil( GetGroupDelay(params[SPair(2,1)]) / ps_per_sample );
int64_t groupdelay_samples = ceil( GetGroupDelay(params[SPair(2,1)]) / fs_per_sample );
if( (groupdelay_samples < 0) || (groupdelay_samples >= (int64_t)npoints) )
{
LogWarning("Calculated invalid group delay = %ld\n", groupdelay_samples);
groupdelay_samples = 0;
}

//Write the output
LogNotice("ps, s11, s21, s12, s22\n");
LogNotice("fs, s11, s21, s12, s22\n");
float tstart = nmid;
for(size_t i=groupdelay_samples; i<npoints; i++)
{
LogNotice("%.0f, %f, %f, %f, %f\n",
(i*ps_per_sample) - tstart,
(i*fs_per_sample) - tstart,
dttime[0][0][i],
dttime[1][0][i],
dttime[0][1][i],
@@ -173,7 +173,7 @@ int main(int argc, char* argv[])
for(size_t i=groupdelay_samples; i<npoints; i++)
{
wfm.m_offsets.push_back(i);
wfm.m_durations.push_back(ps_per_sample);
wfm.m_durations.push_back(fs_per_sample);
wfm.m_samples.push_back(dttime[1][0][i]);
}
float base = Filter::GetBaseVoltage(&wfm);
@@ -208,9 +208,9 @@ int main(int argc, char* argv[])
}

//Print stats
Unit ps(Unit::UNIT_PS);
LogWarning("20-80%%: %s\n", ps.PrettyPrint( (t80-t20) * ps_per_sample).c_str());
LogWarning("10-90%%: %s\n", ps.PrettyPrint( (t90-t10) * ps_per_sample).c_str());
Unit fs(Unit::UNIT_FS);
LogWarning("20-80%%: %s\n", fs.PrettyPrint( (t80-t20) * fs_per_sample).c_str());
LogWarning("10-90%%: %s\n", fs.PrettyPrint( (t90-t10) * fs_per_sample).c_str());

//Clean up
ffts_free(forwardPlan);
@@ -233,5 +233,5 @@ int64_t GetGroupDelay(SParameterVector& vec)
size_t n = vec.size();
for(size_t i=n/4; i<n*3/4; i++)
max_delay = max(max_delay, vec.GetGroupDelay(i));
return max_delay * 1e12;
return max_delay * FS_PER_SECOND;
}
10 changes: 5 additions & 5 deletions src/examples/usbcsv/main.cpp
Original file line number Diff line number Diff line change
@@ -137,7 +137,7 @@ bool ProcessWaveform(MockOscilloscope* scope, const string& fname, USB2PacketDec
return false;
}

Unit ps(Unit::UNIT_PS);
Unit fs(Unit::UNIT_FS);

//Print the protocol analyzer data
LogNotice("Printing packets\n");
@@ -150,8 +150,8 @@ bool ProcessWaveform(MockOscilloscope* scope, const string& fname, USB2PacketDec
auto pack = packets[i];

LogNotice("[%11s] len=%s type=%6s dev=%1s endp=%1s len=%3s info=%s\n",
ps.PrettyPrint(pack->m_offset).c_str(),
ps.PrettyPrint(pack->m_len).c_str(),
fs.PrettyPrint(pack->m_offset).c_str(),
fs.PrettyPrint(pack->m_len).c_str(),
pack->m_headers["Type"].c_str(),
pack->m_headers["Device"].c_str(),
pack->m_headers["Endpoint"].c_str(),
@@ -284,8 +284,8 @@ bool ProcessWaveform(MockOscilloscope* scope, const string& fname, USB2PacketDec
}

LogNotice("[%11s] len=%11s %-15s %02x\n",
ps.PrettyPrint(timestamp).c_str(),
ps.PrettyPrint(duration).c_str(),
fs.PrettyPrint(timestamp).c_str(),
fs.PrettyPrint(duration).c_str(),
type.c_str(),
sym.m_data);
}
8 changes: 4 additions & 4 deletions src/glscopeclient/ChannelPropertiesDialog.cpp
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ ChannelPropertiesDialog::ChannelPropertiesDialog(
auto scope = chan->GetScope();
auto index = chan->GetIndex();

Unit ps(Unit::UNIT_PS);
Unit fs(Unit::UNIT_FS);
Unit volts(Unit::UNIT_VOLTS);
Unit hz(Unit::UNIT_HZ);

@@ -105,7 +105,7 @@ ChannelPropertiesDialog::ChannelPropertiesDialog(
m_deskewLabel.set_halign(Gtk::ALIGN_START);
m_grid.attach_next_to(m_deskewEntry, m_deskewLabel, Gtk::POS_RIGHT, 1, 1);
m_hasDeskew = true;
m_deskewEntry.set_text(ps.PrettyPrint(chan->GetDeskew()));
m_deskewEntry.set_text(fs.PrettyPrint(chan->GetDeskew()));

//Attenuation
m_grid.attach_next_to(m_attenuationLabel, m_deskewLabel, Gtk::POS_BOTTOM, 1, 1);
@@ -280,7 +280,7 @@ void ChannelPropertiesDialog::ConfigureChannel()
m_chan->m_displaycolor = m_channelColorButton.get_color().to_string();

Unit volts(Unit::UNIT_VOLTS);
Unit ps(Unit::UNIT_PS);
Unit fs(Unit::UNIT_FS);
Unit hz(Unit::UNIT_HZ);

if(m_hasThreshold)
@@ -293,7 +293,7 @@ void ChannelPropertiesDialog::ConfigureChannel()
m_chan->SetCenterFrequency(hz.ParseString(m_centerEntry.get_text()));

if(m_hasDeskew)
m_chan->SetDeskew(ps.ParseString(m_deskewEntry.get_text()));
m_chan->SetDeskew(fs.ParseString(m_deskewEntry.get_text()));

if(m_hasAttenuation)
m_chan->SetAttenuation(stof(m_attenuationEntry.get_text()));
8 changes: 4 additions & 4 deletions src/glscopeclient/HistoryWindow.cpp
Original file line number Diff line number Diff line change
@@ -152,13 +152,13 @@ void HistoryWindow::OnWaveformDataReady()
//round to nearest 100ps for display
strftime(tmp, sizeof(tmp), "%H:%M:%S.", &ltime);
string stime = tmp;
snprintf(tmp, sizeof(tmp), "%010zu", static_cast<size_t>(data->m_startPicoseconds / 100));
snprintf(tmp, sizeof(tmp), "%010zu", static_cast<size_t>(data->m_startFemtoseconds / 100000));
stime += tmp;

//Create the row
auto row = *m_model->append();
row[m_columns.m_timestamp] = stime;
TimePoint key(data->m_startTimestamp, data->m_startPicoseconds);
TimePoint key(data->m_startTimestamp, data->m_startFemtoseconds);
row[m_columns.m_capturekey] = key;

//Add waveform data
@@ -347,7 +347,7 @@ void HistoryWindow::SerializeWaveforms(string dir, IDTable& table)
config += " :\n";
snprintf(tmp, sizeof(tmp), " timestamp: %ld\n", key.first);
config += tmp;
snprintf(tmp, sizeof(tmp), " time_psec: %ld\n", key.second);
snprintf(tmp, sizeof(tmp), " time_fsec: %ld\n", key.second);
config += tmp;
snprintf(tmp, sizeof(tmp), " id: %d\n", id);
config += tmp;
@@ -391,7 +391,7 @@ void HistoryWindow::SerializeWaveforms(string dir, IDTable& table)
config += tmp;
snprintf(tmp, sizeof(tmp), " timescale: %ld\n", wave->m_timescale);
config += tmp;
snprintf(tmp, sizeof(tmp), " trigphase: %f\n", wave->m_triggerPhase);
snprintf(tmp, sizeof(tmp), " trigphase: %zu\n", wave->m_triggerPhase);
config += tmp;

//Save channel data
57 changes: 50 additions & 7 deletions src/glscopeclient/OscilloscopeWindow.cpp
Original file line number Diff line number Diff line change
@@ -949,9 +949,19 @@ void OscilloscopeWindow::LoadWaveformDataForScope(
iwave ++;

//Top level metadata
bool timebase_is_ps = true;
auto wfm = it.second;
time.first = wfm["timestamp"].as<long long>();
time.second = wfm["time_psec"].as<long long>();
if(wfm["time_psec"])
{
time.second = wfm["time_psec"].as<long long>() * 1000;
timebase_is_ps = true;
}
else
{
time.second = wfm["time_fsec"].as<long long>();
timebase_is_ps = false;
}
int waveform_id = wfm["id"].as<int>();

//Set up channel metadata first (serialized)
@@ -979,8 +989,14 @@ void OscilloscopeWindow::LoadWaveformDataForScope(
//Channel waveform metadata
cap->m_timescale = ch["timescale"].as<long>();
cap->m_startTimestamp = time.first;
cap->m_startPicoseconds = time.second;
cap->m_triggerPhase = ch["trigphase"].as<float>();
cap->m_startFemtoseconds = time.second;
if(timebase_is_ps)
{
cap->m_timescale *= 1000;
cap->m_triggerPhase = ch["trigphase"].as<float>() * 1000;
}
else
cap->m_triggerPhase = ch["trigphase"].as<long>();

chan->Detach(stream);
chan->SetData(cap, stream);
@@ -1003,6 +1019,7 @@ void OscilloscopeWindow::LoadWaveformDataForScope(
datadir,
scope_id,
waveform_id,
timebase_is_ps,
channel_progress + i,
channel_done + i
));
@@ -1072,6 +1089,7 @@ void OscilloscopeWindow::DoLoadWaveformDataForScope(
string datadir,
int scope_id,
int waveform_id,
bool timebase_is_ps,
volatile float* progress,
volatile int* done
)
@@ -1151,8 +1169,16 @@ void OscilloscopeWindow::DoLoadWaveformDataForScope(
int64_t* stime = reinterpret_cast<int64_t*>(buf+offset);
offset += 2*sizeof(int64_t);

cap->m_offsets[j] = stime[0];
cap->m_durations[j] = stime[1];
if(timebase_is_ps)
{
cap->m_offsets[j] = stime[0] * 1000;
cap->m_durations[j] = stime[1] * 1000;
}
else
{
cap->m_offsets[j] = stime[0];
cap->m_durations[j] = stime[1];
}

//Read sample data
if(acap)
@@ -1362,9 +1388,16 @@ void OscilloscopeWindow::LoadUIConfiguration(const YAML::Node& node, IDTable& ta
WaveformGroup* group = new WaveformGroup(this);
table.emplace(gn["id"].as<int>(), &group->m_frame);
group->m_frame.set_label(gn["name"].as<string>());

//Scale if needed
bool timestamps_are_ps = true;
if(gn["timebaseResolution"])
{
if(gn["timebaseResolution"].as<string>() == "fs")
timestamps_are_ps = false;
}

group->m_pixelsPerXUnit = gn["pixelsPerXUnit"].as<float>();
if(group->m_pixelsPerXUnit < 1e-8) //Sanity check impractically small zoom levels
group->m_pixelsPerXUnit = 0.05;
group->m_xAxisOffset = gn["xAxisOffset"].as<long>();
m_waveformGroups.emplace(group);

@@ -1385,6 +1418,16 @@ void OscilloscopeWindow::LoadUIConfiguration(const YAML::Node& node, IDTable& ta
group->m_yCursorPos[0] = gn["ycursor0"].as<float>();
group->m_yCursorPos[1] = gn["ycursor1"].as<float>();

if(timestamps_are_ps)
{
group->m_pixelsPerXUnit *= 1000;
group->m_xAxisOffset *= 1000;
group->m_xCursorPos[0] *= 1000;
group->m_xCursorPos[1] *= 1000;
group->m_yCursorPos[0] *= 1000;
group->m_yCursorPos[1] *= 1000;
}

//TODO: statistics

//Waveform areas
1 change: 1 addition & 0 deletions src/glscopeclient/OscilloscopeWindow.h
Original file line number Diff line number Diff line change
@@ -255,6 +255,7 @@ class OscilloscopeWindow : public Gtk::Window
std::string datadir,
int scope_id,
int waveform_id,
bool timebase_is_ps,
volatile float* progress,
volatile int* done
);
13 changes: 6 additions & 7 deletions src/glscopeclient/ProtocolAnalyzerWindow.cpp
Original file line number Diff line number Diff line change
@@ -585,26 +585,25 @@ void ProtocolAnalyzerWindow::FillOutRow(
{
//Need a bit of math in case the capture is >1 second long
time_t capstart = data->m_startTimestamp;
int64_t ps = data->m_startPicoseconds + p->m_offset;
const int64_t seconds_per_ps = 1000ll * 1000ll * 1000ll * 1000ll;
if(ps > seconds_per_ps)
int64_t fs = data->m_startFemtoseconds + p->m_offset;
if(fs > FS_PER_SECOND)
{
capstart += (ps / seconds_per_ps);
ps %= seconds_per_ps;
capstart += (fs / FS_PER_SECOND);
fs %= (int64_t)FS_PER_SECOND;
}

//Format timestamp
char tmp[128];
strftime(tmp, sizeof(tmp), "%H:%M:%S.", localtime(&capstart));
string stime = tmp;
snprintf(tmp, sizeof(tmp), "%010zu", static_cast<size_t>(ps / 100)); //round to nearest 100ps for display
snprintf(tmp, sizeof(tmp), "%010zu", static_cast<size_t>(fs / 100000)); //round to nearest 100ps for display
stime += tmp;

//Create the row
row[m_columns.m_bgcolor] = p->m_displayBackgroundColor;
row[m_columns.m_fgcolor] = p->m_displayForegroundColor;
row[m_columns.m_timestamp] = stime;
row[m_columns.m_capturekey] = TimePoint(data->m_startTimestamp, data->m_startPicoseconds);
row[m_columns.m_capturekey] = TimePoint(data->m_startTimestamp, data->m_startFemtoseconds);
row[m_columns.m_offset] = p->m_offset;

//Just copy headers without any processing
12 changes: 6 additions & 6 deletions src/glscopeclient/ScopeSyncWizard.cpp
Original file line number Diff line number Diff line change
@@ -369,8 +369,8 @@ bool ScopeSyncWizard::OnTimer()
#pragma omp parallel for
for(int64_t d = m_delta; d < blockEnd; d ++)
{
//Convert delta from samples of the primary waveform to picoseconds
int64_t deltaPs = m_primaryWaveform->m_timescale * d;
//Convert delta from samples of the primary waveform to femtoseconds
int64_t deltaFs = m_primaryWaveform->m_timescale * d;

//Loop over samples in the primary waveform
//TODO: AVX
@@ -379,11 +379,11 @@ bool ScopeSyncWizard::OnTimer()
double correlation = 0;
for(size_t i=0; i<(size_t)len; i++)
{
//Timestamp of this sample, in ps
//Timestamp of this sample, in fs
int64_t start = m_primaryWaveform->m_offsets[i] * m_primaryWaveform->m_timescale;

//Target timestamp in the secondary waveform
int64_t target = start + deltaPs;
int64_t target = start + deltaFs;

//If off the start of the waveform, skip it
if(target < 0)
@@ -430,7 +430,7 @@ bool ScopeSyncWizard::OnTimer()
//Collect the skew from this round
auto scope = m_activeSecondaryPage->GetScope();
int64_t skew = m_bestCorrelationOffset * m_primaryWaveform->m_timescale;
LogTrace("Best correlation = %f (delta = %ld / %ld ps)\n",
LogTrace("Best correlation = %f (delta = %ld / %ld fs)\n",
m_bestCorrelation, m_bestCorrelationOffset, skew);
m_averageSkews.push_back(skew);

@@ -462,7 +462,7 @@ bool ScopeSyncWizard::OnTimer()
for(auto f : m_averageSkews)
sum += f;
skew = static_cast<int64_t>(round(sum / m_numAverages));
LogTrace("Average skew = %ld ps\n", skew);
LogTrace("Average skew = %ld fs\n", skew);

//Figure out where we want the secondary to go
int64_t targetOffset = scope->GetTriggerOffset() - skew;
Loading