Improve spectrum analyzer

- revert LO2 shift mechanism (restores previous SA speed)
- allow tracking generator to reach all(?) frequencies with sufficient accuracy
This commit is contained in:
Jan Käberich 2025-01-04 16:50:20 +01:00
parent 8df7d1b7be
commit b77ba278de
3 changed files with 68 additions and 60 deletions

View file

@ -501,32 +501,6 @@ bool LibreVNADriver::setSA(const DeviceDriver::SASettings &s, std::function<void
p.spectrumSettings.syncMode = (int) sync;
p.spectrumSettings.syncMaster = syncMaster ? 1 : 0;
if(p.spectrumSettings.trackingGenerator && p.spectrumSettings.f_stop >= 25000000) {
// Check point spacing.
// The highband PLL used as the tracking generator is not able to reach every frequency exactly. This
// could lead to sharp drops in the spectrum at certain frequencies. If the span is wide enough with
// respect to the point number, it is ensured that every displayed point has at least one sample with
// a reachable PLL frequency in it. Display a warning message if this is not the case with the current
// settings.
auto pointSpacing = (p.spectrumSettings.f_stop - p.spectrumSettings.f_start) / (p.spectrumSettings.pointNum - 1);
// The frequency resolution of the PLL is frequency dependent (due to PLL divider).
// This code assumes some knowledge of the actual hardware and probably should be moved
// onto the device at some point
double minSpacing = 25000;
auto stop = p.spectrumSettings.f_stop;
while(stop <= 3000000000) {
minSpacing /= 2;
stop *= 2;
}
if(pointSpacing < minSpacing) {
auto requiredMinSpan = minSpacing * (p.spectrumSettings.pointNum - 1);
auto message = QString() + "Due to PLL limitations, the tracking generator can not reach every frequency exactly. "
"With your current span, this could result in the signal not being detected at some bands. A minimum"
" span of " + Unit::ToString(requiredMinSpan, "Hz", " kMG") + " is recommended at this stop frequency.";
InformationBox::ShowMessage("Warning", message, "TrackingGeneratorSpanTooSmallWarning");
}
}
return SendPacket(p, [=](TransmissionResult r){
if(cb) {
cb(r == TransmissionResult::Ack);

View file

@ -219,17 +219,6 @@ bool Si5351C::WritePLLConfig(PLLConfig config, PLL pll) {
} else {
success &=SetBits(Reg::PLLInputSource, mask);
}
// Reset the PLL
mask = pll == PLL::A ? 0x20 : 0x80;
//success &=SetBits(Reg::PLLReset, mask);
reg = pll == PLL::A ? Reg::MSNA_CONFIG : Reg::MSNB_CONFIG;
for(uint8_t i=0;i<8;i++) {
uint8_t readback;
ReadRegister((Reg)((int)reg + i), &readback);
LOG_DEBUG("PLL readback %d: 0x%02x", i, readback);
}
return success;
}

View file

@ -44,6 +44,17 @@ static uint64_t firstPointTime;
static bool firstPoint; // indicates the first point to be transmitted to the GUI, sets the firstPointTime
static bool zerospan;
static uint32_t PLLRefFreqs[] = {HW::PLLRef, HW::PLLRef - 1000000};
static constexpr uint8_t PLLRefFreqsNum = sizeof(PLLRefFreqs)/sizeof(PLLRefFreqs[0]);
static uint8_t PLLRefIndex;
static void setPLLReference() {
Si5351.SetCLK(SiChannel::Source, PLLRefFreqs[PLLRefIndex], Si5351C::PLL::A, Si5351C::DriveStrength::mA8);
Si5351.SetCLK(SiChannel::LO1, PLLRefFreqs[PLLRefIndex], Si5351C::PLL::A, Si5351C::DriveStrength::mA8);
Source.SetReference(PLLRefFreqs[PLLRefIndex], false, 1, false);
LO1.SetReference(PLLRefFreqs[PLLRefIndex], false, 1, false);
}
static void StartNextSample() {
uint64_t freq = s.f_start + (s.f_stop - s.f_start) * pointCnt / (points - 1);
freq = Cal::FrequencyCorrectionToDevice(freq);
@ -65,12 +76,15 @@ static void StartNextSample() {
negativeDFT = true;
// set tracking generator to default values
trackingFreq = 0;
trackingLowband = false;
attenuator = 0;
// this is the first step in each point, update tracking generator if enabled
if (s.trackingGenerator) {
auto oldTrackingFreq = trackingFreq;
trackingFreq = freq + s.trackingGeneratorOffset;
if(trackingFreq != oldTrackingFreq) {
// need to change the source frequency
oldTrackingFreq = trackingFreq;
if(trackingFreq > 0 && trackingFreq <= (int64_t) HW::Info.limits_maxFreq) {
// tracking frequency is valid, calculate required settings and select band
auto amplitude = HW::GetAmplitudeSettings(s.trackingPower, trackingFreq, s.applySourceCorrection, s.trackingGeneratorPort);
@ -85,6 +99,30 @@ static void StartNextSample() {
FPGA::Disable(FPGA::Periphery::SourceRF);
trackingLowband = true;
} else {
// Source PLL can not hit all frequencies with high enough accuracy with a single reference frequency.
// Check available reference frequencies for best match
uint8_t bestIndex = 0;
uint32_t smallestDeviation = UINT32_MAX;
for(uint8_t i=0;i<PLLRefFreqsNum;i++) {
Source.SetReference(PLLRefFreqs[i], false, 1, false);
Source.SetFrequency(trackingFreq);
auto actualSource = Source.GetActualFrequency();
uint32_t deviation = (uint32_t) abs(actualSource - trackingFreq);
if(deviation < smallestDeviation) {
smallestDeviation = deviation;
bestIndex = i;
if(deviation < actualRBW / 20) {
// good enough, no need to check any further
break;
}
}
}
if(bestIndex != PLLRefIndex) {
LOG_INFO("Switching ref index (current %d, requested f=%lu%06lu)", PLLRefIndex
,(uint32_t) (trackingFreq / 1000000), (uint32_t)(trackingFreq%1000000));
PLLRefIndex = bestIndex;
setPLLReference();
}
Source.SetFrequency(trackingFreq);
Source.SetPowerOutA(amplitude.highBandPower, true);
FPGA::Enable(FPGA::Periphery::SourceChip);
@ -95,6 +133,7 @@ static void StartNextSample() {
}
}
}
}
break;
case 1:
LO2freq = HW::getIF1() - HW::getIF2();
@ -158,7 +197,9 @@ static void StartNextSample() {
// 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) > actualRBW / 100) {
Si5351.SetPLL(Si5351C::PLL::B, LO2freq*HW::LO2Multiplier, HW::Ref::getSource());
// Si5351.SetPLL(Si5351C::PLL::B, LO2freq*HW::LO2Multiplier, HW::Ref::getSource());
Si5351.SetCLK(SiChannel::Port1LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
Si5351.SetCLK(SiChannel::Port2LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
lastLO2 = LO2freq;
}
if (s.UseDFT) {
@ -228,6 +269,10 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
// set initial state
pointCnt = 0;
signalIDstep = 0;
trackingFreq = 0;
PLLRefIndex = 0;
setPLLReference();
// enable the required hardware resources
Si5351.Enable(SiChannel::Port1LO2);
Si5351.Enable(SiChannel::Port2LO2);