diff --git a/Software/PC_Application/Calibration/amplitudecaldialog.cpp b/Software/PC_Application/Calibration/amplitudecaldialog.cpp index 80912e6..e0c37d7 100644 --- a/Software/PC_Application/Calibration/amplitudecaldialog.cpp +++ b/Software/PC_Application/Calibration/amplitudecaldialog.cpp @@ -425,7 +425,7 @@ void AmplitudeCalDialog::AutomaticMeasurementDialog() void AmplitudeCalDialog::ReceivedMeasurement(Protocol::SpectrumAnalyzerResult res) { - MeasurementResult m = {.port1 = Util::SparamTodB(res.port1), .port2 = Util::SparamTodB(res.port2)}; + MeasurementResult m = {.port1 = Util::SparamTodB(complex(res.real_port1, res.imag_port1)), .port2 = Util::SparamTodB(complex(res.real_port2, res.imag_port2))}; sweepMeasurements.push_back(m); if(res.pointNum == automaticSweepPoints - 1) { // sweep finished, find maximum for each port diff --git a/Software/PC_Application/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI.pro index b12ef96..1fa409d 100644 --- a/Software/PC_Application/LibreVNA-GUI.pro +++ b/Software/PC_Application/LibreVNA-GUI.pro @@ -24,6 +24,7 @@ HEADERS += \ Device/manualcontroldialog.h \ Generator/generator.h \ Generator/signalgenwidget.h \ + SpectrumAnalyzer/sadata.h \ SpectrumAnalyzer/spectrumanalyzer.h \ SpectrumAnalyzer/tracewidgetsa.h \ Tools/eseries.h \ diff --git a/Software/PC_Application/SpectrumAnalyzer/sadata.h b/Software/PC_Application/SpectrumAnalyzer/sadata.h new file mode 100644 index 0000000..a94cb4c --- /dev/null +++ b/Software/PC_Application/SpectrumAnalyzer/sadata.h @@ -0,0 +1,24 @@ +#ifndef SADATA_H +#define SADATA_H + +#include "Tools/parameters.h" + +#include + +class SAData { +public: + SAData() = default; + SAData(const Protocol::SpectrumAnalyzerResult &d) { + port1 = std::complex(d.real_port1, d.imag_port1); + port2 = std::complex(d.real_port2, d.imag_port2); + frequency = d.frequency; + time = (double) d.us / 1000000.0; + pointNum = d.pointNum; + } + double frequency; + double time; + std::complex port1, port2; + unsigned int pointNum; +}; + +#endif // SADATA_H diff --git a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp index 12d8d94..026f10b 100644 --- a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp +++ b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp @@ -17,6 +17,7 @@ #include "Device/firmwareupdatedialog.h" #include "preferences.h" #include "Generator/signalgenwidget.h" +#include "sadata.h" #include #include @@ -330,6 +331,7 @@ nlohmann::json SpectrumAnalyzer::toJSON() acq["detector"] = DetectorToString((Detector) settings.Detector).toStdString(); acq["signal ID"] = settings.SignalID ? true : false; sweep["acquisition"] = acq; + sweep["averages"] = averages; nlohmann::json tracking; tracking["enabled"] = settings.trackingGenerator ? true : false; tracking["port"] = settings.trackingGeneratorPort ? 2 : 1; @@ -425,6 +427,7 @@ void SpectrumAnalyzer::fromJSON(nlohmann::json j) EnableNormalization(false); } } + SetAveraging(sweep.value("averages", 0)); SetSingleSweep(sweep.value("single", singleSweep)); } } @@ -455,15 +458,17 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d) return; } - d = average.process(d); + auto sd = SAData(d); + + sd = average.process(sd); if(settings.f_start == settings.f_stop) { // keep track of first point time - if(d.pointNum == 0) { - firstPointTime = d.us; - d.us = 0; + if(sd.pointNum == 0) { + firstPointTime = sd.time; + sd.time = 0; } else { - d.us -= firstPointTime; + sd.time -= firstPointTime; } } @@ -472,8 +477,8 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d) // this is the last averaging sweep, use values for normalization if(normalize.port1Correction.size() > 0 || d.pointNum == 0) { // add measurement - normalize.port1Correction.push_back(d.port1); - normalize.port2Correction.push_back(d.port2); + normalize.port1Correction.push_back(abs(sd.port1)); + normalize.port2Correction.push_back(abs(sd.port2)); if(d.pointNum == settings.pointNum - 1) { // this was the last point normalize.measuring = false; @@ -490,14 +495,14 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d) } if(normalize.active) { - d.port1 /= normalize.port1Correction[d.pointNum]; - d.port2 /= normalize.port2Correction[d.pointNum]; + sd.port1 /= normalize.port1Correction[d.pointNum]; + sd.port2 /= normalize.port2Correction[d.pointNum]; double corr = pow(10.0, normalize.Level->value() / 20.0); - d.port1 *= corr; - d.port2 *= corr; + sd.port1 *= corr; + sd.port2 *= corr; } - traceModel.addSAData(d, settings); + traceModel.addSAData(sd, settings); emit dataChanged(); if(d.pointNum == settings.pointNum - 1) { UpdateAverageCount(); diff --git a/Software/PC_Application/Traces/traceaxis.cpp b/Software/PC_Application/Traces/traceaxis.cpp index 716b20f..19e1b37 100644 --- a/Software/PC_Application/Traces/traceaxis.cpp +++ b/Software/PC_Application/Traces/traceaxis.cpp @@ -354,6 +354,7 @@ std::set YAxis::getSupported(XAxis::Type type, TraceModel::DataSour case XAxis::Type::Frequency: ret.insert(YAxis::Type::Magnitude); ret.insert(YAxis::Type::MagnitudedBuV); + ret.insert(YAxis::Type::Phase); break; default: break; diff --git a/Software/PC_Application/Traces/tracemodel.cpp b/Software/PC_Application/Traces/tracemodel.cpp index e1a31cb..a186684 100644 --- a/Software/PC_Application/Traces/tracemodel.cpp +++ b/Software/PC_Application/Traces/tracemodel.cpp @@ -250,7 +250,7 @@ void TraceModel::addVNAData(const VNAData& d, TraceMath::DataType datatype) } } -void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings) +void TraceModel::addSAData(const SAData &d, const Protocol::SpectrumAnalyzerSettings& settings) { source = DataSource::SA; for(auto t : traces) { @@ -260,13 +260,13 @@ void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Prot if(settings.f_start == settings.f_stop) { // in zerospan mode, insert data by index index = d.pointNum; - td.x = (double) d.us / 1000000.0; + td.x = (double) d.time / 1000000.0; } else { td.x = d.frequency; } switch(t->liveParameter()) { - case Trace::LiveParameter::Port1: td.y = complex(d.port1, 0); break; - case Trace::LiveParameter::Port2: td.y = complex(d.port2, 0); break; + case Trace::LiveParameter::Port1: td.y = d.port1; break; + case Trace::LiveParameter::Port2: td.y = d.port2; break; default: // not a SA trace, skip continue; diff --git a/Software/PC_Application/Traces/tracemodel.h b/Software/PC_Application/Traces/tracemodel.h index 07ea83a..7d6103e 100644 --- a/Software/PC_Application/Traces/tracemodel.h +++ b/Software/PC_Application/Traces/tracemodel.h @@ -5,6 +5,7 @@ #include "savable.h" #include "trace.h" #include "VNA/vnadata.h" +#include "SpectrumAnalyzer/sadata.h" #include #include @@ -66,7 +67,7 @@ signals: public slots: void clearLiveData(); void addVNAData(const VNAData& d, TraceMath::DataType datatype); - void addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings); + void addSAData(const SAData& d, const Protocol::SpectrumAnalyzerSettings& settings); private: DataSource source; diff --git a/Software/PC_Application/VNA/vna.cpp b/Software/PC_Application/VNA/vna.cpp index aa65a67..d6e4ffe 100644 --- a/Software/PC_Application/VNA/vna.cpp +++ b/Software/PC_Application/VNA/vna.cpp @@ -737,6 +737,7 @@ nlohmann::json VNA::toJSON() sweep["power"] = power; sweep["points"] = settings.npoints; sweep["IFBW"] = settings.bandwidth; + sweep["averages"] = averages; j["sweep"] = sweep; j["traces"] = traceModel.toJSON(); @@ -793,6 +794,7 @@ void VNA::fromJSON(nlohmann::json j) type = SweepType::Frequency; } SetSweepType(type); + SetAveraging(sweep.value("averages", 0)); SetSingleSweep(sweep.value("single", singleSweep)); } } diff --git a/Software/PC_Application/averaging.cpp b/Software/PC_Application/averaging.cpp index 5705b46..213b6af 100644 --- a/Software/PC_Application/averaging.cpp +++ b/Software/PC_Application/averaging.cpp @@ -104,7 +104,7 @@ VNAData Averaging::process(VNAData d) return d; } -Protocol::SpectrumAnalyzerResult Averaging::process(Protocol::SpectrumAnalyzerResult d) +SAData Averaging::process(SAData d) { if (d.pointNum == avg.size()) { // add moving average entry @@ -123,16 +123,21 @@ Protocol::SpectrumAnalyzerResult Averaging::process(Protocol::SpectrumAnalyzerRe deque->pop_front(); } + if(averages == 1) { + // no need for any calculation, no averaging set + return d; + } + switch(mode) { case Mode::Mean: { // calculate average complex sum[2]; for(auto s : *deque) { - sum[0] += s[0]; - sum[1] += s[1]; + sum[0] += abs(s[0]); + sum[1] += abs(s[1]); } - d.port1 = abs(sum[0] / (double) (deque->size())); - d.port2 = abs(sum[1] / (double) (deque->size())); + d.port1 = sum[0] / (double) (deque->size()); + d.port2 = sum[1] / (double) (deque->size()); } break; case Mode::Median: { @@ -143,12 +148,12 @@ Protocol::SpectrumAnalyzerResult Averaging::process(Protocol::SpectrumAnalyzerRe port2.reserve(size); for(auto d : *deque) { port1.insert(upper_bound(port1.begin(), port1.end(), abs(d[0])), abs(d[0])); - port2.insert(upper_bound(port2.begin(), port2.end(), abs(d[0])), abs(d[0])); + port2.insert(upper_bound(port2.begin(), port2.end(), abs(d[1])), abs(d[1])); } if(size & 0x01) { // odd number of samples d.port1 = port1[size / 2]; - d.port2 = port1[size / 2]; + d.port2 = port2[size / 2]; } else { // even number, use average of middle samples d.port1 = (port1[size / 2 - 1] + port1[size / 2]) / 2; diff --git a/Software/PC_Application/averaging.h b/Software/PC_Application/averaging.h index ffea038..1da9f04 100644 --- a/Software/PC_Application/averaging.h +++ b/Software/PC_Application/averaging.h @@ -3,6 +3,7 @@ #include "Device/device.h" #include "VNA/vnadata.h" +#include "SpectrumAnalyzer/sadata.h" #include #include @@ -20,7 +21,7 @@ public: void reset(unsigned int points); void setAverages(unsigned int a); VNAData process(VNAData d); - Protocol::SpectrumAnalyzerResult process(Protocol::SpectrumAnalyzerResult d); + SAData process(SAData d); // Returns the number of averaged sweeps. Value is incremented whenever the last point of the sweep is added. // Returned values are in range 0 to averages unsigned int getLevel(); diff --git a/Software/VNA_embedded/Application/Communication/Protocol.hpp b/Software/VNA_embedded/Application/Communication/Protocol.hpp index 424a70c..fd44fa0 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.hpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.hpp @@ -4,7 +4,7 @@ namespace Protocol { -static constexpr uint16_t Version = 11; +static constexpr uint16_t Version = 12; #pragma pack(push, 1) @@ -150,8 +150,8 @@ using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings { }; using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult { - float port1; - float port2; + float real_port1, imag_port1; + float real_port2, imag_port2; union { struct { // for non-zero span diff --git a/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp index 5083b63..f41202c 100644 --- a/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp +++ b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp @@ -452,11 +452,9 @@ FPGA::DFTResult FPGA::ReadDFTResult() { int64_t p1real = assembleSampleResultValue(&recv[18]); // LOG_INFO("DFT raw: %ld, %ld, %ld, %ld", (int32_t) p1real, (int32_t) p1imag, (int32_t) p2real, (int32_t) p2imag); // Log_Flush(); - auto p1 = std::complex(p1real, p1imag); - auto p2 = std::complex(p2real, p2imag); DFTResult res; + res.P1 = std::complex(p1real, p1imag); + res.P2 = std::complex(p2real, p2imag); // LOG_INFO("DFT: %ld, %ld, %ld, %ld", (int32_t) p1.real(), (int32_t) p1.imag(), (int32_t) p2.real(), (int32_t) p2.imag()); - res.P1 = std::abs(p1); - res.P2 = std::abs(p2); return res; } diff --git a/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.hpp b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.hpp index 88da655..826ba31 100644 --- a/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.hpp +++ b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "Flash.hpp" #include "max2871.hpp" @@ -40,7 +41,7 @@ using SamplingResult = struct _samplingresult { }; using DFTResult = struct _dftresult { - float P1, P2; + std::complex P1, P2; }; using ADCLimits = struct _adclimits { diff --git a/Software/VNA_embedded/Application/Drivers/USB/usb.c b/Software/VNA_embedded/Application/Drivers/USB/usb.c index aab7c0a..165d677 100644 --- a/Software/VNA_embedded/Application/Drivers/USB/usb.c +++ b/Software/VNA_embedded/Application/Drivers/USB/usb.c @@ -19,7 +19,7 @@ static uint8_t *USBD_Class_GetDeviceQualifierDescriptor (uint16_t *length); static usbd_recv_callback_t cb; static uint8_t usb_receive_buffer[1024]; -static uint8_t usb_transmit_fifo[8192]; +static uint8_t usb_transmit_fifo[6144]; static uint16_t usb_transmit_read_index = 0; static uint16_t usb_transmit_fifo_level = 0; static bool data_transmission_active = false; diff --git a/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp b/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp index d125da0..44648f6 100644 --- a/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp +++ b/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp @@ -22,13 +22,17 @@ static uint32_t binSize; static uint8_t signalIDstep; static uint32_t sampleNum; static Protocol::PacketInfo p; + +// Result values +static std::complex res_port1, res_port2; + static bool active = false; static uint32_t lastLO2; static uint32_t actualRBW; static uint16_t DFTpoints; static bool negativeDFT; // if true, a positive frequency shift at input results in a negative shift at the 2.IF. Handle DFT accordingly -static float port1Measurement[FPGA::DFTbins], port2Measurement[FPGA::DFTbins]; +static std::complex port1Measurement[FPGA::DFTbins], port2Measurement[FPGA::DFTbins]; static uint8_t signalIDsteps; static std::array signalIDprescalers; @@ -274,15 +278,15 @@ bool SA::MeasurementDone(const FPGA::SamplingResult &result) { FPGA::AbortSweep(); for(uint16_t i=0;i port1, port2; if (s.UseDFT) { // use DFT result auto dft = FPGA::ReadDFTResult(); port1 = dft.P1; port2 = dft.P2; } else { - port1 = fabs(std::complex(result.P1I, result.P1Q)); - port2 = fabs(std::complex(result.P2I, result.P2Q)); + port1 = std::complex(result.P1I, result.P1Q); + port2 = std::complex(result.P2I, result.P2Q); } port1 /= sampleNum; port2 /= sampleNum; @@ -293,10 +297,11 @@ bool SA::MeasurementDone(const FPGA::SamplingResult &result) { index = DFTpoints - i - 1; } - if(port1 < port1Measurement[index]) { + // Signal ID: only keep the lowest measurement + if(abs(port1) < abs(port1Measurement[index])) { port1Measurement[index] = port1; } - if(port2 < port2Measurement[index]) { + if(abs(port2) < abs(port2Measurement[index])) { port2Measurement[index] = port2; } } @@ -332,46 +337,46 @@ void SA::Work() { switch(det) { case Detector::PosPeak: if(pointInBin == 0) { - p.spectrumResult.port1 = std::numeric_limits::min(); - p.spectrumResult.port2 = std::numeric_limits::min(); + res_port1 = std::numeric_limits>::min(); + res_port2 = std::numeric_limits>::min(); } - if(port1Measurement[i] > p.spectrumResult.port1) { - p.spectrumResult.port1 = port1Measurement[i]; + if(abs(port1Measurement[i]) > abs(res_port1)) { + res_port1 = port1Measurement[i]; } - if(port2Measurement[i] > p.spectrumResult.port2) { - p.spectrumResult.port2 = port2Measurement[i]; + if(abs(port2Measurement[i]) > abs(res_port2)) { + res_port2 = port2Measurement[i]; } break; case Detector::NegPeak: if(pointInBin == 0) { - p.spectrumResult.port1 = std::numeric_limits::max(); - p.spectrumResult.port2 = std::numeric_limits::max(); + res_port1 = std::complex(std::numeric_limits::max()); + res_port2 = std::complex(std::numeric_limits::max()); } - if(port1Measurement[i] < p.spectrumResult.port1) { - p.spectrumResult.port1 = port1Measurement[i]; + if(abs(port1Measurement[i]) < abs(res_port1)) { + res_port1 = port1Measurement[i]; } - if(port2Measurement[i] < p.spectrumResult.port2) { - p.spectrumResult.port2 = port2Measurement[i]; + if(abs(port2Measurement[i]) < abs(res_port2)) { + res_port2 = port2Measurement[i]; } break; case Detector::Sample: if(pointInBin <= binSize / 2) { // still in first half of bin, simply overwrite - p.spectrumResult.port1 = port1Measurement[i]; - p.spectrumResult.port2 = port2Measurement[i]; + res_port1 = port1Measurement[i]; + res_port2 = port2Measurement[i]; } break; case Detector::Average: if(pointInBin == 0) { - p.spectrumResult.port1 = 0; - p.spectrumResult.port2 = 0; + res_port1 = 0; + res_port2 = 0; } - p.spectrumResult.port1 += port1Measurement[i]; - p.spectrumResult.port2 += port2Measurement[i]; + res_port1 += port1Measurement[i]; + res_port2 += port2Measurement[i]; if(lastPointInBin) { // calculate average - p.spectrumResult.port1 /= binSize; - p.spectrumResult.port2 /= binSize; + res_port1 /= binSize; + res_port2 /= binSize; } break; case Detector::Normal: @@ -396,13 +401,17 @@ void SA::Work() { p.spectrumResult.frequency = s.f_start + (s.f_stop - s.f_start) * binIndex / (s.pointNum - 1); } // scale approximately (constant determined empirically) - p.spectrumResult.port1 /= 253000000.0; - p.spectrumResult.port2 /= 253000000.0; + res_port1 /= 253000000.0; + res_port2 /= 253000000.0; if (s.applyReceiverCorrection) { auto correction = Cal::ReceiverCorrection(p.spectrumResult.frequency); - p.spectrumResult.port1 *= powf(10.0f, (float) correction.port1 / 100.0f / 20.0f); - p.spectrumResult.port2 *= powf(10.0f, (float) correction.port2 / 100.0f / 20.0f); + res_port1 *= powf(10.0f, (float) correction.port1 / 100.0f / 20.0f); + res_port2 *= powf(10.0f, (float) correction.port2 / 100.0f / 20.0f); } + p.spectrumResult.real_port1 = real(res_port1); + p.spectrumResult.imag_port1 = imag(res_port1); + p.spectrumResult.real_port2 = real(res_port2); + p.spectrumResult.imag_port2 = imag(res_port2); p.spectrumResult.pointNum = binIndex; Communication::Send(p); }