mirror of
https://github.com/jankae/LibreVNA.git
synced 2025-12-06 07:12:10 +01:00
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:
parent
8df7d1b7be
commit
b77ba278de
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue