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.syncMode = (int) sync;
|
||||||
p.spectrumSettings.syncMaster = syncMaster ? 1 : 0;
|
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){
|
return SendPacket(p, [=](TransmissionResult r){
|
||||||
if(cb) {
|
if(cb) {
|
||||||
cb(r == TransmissionResult::Ack);
|
cb(r == TransmissionResult::Ack);
|
||||||
|
|
|
||||||
|
|
@ -219,17 +219,6 @@ bool Si5351C::WritePLLConfig(PLLConfig config, PLL pll) {
|
||||||
} else {
|
} else {
|
||||||
success &=SetBits(Reg::PLLInputSource, mask);
|
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;
|
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 firstPoint; // indicates the first point to be transmitted to the GUI, sets the firstPointTime
|
||||||
static bool zerospan;
|
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() {
|
static void StartNextSample() {
|
||||||
uint64_t freq = s.f_start + (s.f_stop - s.f_start) * pointCnt / (points - 1);
|
uint64_t freq = s.f_start + (s.f_stop - s.f_start) * pointCnt / (points - 1);
|
||||||
freq = Cal::FrequencyCorrectionToDevice(freq);
|
freq = Cal::FrequencyCorrectionToDevice(freq);
|
||||||
|
|
@ -65,12 +76,15 @@ static void StartNextSample() {
|
||||||
negativeDFT = true;
|
negativeDFT = true;
|
||||||
|
|
||||||
// set tracking generator to default values
|
// set tracking generator to default values
|
||||||
trackingFreq = 0;
|
|
||||||
trackingLowband = false;
|
trackingLowband = false;
|
||||||
attenuator = 0;
|
attenuator = 0;
|
||||||
// this is the first step in each point, update tracking generator if enabled
|
// this is the first step in each point, update tracking generator if enabled
|
||||||
if (s.trackingGenerator) {
|
if (s.trackingGenerator) {
|
||||||
|
auto oldTrackingFreq = trackingFreq;
|
||||||
trackingFreq = freq + s.trackingGeneratorOffset;
|
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) {
|
if(trackingFreq > 0 && trackingFreq <= (int64_t) HW::Info.limits_maxFreq) {
|
||||||
// tracking frequency is valid, calculate required settings and select band
|
// tracking frequency is valid, calculate required settings and select band
|
||||||
auto amplitude = HW::GetAmplitudeSettings(s.trackingPower, trackingFreq, s.applySourceCorrection, s.trackingGeneratorPort);
|
auto amplitude = HW::GetAmplitudeSettings(s.trackingPower, trackingFreq, s.applySourceCorrection, s.trackingGeneratorPort);
|
||||||
|
|
@ -85,6 +99,30 @@ static void StartNextSample() {
|
||||||
FPGA::Disable(FPGA::Periphery::SourceRF);
|
FPGA::Disable(FPGA::Periphery::SourceRF);
|
||||||
trackingLowband = true;
|
trackingLowband = true;
|
||||||
} else {
|
} 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.SetFrequency(trackingFreq);
|
||||||
Source.SetPowerOutA(amplitude.highBandPower, true);
|
Source.SetPowerOutA(amplitude.highBandPower, true);
|
||||||
FPGA::Enable(FPGA::Periphery::SourceChip);
|
FPGA::Enable(FPGA::Periphery::SourceChip);
|
||||||
|
|
@ -95,6 +133,7 @@ static void StartNextSample() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
LO2freq = HW::getIF1() - HW::getIF2();
|
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)
|
// 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) {
|
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;
|
lastLO2 = LO2freq;
|
||||||
}
|
}
|
||||||
if (s.UseDFT) {
|
if (s.UseDFT) {
|
||||||
|
|
@ -228,6 +269,10 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
|
||||||
// set initial state
|
// set initial state
|
||||||
pointCnt = 0;
|
pointCnt = 0;
|
||||||
signalIDstep = 0;
|
signalIDstep = 0;
|
||||||
|
trackingFreq = 0;
|
||||||
|
PLLRefIndex = 0;
|
||||||
|
setPLLReference();
|
||||||
|
|
||||||
// enable the required hardware resources
|
// enable the required hardware resources
|
||||||
Si5351.Enable(SiChannel::Port1LO2);
|
Si5351.Enable(SiChannel::Port1LO2);
|
||||||
Si5351.Enable(SiChannel::Port2LO2);
|
Si5351.Enable(SiChannel::Port2LO2);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue