TCXO offset calibration
This commit is contained in:
parent
4f4b2db549
commit
938f444c73
39
Software/PC_Application/Calibration/frequencycaldialog.cpp
Normal file
39
Software/PC_Application/Calibration/frequencycaldialog.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "frequencycaldialog.h"
|
||||
#include "ui_frequencycaldialog.h"
|
||||
|
||||
FrequencyCalDialog::FrequencyCalDialog(Device *dev, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::FrequencyCalDialog),
|
||||
dev(dev)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->ppm->setUnit("ppm");
|
||||
ui->ppm->setPrefixes(" ");
|
||||
ui->ppm->setPrecision(4);
|
||||
ui->ppm->setValue(0.0);
|
||||
|
||||
connect(dev, &Device::FrequencyCorrectionReceived, ui->ppm, &SIUnitEdit::setValueQuiet);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [=](){
|
||||
// get value and transfer to device
|
||||
Protocol::PacketInfo p;
|
||||
p.type = Protocol::PacketType::FrequencyCorrection;
|
||||
p.frequencyCorrection.ppm = ui->ppm->value();
|
||||
dev->SendPacket(p);
|
||||
// force restart of current mode for setting to take effect
|
||||
auto activeMode = Mode::getActiveMode();
|
||||
activeMode->deactivate();
|
||||
activeMode->activate();
|
||||
accept();
|
||||
delete this;
|
||||
});
|
||||
|
||||
// request setting from device
|
||||
dev->SendCommandWithoutPayload(Protocol::PacketType::RequestFrequencyCorrection);
|
||||
}
|
||||
|
||||
|
||||
FrequencyCalDialog::~FrequencyCalDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
25
Software/PC_Application/Calibration/frequencycaldialog.h
Normal file
25
Software/PC_Application/Calibration/frequencycaldialog.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef FREQUENCYCALDIALOG_H
|
||||
#define FREQUENCYCALDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "Device/device.h"
|
||||
#include "mode.h"
|
||||
|
||||
namespace Ui {
|
||||
class FrequencyCalDialog;
|
||||
}
|
||||
|
||||
class FrequencyCalDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FrequencyCalDialog(Device *dev, QWidget *parent = nullptr);
|
||||
~FrequencyCalDialog();
|
||||
|
||||
private:
|
||||
Ui::FrequencyCalDialog *ui;
|
||||
Device *dev;
|
||||
};
|
||||
|
||||
#endif // FREQUENCYCALDIALOG_H
|
124
Software/PC_Application/Calibration/frequencycaldialog.ui
Normal file
124
Software/PC_Application/Calibration/frequencycaldialog.ui
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FrequencyCalDialog</class>
|
||||
<widget class="QDialog" name="FrequencyCalDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>363</width>
|
||||
<height>178</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Frequency Calibration</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Specify the error of the internal TCXO to correct for it during measurements and signal generation. This setting has no effect when an external reference is used.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>TCXO offset:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SIUnitEdit" name="ppm"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>SIUnitEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>CustomWidgets/siunitedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>FrequencyCalDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>FrequencyCalDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -459,6 +459,9 @@ void Device::ReceivedData()
|
||||
emit NackReceived();
|
||||
emit receivedAnswer(TransmissionResult::Nack);
|
||||
break;
|
||||
case Protocol::PacketType::FrequencyCorrection:
|
||||
emit FrequencyCorrectionReceived(packet.frequencyCorrection.ppm);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ signals:
|
||||
void ManualStatusReceived(Protocol::ManualStatus);
|
||||
void SpectrumResultReceived(Protocol::SpectrumAnalyzerResult);
|
||||
void AmplitudeCorrectionPointReceived(Protocol::AmplitudeCorrectionPoint);
|
||||
void FrequencyCorrectionReceived(float ppm);
|
||||
void DeviceInfoUpdated();
|
||||
void ConnectionLost();
|
||||
void AckReceived();
|
||||
|
@ -5,6 +5,7 @@ HEADERS += \
|
||||
Calibration/calibrationtracedialog.h \
|
||||
Calibration/calkit.h \
|
||||
Calibration/calkitdialog.h \
|
||||
Calibration/frequencycaldialog.h \
|
||||
Calibration/manualcalibrationdialog.h \
|
||||
Calibration/measurementmodel.h \
|
||||
Calibration/receivercaldialog.h \
|
||||
@ -128,6 +129,7 @@ SOURCES += \
|
||||
Calibration/calibrationtracedialog.cpp \
|
||||
Calibration/calkit.cpp \
|
||||
Calibration/calkitdialog.cpp \
|
||||
Calibration/frequencycaldialog.cpp \
|
||||
Calibration/manualcalibrationdialog.cpp \
|
||||
Calibration/measurementmodel.cpp \
|
||||
Calibration/receivercaldialog.cpp \
|
||||
@ -244,6 +246,7 @@ FORMS += \
|
||||
Calibration/automaticamplitudedialog.ui \
|
||||
Calibration/calibrationtracedialog.ui \
|
||||
Calibration/calkitdialog.ui \
|
||||
Calibration/frequencycaldialog.ui \
|
||||
Calibration/manualcalibrationdialog.ui \
|
||||
CustomWidgets/jsonpickerdialog.ui \
|
||||
CustomWidgets/tilewidget.ui \
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "SpectrumAnalyzer/spectrumanalyzer.h"
|
||||
#include "Calibration/sourcecaldialog.h"
|
||||
#include "Calibration/receivercaldialog.h"
|
||||
#include "Calibration/frequencycaldialog.h"
|
||||
#include <QDebug>
|
||||
#include "CustomWidgets/jsonpickerdialog.h"
|
||||
#include <QCommandLineParser>
|
||||
@ -185,6 +186,7 @@ AppWindow::AppWindow(QWidget *parent)
|
||||
connect(ui->actionFirmware_Update, &QAction::triggered, this, &AppWindow::StartFirmwareUpdateDialog);
|
||||
connect(ui->actionSource_Calibration, &QAction::triggered, this, &AppWindow::SourceCalibrationDialog);
|
||||
connect(ui->actionReceiver_Calibration, &QAction::triggered, this, &AppWindow::ReceiverCalibrationDialog);
|
||||
connect(ui->actionFrequency_Calibration, &QAction::triggered, this, &AppWindow::FrequencyCalibrationDialog);
|
||||
connect(ui->actionPreferences, &QAction::triggered, [=](){
|
||||
// save previous SCPI settings in case they change
|
||||
auto &p = Preferences::getInstance();
|
||||
@ -291,6 +293,7 @@ bool AppWindow::ConnectToDevice(QString serial)
|
||||
ui->actionFirmware_Update->setEnabled(true);
|
||||
ui->actionSource_Calibration->setEnabled(true);
|
||||
ui->actionReceiver_Calibration->setEnabled(true);
|
||||
ui->actionFrequency_Calibration->setEnabled(true);
|
||||
|
||||
Mode::getActiveMode()->initializeDevice();
|
||||
UpdateReference();
|
||||
@ -321,6 +324,7 @@ void AppWindow::DisconnectDevice()
|
||||
ui->actionFirmware_Update->setEnabled(false);
|
||||
ui->actionSource_Calibration->setEnabled(false);
|
||||
ui->actionReceiver_Calibration->setEnabled(false);
|
||||
ui->actionFrequency_Calibration->setEnabled(false);
|
||||
for(auto a : deviceActionGroup->actions()) {
|
||||
a->setChecked(false);
|
||||
}
|
||||
@ -654,6 +658,12 @@ void AppWindow::ReceiverCalibrationDialog()
|
||||
d->exec();
|
||||
}
|
||||
|
||||
void AppWindow::FrequencyCalibrationDialog()
|
||||
{
|
||||
auto d = new FrequencyCalDialog(device);
|
||||
d->exec();
|
||||
}
|
||||
|
||||
nlohmann::json AppWindow::SaveSetup()
|
||||
{
|
||||
nlohmann::json j;
|
||||
|
@ -53,6 +53,7 @@ private slots:
|
||||
void DeviceNeedsUpdate(int reported, int expected);
|
||||
void SourceCalibrationDialog();
|
||||
void ReceiverCalibrationDialog();
|
||||
void FrequencyCalibrationDialog();
|
||||
nlohmann::json SaveSetup();
|
||||
void LoadSetup(nlohmann::json j);
|
||||
private:
|
||||
|
@ -54,6 +54,7 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSource_Calibration"/>
|
||||
<addaction name="actionReceiver_Calibration"/>
|
||||
<addaction name="actionFrequency_Calibration"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuWindow">
|
||||
<property name="title">
|
||||
@ -193,12 +194,21 @@
|
||||
</action>
|
||||
<action name="actionSave_image">
|
||||
<property name="icon">
|
||||
<iconset theme="camera-photo"/>
|
||||
<iconset theme="camera-photo">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save image...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFrequency_Calibration">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Frequency Calibration</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="icons.qrc"/>
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <Cal.hpp>
|
||||
#include <VNA.hpp>
|
||||
#include "App.h"
|
||||
|
||||
@ -18,7 +19,6 @@
|
||||
#include "Generator.hpp"
|
||||
#include "SpectrumAnalyzer.hpp"
|
||||
#include "HW_HAL.hpp"
|
||||
#include "AmplitudeCal.hpp"
|
||||
|
||||
#define LOG_LEVEL LOG_LEVEL_INFO
|
||||
#define LOG_MODULE "App"
|
||||
@ -86,7 +86,7 @@ void App_Start() {
|
||||
EN_6V_GPIO_Port->BSRR = EN_6V_Pin;
|
||||
#endif
|
||||
|
||||
AmplitudeCal::Load();
|
||||
Cal::Load();
|
||||
|
||||
if (!HW::Init()) {
|
||||
LOG_CRIT("Initialization failed, unable to start");
|
||||
@ -191,18 +191,31 @@ void App_Start() {
|
||||
#endif
|
||||
case Protocol::PacketType::RequestSourceCal:
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
AmplitudeCal::SendSource();
|
||||
Cal::SendSource();
|
||||
break;
|
||||
case Protocol::PacketType::RequestReceiverCal:
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
AmplitudeCal::SendReceiver();
|
||||
Cal::SendReceiver();
|
||||
break;
|
||||
case Protocol::PacketType::SourceCalPoint:
|
||||
AmplitudeCal::AddSourcePoint(recv_packet.amplitudePoint);
|
||||
Cal::AddSourcePoint(recv_packet.amplitudePoint);
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
break;
|
||||
case Protocol::PacketType::ReceiverCalPoint:
|
||||
AmplitudeCal::AddReceiverPoint(recv_packet.amplitudePoint);
|
||||
Cal::AddReceiverPoint(recv_packet.amplitudePoint);
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
break;
|
||||
case Protocol::PacketType::RequestFrequencyCorrection:
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
{
|
||||
Protocol::PacketInfo send;
|
||||
send.type = Protocol::PacketType::FrequencyCorrection;
|
||||
send.frequencyCorrection.ppm = Cal::getFrequencyCal();
|
||||
Communication::Send(send);
|
||||
}
|
||||
break;
|
||||
case Protocol::PacketType::FrequencyCorrection:
|
||||
Cal::setFrequencyCal(recv_packet.frequencyCorrection.ppm);
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
break;
|
||||
default:
|
||||
|
@ -1,7 +1,8 @@
|
||||
#include "AmplitudeCal.hpp"
|
||||
#include <Cal.hpp>
|
||||
#include <cstring>
|
||||
#include "Communication.h"
|
||||
#include "HW_HAL.hpp"
|
||||
#include "Hardware.hpp"
|
||||
|
||||
#define LOG_LEVEL LOG_LEVEL_INFO
|
||||
#define LOG_MODULE "CAL"
|
||||
@ -9,26 +10,27 @@
|
||||
|
||||
|
||||
// increment when Calibration struct format changed. If a wrong version is found in flash, it will revert to default values
|
||||
static constexpr uint16_t version = 0x0000;
|
||||
static constexpr uint16_t version = 0x0001;
|
||||
|
||||
using CorrectionTable = struct {
|
||||
uint8_t usedPoints;
|
||||
uint32_t freq[AmplitudeCal::maxPoints]; // LSB = 10Hz
|
||||
int16_t port1Correction[AmplitudeCal::maxPoints]; // LSB = 0.01db
|
||||
int16_t port2Correction[AmplitudeCal::maxPoints]; // LSB = 0.01db
|
||||
uint32_t freq[Cal::maxPoints]; // LSB = 10Hz
|
||||
int16_t port1Correction[Cal::maxPoints]; // LSB = 0.01db
|
||||
int16_t port2Correction[Cal::maxPoints]; // LSB = 0.01db
|
||||
};
|
||||
|
||||
using Calibration = struct _calibration {
|
||||
uint16_t version;
|
||||
CorrectionTable Source;
|
||||
CorrectionTable Receiver;
|
||||
float TCXO_PPM_correction;
|
||||
};
|
||||
|
||||
static Calibration cal;
|
||||
|
||||
static_assert(sizeof(cal) <= AmplitudeCal::flash_size, "Reserved flash size is too small");
|
||||
static_assert(sizeof(cal) <= Cal::flash_size, "Reserved flash size is too small");
|
||||
|
||||
bool AmplitudeCal::Load() {
|
||||
bool Cal::Load() {
|
||||
HWHAL::flash.read(flash_address, sizeof(cal), &cal);
|
||||
if(cal.version != version) {
|
||||
LOG_WARN("Invalid version in flash, expected %u, got %u", version, cal.version);
|
||||
@ -44,7 +46,7 @@ bool AmplitudeCal::Load() {
|
||||
}
|
||||
}
|
||||
|
||||
bool AmplitudeCal::Save() {
|
||||
bool Cal::Save() {
|
||||
if(!HWHAL::flash.eraseRange(flash_address, flash_size)) {
|
||||
return false;
|
||||
}
|
||||
@ -56,7 +58,7 @@ bool AmplitudeCal::Save() {
|
||||
return HWHAL::flash.write(flash_address, write_size, &cal);
|
||||
}
|
||||
|
||||
void AmplitudeCal::SetDefault() {
|
||||
void Cal::SetDefault() {
|
||||
memset(&cal, 0, sizeof(cal));
|
||||
cal.version = version;
|
||||
cal.Source.usedPoints = 1;
|
||||
@ -66,10 +68,10 @@ void AmplitudeCal::SetDefault() {
|
||||
LOG_INFO("Set to default");
|
||||
}
|
||||
|
||||
static AmplitudeCal::Correction InterpolateCorrection(const CorrectionTable& table, uint64_t freq) {
|
||||
static Cal::Correction InterpolateCorrection(const CorrectionTable& table, uint64_t freq) {
|
||||
// adjust LSB to match table
|
||||
freq /= 10;
|
||||
AmplitudeCal::Correction ret;
|
||||
Cal::Correction ret;
|
||||
// find first valid index that is higher than the given frequency
|
||||
uint8_t i = 0;
|
||||
for (; i < table.usedPoints; i++) {
|
||||
@ -94,11 +96,11 @@ static AmplitudeCal::Correction InterpolateCorrection(const CorrectionTable& tab
|
||||
return ret;
|
||||
}
|
||||
|
||||
AmplitudeCal::Correction AmplitudeCal::SourceCorrection(uint64_t freq) {
|
||||
Cal::Correction Cal::SourceCorrection(uint64_t freq) {
|
||||
return InterpolateCorrection(cal.Source, freq);
|
||||
}
|
||||
|
||||
AmplitudeCal::Correction AmplitudeCal::ReceiverCorrection(uint64_t freq) {
|
||||
Cal::Correction Cal::ReceiverCorrection(uint64_t freq) {
|
||||
return InterpolateCorrection(cal.Receiver, freq);
|
||||
}
|
||||
|
||||
@ -116,34 +118,64 @@ static void SendCorrectionTable(const CorrectionTable& table, Protocol::PacketTy
|
||||
}
|
||||
}
|
||||
|
||||
void AmplitudeCal::SendSource() {
|
||||
void Cal::SendSource() {
|
||||
SendCorrectionTable(cal.Source, Protocol::PacketType::SourceCalPoint);
|
||||
}
|
||||
|
||||
void AmplitudeCal::SendReceiver() {
|
||||
void Cal::SendReceiver() {
|
||||
SendCorrectionTable(cal.Receiver, Protocol::PacketType::ReceiverCalPoint);
|
||||
}
|
||||
|
||||
static void addPoint(CorrectionTable& table, const Protocol::AmplitudeCorrectionPoint& p) {
|
||||
if(p.pointNum >= AmplitudeCal::maxPoints) {
|
||||
if(p.pointNum >= Cal::maxPoints) {
|
||||
// ignore out-of-bounds point
|
||||
return;
|
||||
}
|
||||
table.freq[p.pointNum] = p.freq;
|
||||
table.port1Correction[p.pointNum] = p.port1;
|
||||
table.port2Correction[p.pointNum] = p.port2;
|
||||
if(p.pointNum == p.totalPoints - 1 || p.pointNum == AmplitudeCal::maxPoints - 1) {
|
||||
if(p.pointNum == p.totalPoints - 1 || p.pointNum == Cal::maxPoints - 1) {
|
||||
// this was the last point, update used points and save
|
||||
table.usedPoints = p.totalPoints;
|
||||
LOG_INFO("Last point received, saving to flash");
|
||||
AmplitudeCal::Save();
|
||||
Cal::Save();
|
||||
}
|
||||
}
|
||||
|
||||
void AmplitudeCal::AddSourcePoint(const Protocol::AmplitudeCorrectionPoint& p) {
|
||||
void Cal::AddSourcePoint(const Protocol::AmplitudeCorrectionPoint& p) {
|
||||
addPoint(cal.Source, p);
|
||||
}
|
||||
|
||||
void AmplitudeCal::AddReceiverPoint(const Protocol::AmplitudeCorrectionPoint& p) {
|
||||
void Cal::AddReceiverPoint(const Protocol::AmplitudeCorrectionPoint& p) {
|
||||
addPoint(cal.Receiver, p);
|
||||
}
|
||||
|
||||
uint64_t Cal::FrequencyCorrectionToDevice(uint64_t freq) {
|
||||
// The frequency calibration is only used when the internal reference is active.
|
||||
// If an external reference is in use, it is assumed to already be at the correct frequency
|
||||
if(!HW::Ref::usingExternal()) {
|
||||
freq -= freq * cal.TCXO_PPM_correction * 1e-6f;
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
|
||||
uint64_t Cal::FrequencyCorrectionFromDevice(uint64_t freq) {
|
||||
if(!HW::Ref::usingExternal()) {
|
||||
// this formula is not exactly correct, it should actually be
|
||||
// freq *= (1+PPM*10^-6). However, this can not be used directly
|
||||
// due to floating point limitation. But the error of this approximation
|
||||
// is so small that is doesn't make a difference (as the result only has
|
||||
// 1Hz resolution anyway)
|
||||
freq += freq * cal.TCXO_PPM_correction * 1e-6f;
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
|
||||
float Cal::getFrequencyCal() {
|
||||
return cal.TCXO_PPM_correction;
|
||||
}
|
||||
|
||||
bool Cal::setFrequencyCal(float ppm) {
|
||||
cal.TCXO_PPM_correction = ppm;
|
||||
return Save();
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
#include "Firmware.hpp"
|
||||
#include "Protocol.hpp"
|
||||
|
||||
namespace AmplitudeCal {
|
||||
namespace Cal {
|
||||
|
||||
constexpr uint8_t maxPoints = 64;
|
||||
constexpr uint32_t flash_address = Firmware::maxSize; // stored directly behind firmware in flash
|
||||
@ -22,9 +22,16 @@ using Correction = struct _correction {
|
||||
|
||||
Correction SourceCorrection(uint64_t freq);
|
||||
Correction ReceiverCorrection(uint64_t freq);
|
||||
// converts a frequency as received from the GUI to a calibrated value that should be used for the PLLs etc.
|
||||
uint64_t FrequencyCorrectionToDevice(uint64_t freq);
|
||||
// corrects a measured frequency to its calibrated value for transfer to the GUI
|
||||
uint64_t FrequencyCorrectionFromDevice(uint64_t freq);
|
||||
void SendSource();
|
||||
void SendReceiver();
|
||||
void AddSourcePoint(const Protocol::AmplitudeCorrectionPoint& p);
|
||||
void AddReceiverPoint(const Protocol::AmplitudeCorrectionPoint& p);
|
||||
|
||||
float getFrequencyCal();
|
||||
bool setFrequencyCal(float ppm);
|
||||
|
||||
}
|
@ -99,6 +99,7 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_
|
||||
case PacketType::SpectrumAnalyzerResult: payload_size = sizeof(packet.spectrumResult); break;
|
||||
case PacketType::SourceCalPoint:
|
||||
case PacketType::ReceiverCalPoint: payload_size = sizeof(packet.amplitudePoint); break;
|
||||
case PacketType::FrequencyCorrection: payload_size = sizeof(packet.frequencyCorrection); break;
|
||||
case PacketType::Ack:
|
||||
case PacketType::PerformFirmwareUpdate:
|
||||
case PacketType::ClearFlash:
|
||||
@ -107,6 +108,7 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_
|
||||
case PacketType::RequestSourceCal:
|
||||
case PacketType::RequestReceiverCal:
|
||||
case PacketType::SetIdle:
|
||||
case PacketType::RequestFrequencyCorrection:
|
||||
// no payload
|
||||
break;
|
||||
case PacketType::None:
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
namespace Protocol {
|
||||
|
||||
static constexpr uint16_t Version = 4;
|
||||
static constexpr uint16_t Version = 5;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@ -152,6 +152,10 @@ using AmplitudeCorrectionPoint = struct _amplitudecorrectionpoint {
|
||||
int16_t port2;
|
||||
};
|
||||
|
||||
using FrequencyCorrection = struct _frequencycorrection {
|
||||
float ppm;
|
||||
};
|
||||
|
||||
enum class PacketType : uint8_t {
|
||||
None = 0,
|
||||
Datapoint = 1,
|
||||
@ -174,6 +178,8 @@ enum class PacketType : uint8_t {
|
||||
SourceCalPoint = 18,
|
||||
ReceiverCalPoint = 19,
|
||||
SetIdle = 20,
|
||||
RequestFrequencyCorrection = 21,
|
||||
FrequencyCorrection = 22,
|
||||
};
|
||||
|
||||
using PacketInfo = struct _packetinfo {
|
||||
@ -190,6 +196,7 @@ using PacketInfo = struct _packetinfo {
|
||||
SpectrumAnalyzerSettings spectrumSettings;
|
||||
SpectrumAnalyzerResult spectrumResult;
|
||||
AmplitudeCorrectionPoint amplitudePoint;
|
||||
FrequencyCorrection frequencyCorrection;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include <Cal.hpp>
|
||||
#include "Generator.hpp"
|
||||
#include "Manual.hpp"
|
||||
#include "Hardware.hpp"
|
||||
#include "max2871.hpp"
|
||||
#include "Si5351C.hpp"
|
||||
#include "AmplitudeCal.hpp"
|
||||
|
||||
void Generator::Setup(Protocol::GeneratorSettings g) {
|
||||
if(g.activePort == 0) {
|
||||
@ -35,6 +35,7 @@ void Generator::Setup(Protocol::GeneratorSettings g) {
|
||||
m.PortSwitch = 1;
|
||||
break;
|
||||
}
|
||||
g.frequency = Cal::FrequencyCorrectionToDevice(g.frequency);
|
||||
auto amplitude = HW::GetAmplitudeSettings(g.cdbm_level, g.frequency, g.applyAmplitudeCorrection, g.activePort == 2);
|
||||
// Select correct source
|
||||
if(g.frequency < HW::BandSwitchFrequency) {
|
||||
|
@ -235,7 +235,7 @@ void HW::SetIdle() {
|
||||
|
||||
HW::AmplitudeSettings HW::GetAmplitudeSettings(int16_t cdbm, uint64_t freq, bool applyCorrections, bool port2) {
|
||||
if (applyCorrections) {
|
||||
auto correction = AmplitudeCal::SourceCorrection(freq);
|
||||
auto correction = Cal::SourceCorrection(freq);
|
||||
if (port2) {
|
||||
cdbm += correction.port2;
|
||||
} else {
|
||||
@ -336,6 +336,10 @@ void HW::Ref::set(Protocol::ReferenceSettings s) {
|
||||
ref = s;
|
||||
}
|
||||
|
||||
bool HW::Ref::usingExternal() {
|
||||
return extRefInUse;
|
||||
}
|
||||
|
||||
void HW::Ref::update() {
|
||||
if(extOutFreq != ref.ExtRefOuputFreq) {
|
||||
extOutFreq = ref.ExtRefOuputFreq;
|
||||
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Cal.hpp>
|
||||
#include <cstdint>
|
||||
#include "Protocol.hpp"
|
||||
#include "FPGA/FPGA.hpp"
|
||||
#include "AmplitudeCal.hpp"
|
||||
#include "max2871.hpp"
|
||||
#include "Si5351C.hpp"
|
||||
|
||||
@ -73,7 +73,7 @@ static constexpr Protocol::DeviceInfo Info = {
|
||||
.limits_cdbm_max = 0,
|
||||
.limits_minRBW = (uint32_t) (ADCSamplerate * 2.23f / MaxSamples),
|
||||
.limits_maxRBW = (uint32_t) (ADCSamplerate * 2.23f / MinSamples),
|
||||
.limits_maxAmplitudePoints = AmplitudeCal::maxPoints,
|
||||
.limits_maxAmplitudePoints = Cal::maxPoints,
|
||||
.limits_maxFreqHarmonic = 18000000000,
|
||||
};
|
||||
|
||||
@ -106,6 +106,7 @@ bool GetTemps(uint8_t *source, uint8_t *lo);
|
||||
void fillDeviceInfo(Protocol::DeviceInfo *info, bool updateEvenWhenBusy = false);
|
||||
namespace Ref {
|
||||
bool available();
|
||||
bool usingExternal();
|
||||
// reference won't change until update is called
|
||||
void set(Protocol::ReferenceSettings s);
|
||||
void update();
|
||||
|
@ -38,6 +38,7 @@ static bool trackingLowband;
|
||||
|
||||
static void StartNextSample() {
|
||||
uint64_t freq = s.f_start + (s.f_stop - s.f_start) * pointCnt / (points - 1);
|
||||
freq = Cal::FrequencyCorrectionToDevice(freq);
|
||||
uint64_t LO1freq;
|
||||
uint32_t LO2freq;
|
||||
switch(signalIDstep) {
|
||||
@ -364,7 +365,7 @@ void SA::Work() {
|
||||
p.spectrumResult.port1 /= 253000000.0;
|
||||
p.spectrumResult.port2 /= 253000000.0;
|
||||
if (s.applyReceiverCorrection) {
|
||||
auto correction = AmplitudeCal::ReceiverCorrection(p.spectrumResult.frequency);
|
||||
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);
|
||||
}
|
||||
|
@ -117,6 +117,7 @@ bool VNA::Setup(Protocol::SweepSettings s) {
|
||||
for (uint16_t i = 0; i < points; i++) {
|
||||
bool harmonic_mixing = false;
|
||||
uint64_t freq = s.f_start + (s.f_stop - s.f_start) * i / (points - 1);
|
||||
freq = Cal::FrequencyCorrectionToDevice(freq);
|
||||
|
||||
if(freq > 6000000000ULL) {
|
||||
harmonic_mixing = true;
|
||||
|
Loading…
Reference in New Issue
Block a user