mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-04-04 22:17:31 +00:00
Improved spectrum analyzer mode
- Faster sweeps by changing 2.LO only when necessary and using 400kHz I2C frequency - Added FPGA settings for selectable ADC samplerate - Additional measurement with different ADC samplerate when signal ID is on to remove ADC images
This commit is contained in:
parent
38e73365df
commit
fc3ce7a828
22 changed files with 118 additions and 86 deletions
Binary file not shown.
|
|
@ -189,8 +189,8 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window)
|
|||
// if(pref.Startup.RememberSweepSettings) {
|
||||
// LoadSweepSettings();
|
||||
// } else {
|
||||
settings.f_start = pref.Startup.DefaultSweep.start;
|
||||
settings.f_stop = pref.Startup.DefaultSweep.stop;
|
||||
settings.f_start = 950000000;
|
||||
settings.f_stop = 1050000000;
|
||||
ConstrainAndUpdateFrequencies();
|
||||
SetRBW(10000);
|
||||
settings.WindowType = 1;
|
||||
|
|
@ -235,7 +235,7 @@ void SpectrumAnalyzer::SettingsChanged()
|
|||
}
|
||||
average.reset();
|
||||
traceModel.clearVNAData();
|
||||
TracePlot::UpdateSpan(settings.f_start, settings.f_stop);
|
||||
emit traceModel.SpanChanged(settings.f_start, settings.f_stop);
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::StartImpedanceMatching()
|
||||
|
|
|
|||
|
|
@ -146,6 +146,8 @@ TraceBodePlot::TraceBodePlot(TraceModel &model, QWidget *parent)
|
|||
// enable autoscaling and set for full span (no information about actual span available yet)
|
||||
setXAxis(0, 6000000000);
|
||||
setXAxis(true, 0, 6000000000, 600000000);
|
||||
// get notified when the span changes
|
||||
connect(&model, &TraceModel::SpanChanged, this, qOverload<double, double>(&TraceBodePlot::setXAxis));
|
||||
}
|
||||
|
||||
TraceBodePlot::~TraceBodePlot()
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ public:
|
|||
std::vector<Trace*> getTraces();
|
||||
|
||||
bool PortExcitationRequired(int port);
|
||||
|
||||
signals:
|
||||
void SpanChanged(double fmin, double fmax);
|
||||
void traceAdded(Trace *t);
|
||||
void traceRemoved(Trace *t);
|
||||
void requiredExcitation(bool excitePort1, bool excitePort2);
|
||||
|
|
|
|||
|
|
@ -48,13 +48,6 @@ void TracePlot::mouseDoubleClickEvent(QMouseEvent *) {
|
|||
emit doubleClicked(this);
|
||||
}
|
||||
|
||||
void TracePlot::UpdateSpan(double fmin, double fmax)
|
||||
{
|
||||
for(auto p : plots) {
|
||||
p->setXAxis(fmin, fmax);
|
||||
}
|
||||
}
|
||||
|
||||
void TracePlot::initializeTraceInfo(TraceModel &model)
|
||||
{
|
||||
// Populate already present traces
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ public:
|
|||
virtual void setXAxis(double min, double max){Q_UNUSED(min);Q_UNUSED(max)};
|
||||
|
||||
static std::set<TracePlot *> getPlots();
|
||||
static void UpdateSpan(double fmin, double fmax);
|
||||
|
||||
signals:
|
||||
void doubleClicked(QWidget *w);
|
||||
|
|
|
|||
|
|
@ -544,7 +544,7 @@ void VNA::SettingsChanged()
|
|||
average.reset();
|
||||
traceModel.clearVNAData();
|
||||
UpdateStatusPanel();
|
||||
TracePlot::UpdateSpan(settings.f_start, settings.f_stop);
|
||||
emit traceModel.SpanChanged(settings.f_start, settings.f_stop);
|
||||
}
|
||||
|
||||
void VNA::StartImpedanceMatching()
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ static void SwitchBytes(int16_t &value) {
|
|||
value = (value & 0xFF00) >> 8 | (value & 0x00FF) << 8;
|
||||
}
|
||||
|
||||
void WriteRegister(FPGA::Reg reg, uint16_t value) {
|
||||
void FPGA::WriteRegister(FPGA::Reg reg, uint16_t value) {
|
||||
uint8_t cmd[4] = {0x80, (uint8_t) reg, (uint8_t) (value >> 8), (uint8_t) (value & 0xFF)};
|
||||
Low(CS);
|
||||
HAL_SPI_Transmit(&FPGA_SPI, (uint8_t*) cmd, 4, 100);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ enum class Reg {
|
|||
SweepPoints = 0x01,
|
||||
SamplesPerPoint = 0x02,
|
||||
SystemControl = 0x03,
|
||||
SettlingTime = 0x04,
|
||||
ADCPrescaler = 0x04,
|
||||
PhaseIncrement = 0x05,
|
||||
MAX2871Def0LSB = 0x08,
|
||||
MAX2871Def0MSB = 0x09,
|
||||
MAX2871Def1LSB = 0x0A,
|
||||
|
|
@ -49,6 +50,7 @@ enum class Periphery {
|
|||
LO1Chip = 0x0008,
|
||||
ExcitePort2 = 0x0004,
|
||||
ExcitePort1 = 0x0002,
|
||||
PortSwitch = 0x0001,
|
||||
};
|
||||
|
||||
enum class Interrupt {
|
||||
|
|
@ -96,6 +98,7 @@ bool Configure(Flash *f, uint32_t start_address, uint32_t bitstream_size);
|
|||
|
||||
using HaltedCallback = void(*)(void);
|
||||
bool Init(HaltedCallback cb = nullptr);
|
||||
void WriteRegister(FPGA::Reg reg, uint16_t value);
|
||||
void SetNumberOfPoints(uint16_t npoints);
|
||||
void SetSamplesPerPoint(uint32_t nsamples);
|
||||
void Enable(Periphery p, bool enable = true);
|
||||
|
|
|
|||
|
|
@ -119,6 +119,10 @@ bool HW::Init(WorkRequest wr) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Set default ADC samplerate
|
||||
FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, 112);
|
||||
FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, 1120);
|
||||
|
||||
// Enable new data and sweep halt interrupt
|
||||
FPGA::EnableInterrupt(FPGA::Interrupt::NewData);
|
||||
FPGA::EnableInterrupt(FPGA::Interrupt::SweepHalted);
|
||||
|
|
@ -211,6 +215,7 @@ void HW::SetIdle() {
|
|||
FPGA::Enable(FPGA::Periphery::Port1Mixer, false);
|
||||
FPGA::Enable(FPGA::Periphery::Port2Mixer, false);
|
||||
FPGA::Enable(FPGA::Periphery::RefMixer, false);
|
||||
FPGA::Enable(FPGA::Periphery::PortSwitch, false);
|
||||
}
|
||||
|
||||
void HW::fillDeviceInfo(Protocol::DeviceInfo *info) {
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ void Manual::Setup(Protocol::ManualControl m) {
|
|||
FPGA::Enable(FPGA::Periphery::RefMixer, m.RefEN);
|
||||
FPGA::Enable(FPGA::Periphery::ExcitePort1, m.PortSwitch == 0);
|
||||
FPGA::Enable(FPGA::Periphery::ExcitePort2, m.PortSwitch == 1);
|
||||
FPGA::Enable(FPGA::Periphery::PortSwitch);
|
||||
|
||||
active = true;
|
||||
FPGA::StartSweep();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ static uint8_t signalIDstep;
|
|||
static uint32_t sampleNum;
|
||||
static Protocol::PacketInfo p;
|
||||
static bool active = false;
|
||||
static uint32_t lastLO2;
|
||||
|
||||
static float port1Measurement, port2Measurement;
|
||||
|
||||
|
|
@ -32,30 +33,44 @@ static void StartNextSample() {
|
|||
// reset minimum amplitudes in first signal ID step
|
||||
port1Measurement = std::numeric_limits<float>::max();
|
||||
port2Measurement = std::numeric_limits<float>::max();
|
||||
// Use default LO frequencies
|
||||
LO1freq = freq + HW::IF1;
|
||||
LO2freq = HW::IF1 - HW::IF2;
|
||||
FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, 112);
|
||||
FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, 1120);
|
||||
break;
|
||||
case 1:
|
||||
// Shift first LO to other side
|
||||
LO1freq = freq - HW::IF1;
|
||||
LO2freq = HW::IF1 - HW::IF2;
|
||||
break;
|
||||
case 2:
|
||||
// Shift both LOs to other side
|
||||
LO1freq = freq + HW::IF1;
|
||||
LO2freq = HW::IF1 + HW::IF2;
|
||||
break;
|
||||
case 3:
|
||||
// Shift second LO to other side
|
||||
LO1freq = freq - HW::IF1;
|
||||
LO2freq = HW::IF1 + HW::IF2;
|
||||
break;
|
||||
case 4:
|
||||
// Use default frequencies with different ADC samplerate to remove images in final IF
|
||||
LO1freq = freq + HW::IF1;
|
||||
LO2freq = HW::IF1 - HW::IF2;
|
||||
FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, 120);
|
||||
FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, 1200);
|
||||
}
|
||||
LO1.SetFrequency(LO1freq);
|
||||
// LO1 is not able to reach all frequencies with the required precision, adjust LO2 to account for deviation
|
||||
int32_t LO1deviation = (int64_t) LO1.GetActualFrequency() - LO1freq;
|
||||
LO2freq += LO1deviation;
|
||||
// Adjust LO2 PLL
|
||||
// Generate second LO with Si5351
|
||||
Si5351.SetCLK(SiChannel::Port1LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
|
||||
Si5351.SetCLK(SiChannel::Port2LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
|
||||
// only adjust LO2 PLL if necessary (if the deviation is significantly less than the RBW it does not matter)
|
||||
if((uint32_t) abs(LO2freq - lastLO2) > s.RBW / 2) {
|
||||
Si5351.SetCLK(SiChannel::Port1LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
|
||||
Si5351.SetCLK(SiChannel::Port2LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
|
||||
lastLO2 = LO2freq;
|
||||
}
|
||||
// Configure the sampling in the FPGA
|
||||
FPGA::WriteSweepConfig(0, 0, Source.GetRegisters(), LO1.GetRegisters(), 0,
|
||||
0, FPGA::SettlingTime::us20, FPGA::Samples::SPPRegister, 0,
|
||||
|
|
@ -74,7 +89,7 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
|
|||
// individually start each point and do the sweep in the uC
|
||||
FPGA::SetNumberOfPoints(1);
|
||||
// calculate amount of required points
|
||||
points = (s.f_stop - s.f_start) / s.RBW;
|
||||
points = 2 * (s.f_stop - s.f_start) / s.RBW;
|
||||
// adjust to integer multiple of requested result points (in order to have the same amount of measurements in each bin)
|
||||
points += s.pointNum - points % s.pointNum;
|
||||
binSize = points / s.pointNum;
|
||||
|
|
@ -97,6 +112,7 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
|
|||
FPGA::Enable(FPGA::Periphery::ExcitePort1);
|
||||
FPGA::Enable(FPGA::Periphery::Port1Mixer);
|
||||
FPGA::Enable(FPGA::Periphery::Port2Mixer);
|
||||
lastLO2 = 0;
|
||||
active = true;
|
||||
StartNextSample();
|
||||
}
|
||||
|
|
@ -121,7 +137,7 @@ void SA::Work() {
|
|||
if(!active) {
|
||||
return;
|
||||
}
|
||||
if(!s.SignalID || signalIDstep >= 3) {
|
||||
if(!s.SignalID || signalIDstep >= 4) {
|
||||
// this measurement point is done, handle result according to detector
|
||||
uint16_t binIndex = pointCnt / binSize;
|
||||
uint32_t pointInBin = pointCnt % binSize;
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ bool VNA::Setup(Protocol::SweepSettings s, SweepCallback cb) {
|
|||
FPGA::Enable(FPGA::Periphery::LO1RF);
|
||||
FPGA::Enable(FPGA::Periphery::ExcitePort1, s.excitePort1);
|
||||
FPGA::Enable(FPGA::Periphery::ExcitePort2, s.excitePort2);
|
||||
FPGA::Enable(FPGA::Periphery::PortSwitch);
|
||||
pointCnt = 0;
|
||||
// starting port depends on whether port 1 is active in sweep
|
||||
excitingPort1 = s.excitePort1;
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ static void MX_I2C2_Init(void)
|
|||
|
||||
/* USER CODE END I2C2_Init 1 */
|
||||
hi2c2.Instance = I2C2;
|
||||
hi2c2.Init.Timing = 0x20B0D9FF;
|
||||
hi2c2.Init.Timing = 0x00E057FD;
|
||||
hi2c2.Init.OwnAddress1 = 0;
|
||||
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
|
||||
hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
|
||||
|
|
|
|||
|
|
@ -85,8 +85,9 @@ FREERTOS.configENABLE_BACKWARD_COMPATIBILITY=1
|
|||
FREERTOS.configTOTAL_HEAP_SIZE=2048
|
||||
FREERTOS.configUSE_MUTEXES=1
|
||||
File.Version=6
|
||||
I2C2.IPParameters=Timing
|
||||
I2C2.Timing=0x20B0D9FF
|
||||
I2C2.I2C_Speed_Mode=I2C_Fast
|
||||
I2C2.IPParameters=Timing,I2C_Speed_Mode
|
||||
I2C2.Timing=0x00E057FD
|
||||
KeepUserPlacement=false
|
||||
Mcu.Family=STM32G4
|
||||
Mcu.IP0=DMA
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue