Skip to content

Commit

Permalink
WIP: TDR/DFT improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
jankae committed Dec 16, 2024
1 parent 4725942 commit acb79fa
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 51 deletions.
104 changes: 69 additions & 35 deletions Software/PC_Application/LibreVNA-GUI/Traces/Math/dft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ using namespace std;
Math::DFT::DFT()
{
automaticDC = true;
removePaddingFromTDR = true;
revertWindowFromTDR = true;
DCfreq = 1000000000.0;

destructing = false;
Expand Down Expand Up @@ -67,12 +69,23 @@ void Math::DFT::edit()
ui->windowBox->setLayout(new QVBoxLayout);
ui->windowBox->layout()->addWidget(window.createEditor());

connect(ui->DCautomatic, &QRadioButton::toggled, [=](bool automatic){
connect(ui->removePadding, &QCheckBox::toggled, this, [=](bool remove){
removePaddingFromTDR = remove;
});

connect(ui->revertWindow, &QCheckBox::toggled, this, [=](bool revert){
revertWindowFromTDR = revert;
});

connect(ui->DCautomatic, &QRadioButton::toggled, this, [=](bool automatic){
automaticDC = automatic;
ui->freq->setEnabled(!automatic);
updateDFT();
});

ui->removePadding->setChecked(removePaddingFromTDR);
ui->revertWindow->setChecked(revertWindowFromTDR);

if(automaticDC) {
ui->DCautomatic->setChecked(true);
} else {
Expand All @@ -84,7 +97,7 @@ void Math::DFT::edit()
ui->freq->setPrefixes(" kMG");
ui->freq->setValue(DCfreq);

connect(ui->freq, &SIUnitEdit::valueChanged, [=](double newval){
connect(ui->freq, &SIUnitEdit::valueChanged, this, [=](double newval){
DCfreq = newval;
updateDFT();
});
Expand All @@ -111,6 +124,8 @@ nlohmann::json Math::DFT::toJSON()
nlohmann::json j;
j["automatic_DC"] = automaticDC;
j["window"] = window.toJSON();
j["removePadding"] = removePaddingFromTDR;
j["revertWindow"] = revertWindowFromTDR;
if(!automaticDC) {
j["DC"] = DCfreq;
}
Expand All @@ -124,6 +139,8 @@ void Math::DFT::fromJSON(nlohmann::json j)
if(j.contains("window")) {
window.fromJSON(j["window"]);
}
removePaddingFromTDR = j.value("removePadding", true);
revertWindowFromTDR = j.value("revertWindow", true);
}

void Math::DFT::inputSamplesChanged(unsigned int begin, unsigned int end)
Expand Down Expand Up @@ -169,53 +186,68 @@ void Math::DFTThread::run()
qDebug() << "DFT thread exiting";
return;
}
// limit update rate if configured in preferences
auto &p = Preferences::getInstance();
if(p.Acquisition.limitDFT) {
std::this_thread::sleep_until(lastCalc + duration<double>(1.0 / p.Acquisition.maxDFTrate));
lastCalc = system_clock::now();
}
// qDebug() << "DFT thread calculating";
if(!dft.input) {
// not connected, skip calculation
continue;
}
double DC = dft.DCfreq;
TDR *tdr = nullptr;
if(dft.automaticDC) {
// find the last operation that transformed from the frequency domain to the time domain
auto in = dft.input;
while(in->getInput()->getDataType() != DFT::DataType::Frequency) {
in = dft.input->getInput();
}
switch(in->getType()) {
case DFT::Type::TDR: {
tdr = static_cast<TDR*>(in);
if(tdr->getMode() == TDR::Mode::Lowpass) {
DC = 0;
} else {
// bandpass mode, assume DC is in the middle of the frequency data
DC = tdr->getInput()->getSample(tdr->getInput()->numSamples()/2).x;
}
}
break;
default:
// unknown, assume DC is in the middle of the frequency data
DC = in->getInput()->getSample(in->getInput()->numSamples()/2).x;
// find the last TDR operation
auto in = dft.input;
while(in->getType() != DFT::Type::TDR) {
in = dft.input->getInput();
if(!in) {
break;
}
}
if(in) {
tdr = static_cast<TDR*>(in);
}

if(tdr && dft.automaticDC) {
if(tdr->getMode() == TDR::Mode::Lowpass) {
DC = 0;
} else {
// bandpass mode, assume DC is in the middle of the frequency data
DC = tdr->getInput()->getSample(tdr->getInput()->numSamples()/2).x;
}
}
auto samples = dft.input->rData().size();
auto timeSpacing = dft.input->rData()[1].x - dft.input->rData()[0].x;
vector<complex<double>> timeDomain(samples);
for(unsigned int i=0;i<samples;i++) {
timeDomain.at(i) = dft.input->rData()[i].y;
}

Fft::shift(timeDomain, false);
dft.window.apply(timeDomain);
Fft::shift(timeDomain, true);
Fft::transform(timeDomain, false);
// shift DC bin into the middle
Fft::shift(timeDomain, false);

double binSpacing = 1.0 / (timeSpacing * timeDomain.size());

if(tdr) {
// split in padding and actual data sections
unsigned int padding = timeDomain.size() - tdr->getUnpaddedInputSize();
std::vector<std::complex<double>> pad_front(timeDomain.begin(), timeDomain.begin()+padding/2);
std::vector<std::complex<double>> data(timeDomain.begin()+padding/2, timeDomain.end()-padding/2);
std::vector<std::complex<double>> pad_back(timeDomain.end()-padding/2, timeDomain.end());

if(dft.revertWindowFromTDR) {
tdr->getWindow().reverse(data);
}

if(dft.removePaddingFromTDR) {
timeDomain = data;
} else {
// include padding
timeDomain = pad_front;
copy(data.begin(), data.end(), back_inserter(timeDomain));
copy(pad_back.begin(), pad_back.end(), back_inserter(timeDomain));
}
}

dft.data.clear();
int DCbin = timeDomain.size() / 2, startBin = 0;
if(DC > 0) {
Expand All @@ -225,16 +257,18 @@ void Math::DFTThread::run()
dft.data.resize(timeDomain.size()/2, TraceMath::Data());
}

// reverse effect of frequency domain window function from TDR (if available)
if(tdr) {
tdr->getWindow().reverse(timeDomain);
}

for(int i = startBin;(unsigned int) i<timeDomain.size();i++) {
auto freq = (i - DCbin) * binSpacing + DC;
dft.data[i - startBin].x = round(freq);
dft.data[i - startBin].y = timeDomain.at(i);
}
emit dft.outputSamplesChanged(0, dft.data.size());

// limit update rate if configured in preferences
auto &p = Preferences::getInstance();
if(p.Acquisition.limitDFT) {
std::this_thread::sleep_until(lastCalc + duration<double>(1.0 / p.Acquisition.maxDFTrate));
lastCalc = system_clock::now();
}
}
}
2 changes: 2 additions & 0 deletions Software/PC_Application/LibreVNA-GUI/Traces/Math/dft.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public slots:
bool automaticDC;
double DCfreq;
WindowFunction window;
bool removePaddingFromTDR;
bool revertWindowFromTDR;
DFTThread *thread;
bool destructing;
QSemaphore semphr;
Expand Down
20 changes: 17 additions & 3 deletions Software/PC_Application/LibreVNA-GUI/Traces/Math/dftdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<class>DFTDialog</class>
<widget class="QDialog" name="DFTDialog">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
<enum>Qt::WindowModality::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
Expand All @@ -19,7 +19,21 @@
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,1,0">
<item>
<widget class="QCheckBox" name="removePadding">
<property name="text">
<string>Remove possible padding from last TDR</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="revertWindow">
<property name="text">
<string>Revert window function from last TDR</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
Expand Down Expand Up @@ -83,7 +97,7 @@
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
<set>QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>
Expand Down
47 changes: 36 additions & 11 deletions Software/PC_Application/LibreVNA-GUI/Traces/Math/tdr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ TDR::TDR()
manualDC = 1.0;
stepResponse = true;
mode = Mode::Lowpass;
padding = 0;

destructing = false;
thread = new TDRThread(*this);
Expand Down Expand Up @@ -86,19 +87,23 @@ void TDR::edit()
ui->manualMag->setEnabled(enable);
};

connect(ui->mode, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index){
connect(ui->mode, qOverload<int>(&QComboBox::currentIndexChanged), this, [=](int index){
mode = (Mode) index;
updateEnabledWidgets();
updateTDR();
});

connect(ui->computeStepResponse, &QCheckBox::toggled, [=](bool computeStep) {
connect(ui->padding, &QSpinBox::valueChanged, this, [=](int value) {
padding = value;
});

connect(ui->computeStepResponse, &QCheckBox::toggled, this, [=](bool computeStep) {
stepResponse = computeStep;
updateEnabledWidgets();
updateTDR();
});

connect(ui->DCmanual, &QRadioButton::toggled, [=](bool manual) {
connect(ui->DCmanual, &QRadioButton::toggled, this, [=](bool manual) {
automaticDC = !manual;
updateEnabledWidgets();
updateTDR();
Expand All @@ -114,18 +119,20 @@ void TDR::edit()
ui->mode->setCurrentIndex(1);
}

ui->padding->setValue(padding);

ui->manualMag->setUnit("dBm");
ui->manualMag->setPrecision(3);
ui->manualMag->setValue(Util::SparamTodB(manualDC));
ui->manualPhase->setUnit("°");
ui->manualPhase->setPrecision(4);
ui->manualPhase->setValue(180.0/M_PI * arg(manualDC));

connect(ui->manualMag, &SIUnitEdit::valueChanged, [=](double newval){
connect(ui->manualMag, &SIUnitEdit::valueChanged, this, [=](double newval){
manualDC = polar(pow(10, newval / 20.0), arg(manualDC));
updateTDR();
});
connect(ui->manualPhase, &SIUnitEdit::valueChanged, [=](double newval){
connect(ui->manualPhase, &SIUnitEdit::valueChanged, this, [=](double newval){
manualDC = polar(abs(manualDC), newval * M_PI / 180.0);
updateTDR();
});
Expand All @@ -152,6 +159,7 @@ nlohmann::json TDR::toJSON()
nlohmann::json j;
j["bandpass_mode"] = mode == Mode::Bandpass;
j["window"] = window.toJSON();
j["padding"] = padding;
if(mode == Mode::Lowpass) {
j["step_response"] = stepResponse;
if(stepResponse) {
Expand All @@ -170,6 +178,7 @@ void TDR::fromJSON(nlohmann::json j)
if(j.contains("window")) {
window.fromJSON(j["window"]);
}
padding = j.value("padding", 0);
if(j.value("bandpass_mode", true)) {
mode = Mode::Bandpass;
} else {
Expand Down Expand Up @@ -224,6 +233,11 @@ void TDR::updateTDR()
}
}

unsigned int TDR::getUnpaddedInputSize() const
{
return unpaddedInputSize;
}

const WindowFunction& TDR::getWindow() const
{
return window;
Expand Down Expand Up @@ -254,14 +268,12 @@ void TDRThread::run()
qDebug() << "TDR thread exiting";
return;
}
// limit update rate if configured in preferences
auto &p = Preferences::getInstance();
if(p.Acquisition.limitDFT) {
std::this_thread::sleep_until(lastCalc + duration<double>(1.0 / p.Acquisition.maxDFTrate));
lastCalc = system_clock::now();
}
// qDebug() << "TDR thread calculating";
// perform calculation
if(!tdr.input) {
// not connected, skip calculation
continue;
}
vector<complex<double>> frequencyDomain;
auto stepSize = (tdr.input->rData().back().x - tdr.input->rData().front().x) / (tdr.input->rData().size() - 1);
if(tdr.mode == TDR::Mode::Lowpass) {
Expand Down Expand Up @@ -321,6 +333,12 @@ void TDRThread::run()
}

tdr.window.apply(frequencyDomain);
tdr.unpaddedInputSize = frequencyDomain.size();
if(frequencyDomain.size() < tdr.padding) {
auto missing = tdr.padding - frequencyDomain.size();
frequencyDomain.insert(frequencyDomain.begin(), missing/2, 0);
frequencyDomain.insert(frequencyDomain.end(), missing/2, 0);
}
Fft::shift(frequencyDomain, true);

int fft_bins = frequencyDomain.size();
Expand All @@ -341,5 +359,12 @@ void TDRThread::run()
tdr.updateStepResponse(false);
}
emit tdr.outputSamplesChanged(0, tdr.data.size());

// limit update rate if configured in preferences
auto &p = Preferences::getInstance();
if(p.Acquisition.limitDFT) {
std::this_thread::sleep_until(lastCalc + duration<double>(1.0 / p.Acquisition.maxDFTrate));
lastCalc = system_clock::now();
}
}
}
4 changes: 4 additions & 0 deletions Software/PC_Application/LibreVNA-GUI/Traces/Math/tdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,17 @@ class TDR : public TraceMath
Mode getMode() const;
const WindowFunction& getWindow() const;

unsigned int getUnpaddedInputSize() const;

public slots:
void inputSamplesChanged(unsigned int begin, unsigned int end) override;

private:
void updateTDR();
Mode mode;
WindowFunction window;
unsigned int padding;
unsigned int unpaddedInputSize;
bool stepResponse;
bool automaticDC;
std::complex<double> manualDC;
Expand Down
Loading

0 comments on commit acb79fa

Please sign in to comment.