Working source and receiver calibration
This commit is contained in:
parent
875f3b0170
commit
026fffd588
@ -7,6 +7,7 @@ HEADERS += \
|
||||
Calibration/calkitdialog.h \
|
||||
Calibration/json.hpp \
|
||||
Calibration/measurementmodel.h \
|
||||
Calibration/receivercaldialog.h \
|
||||
Calibration/sourcecaldialog.h \
|
||||
CustomWidgets/colorpickerbutton.h \
|
||||
CustomWidgets/informationbox.h \
|
||||
@ -56,6 +57,7 @@ SOURCES += \
|
||||
Calibration/calkit.cpp \
|
||||
Calibration/calkitdialog.cpp \
|
||||
Calibration/measurementmodel.cpp \
|
||||
Calibration/receivercaldialog.cpp \
|
||||
Calibration/sourcecaldialog.cpp \
|
||||
CustomWidgets/colorpickerbutton.cpp \
|
||||
CustomWidgets/informationbox.cpp \
|
||||
@ -106,6 +108,7 @@ win32:LIBS += -LC:\Qwt-6.1.4\lib -lqwt
|
||||
QT += widgets
|
||||
|
||||
FORMS += \
|
||||
Calibration/addamplitudepointsdialog.ui \
|
||||
Calibration/amplitudecaldialog.ui \
|
||||
Calibration/calibrationtracedialog.ui \
|
||||
Calibration/calkitdialog.ui \
|
||||
|
138
Software/PC_Application/Calibration/addamplitudepointsdialog.ui
Normal file
138
Software/PC_Application/Calibration/addamplitudepointsdialog.ui
Normal file
@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AddAmplitudePointsDialog</class>
|
||||
<widget class="QDialog" name="AddAmplitudePointsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>564</width>
|
||||
<height>139</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Add points</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,1">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="singlePoint">
|
||||
<property name="text">
|
||||
<string>Single Point at</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">groupType</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SIUnitEdit" name="frequency"/>
|
||||
</item>
|
||||
<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>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0,0,1">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="array">
|
||||
<property name="text">
|
||||
<string>Array of </string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">groupType</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="numPoints">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>64</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>points from</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SIUnitEdit" name="startFreq"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>to</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SIUnitEdit" name="stopFreq"/>
|
||||
</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="QCheckBox" name="deleteExisting">
|
||||
<property name="text">
|
||||
<string>Delete already existing points</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<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/>
|
||||
<buttongroups>
|
||||
<buttongroup name="groupType"/>
|
||||
</buttongroups>
|
||||
</ui>
|
@ -3,12 +3,17 @@
|
||||
#include "mode.h"
|
||||
#include "unit.h"
|
||||
#include <QDebug>
|
||||
#include "ui_addamplitudepointsdialog.h"
|
||||
#include <QMessageBox>
|
||||
|
||||
using namespace std;
|
||||
|
||||
AmplitudeCalDialog::AmplitudeCalDialog(Device *dev, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::AmplitudeCalDialog),
|
||||
dev(dev),
|
||||
model(this)
|
||||
model(this),
|
||||
mode(CalibrationMode::BothPorts)
|
||||
{
|
||||
activeMode = Mode::getActiveMode();
|
||||
activeMode->deactivate();
|
||||
@ -20,9 +25,40 @@ AmplitudeCalDialog::AmplitudeCalDialog(Device *dev, QWidget *parent) :
|
||||
ui->view->setColumnWidth(AmplitudeModel::ColIndexPort1, 150);
|
||||
ui->view->setColumnWidth(AmplitudeModel::ColIndexPort2, 150);
|
||||
connect(dev, &Device::AmplitudeCorrectionPointReceived, this, &AmplitudeCalDialog::ReceivedPoint);
|
||||
connect(ui->load, &QPushButton::clicked, this, &AmplitudeCalDialog::LoadFromDevice);
|
||||
connect(ui->add, &QPushButton::clicked, this, &AmplitudeCalDialog::AddPoint);
|
||||
connect(ui->remove, &QPushButton::clicked, this, &AmplitudeCalDialog::RemovePoint);
|
||||
connect(ui->load, &QPushButton::clicked, [=](){
|
||||
if(ConfirmActionIfEdited()) {
|
||||
LoadFromDevice();
|
||||
}
|
||||
});
|
||||
connect(ui->save, &QPushButton::clicked, this, &AmplitudeCalDialog::SaveToDevice);
|
||||
connect(ui->add, &QPushButton::clicked, this, &AmplitudeCalDialog::AddPointDialog);
|
||||
connect(ui->remove, &QPushButton::clicked, [=](){
|
||||
unsigned int row = ui->view->currentIndex().row();
|
||||
if(row < points.size()) {
|
||||
RemovePoint(row);
|
||||
}
|
||||
});
|
||||
auto selectionModel = ui->view->selectionModel();
|
||||
connect(selectionModel, &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex&) {
|
||||
if(current.isValid() && (current.column() == model.ColIndexPort1 || current.column() == model.ColIndexPort2)) {
|
||||
SelectedPoint(points[current.row()].frequency, current.column() == model.ColIndexPort2);
|
||||
} else {
|
||||
// Invalid selection
|
||||
SelectedPoint(0, false);
|
||||
}
|
||||
});
|
||||
connect(ui->modeBoth, &QPushButton::pressed, [=](){
|
||||
mode = CalibrationMode::BothPorts;
|
||||
model.dataChanged(model.index(0, model.ColIndexPort1), model.index(points.size(), model.ColIndexPort2));
|
||||
});
|
||||
connect(ui->modePort1, &QPushButton::pressed, [=](){
|
||||
mode = CalibrationMode::OnlyPort1;
|
||||
model.dataChanged(model.index(0, model.ColIndexPort1), model.index(points.size(), model.ColIndexPort2));
|
||||
});
|
||||
connect(ui->modePort2, &QPushButton::pressed, [=](){
|
||||
mode = CalibrationMode::OnlyPort2;
|
||||
model.dataChanged(model.index(0, model.ColIndexPort1), model.index(points.size(), model.ColIndexPort2));
|
||||
});
|
||||
}
|
||||
|
||||
AmplitudeCalDialog::~AmplitudeCalDialog()
|
||||
@ -33,8 +69,9 @@ AmplitudeCalDialog::~AmplitudeCalDialog()
|
||||
|
||||
void AmplitudeCalDialog::reject()
|
||||
{
|
||||
// TODO check for unsaved data
|
||||
if(ConfirmActionIfEdited()) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<AmplitudeCalDialog::CorrectionPoint> AmplitudeCalDialog::getPoints() const
|
||||
@ -49,9 +86,24 @@ void AmplitudeCalDialog::setAmplitude(double amplitude, unsigned int point, bool
|
||||
}
|
||||
if(port2) {
|
||||
points[point].amplitudePort2 = amplitude;
|
||||
points[point].port2set = true;
|
||||
} else {
|
||||
points[point].amplitudePort1 = amplitude;
|
||||
points[point].port1set = true;
|
||||
}
|
||||
edited = true;
|
||||
AmplitudeChanged(points[point], port2);
|
||||
if(mode == CalibrationMode::OnlyPort1 && !port2) {
|
||||
// apply result from port 1 to port 2 as well
|
||||
points[point].correctionPort2 = points[point].correctionPort1;
|
||||
points[point].port2set = points[point].port1set;
|
||||
} else if(mode == CalibrationMode::OnlyPort2 && port2) {
|
||||
// apply result from port 2 to port 1 as well
|
||||
points[point].correctionPort1 = points[point].correctionPort2;
|
||||
points[point].port1set = points[point].port2set;
|
||||
}
|
||||
model.dataChanged(model.index(point, model.ColIndexCorrectionFactors), model.index(point, model.ColIndexPort2));
|
||||
UpdateSaveButton();
|
||||
}
|
||||
|
||||
void AmplitudeCalDialog::ReceivedPoint(Protocol::AmplitudeCorrectionPoint p)
|
||||
@ -61,7 +113,10 @@ void AmplitudeCalDialog::ReceivedPoint(Protocol::AmplitudeCorrectionPoint p)
|
||||
c.frequency = p.freq * 10.0;
|
||||
c.correctionPort1 = p.port1;
|
||||
c.correctionPort2 = p.port2;
|
||||
c.port1set = false;
|
||||
c.port2set = false;
|
||||
model.beginInsertRows(QModelIndex(), points.size(), points.size());
|
||||
UpdateAmplitude(c);
|
||||
points.push_back(c);
|
||||
model.endInsertRows();
|
||||
emit pointsUpdated();
|
||||
@ -69,15 +124,17 @@ void AmplitudeCalDialog::ReceivedPoint(Protocol::AmplitudeCorrectionPoint p)
|
||||
|
||||
void AmplitudeCalDialog::LoadFromDevice()
|
||||
{
|
||||
model.beginResetModel();
|
||||
points.clear();
|
||||
model.endResetModel();
|
||||
dev->SetIdle();
|
||||
RemoveAllPoints();
|
||||
qDebug() << "Asking for amplitude calibration";
|
||||
dev->SendCommandWithoutPayload(requestCommand());
|
||||
edited = false;
|
||||
ui->save->setEnabled(false);
|
||||
}
|
||||
|
||||
void AmplitudeCalDialog::SaveToDevice()
|
||||
{
|
||||
dev->SetIdle();
|
||||
for(unsigned int i=0;i<points.size();i++) {
|
||||
auto p = points[i];
|
||||
Protocol::PacketInfo info;
|
||||
@ -89,21 +146,134 @@ void AmplitudeCalDialog::SaveToDevice()
|
||||
info.amplitudePoint.pointNum = i;
|
||||
dev->SendPacket(info);
|
||||
}
|
||||
edited = false;
|
||||
ui->save->setEnabled(false);
|
||||
}
|
||||
|
||||
void AmplitudeCalDialog::RemovePoint()
|
||||
void AmplitudeCalDialog::RemovePoint(unsigned int i)
|
||||
{
|
||||
unsigned int row = ui->view->currentIndex().row();
|
||||
if(row < points.size()) {
|
||||
model.beginRemoveRows(QModelIndex(), row, row);
|
||||
points.erase(points.begin() + row);
|
||||
model.beginRemoveRows(QModelIndex(), i, i);
|
||||
points.erase(points.begin() + i);
|
||||
model.endRemoveRows();
|
||||
edited = true;
|
||||
UpdateSaveButton();
|
||||
}
|
||||
|
||||
void AmplitudeCalDialog::RemoveAllPoints()
|
||||
{
|
||||
model.beginResetModel();
|
||||
points.clear();
|
||||
model.endResetModel();
|
||||
edited = true;
|
||||
ui->save->setEnabled(false);
|
||||
UpdateSaveButton();
|
||||
}
|
||||
|
||||
void AmplitudeCalDialog::AddPoint(double frequency)
|
||||
{
|
||||
if(points.size() >= Device::Info().limits_maxAmplitudePoints) {
|
||||
qWarning() << "Unable to add amplitude point, already maximum limit (" << Device::Info().limits_maxAmplitudePoints << ")";
|
||||
return;
|
||||
}
|
||||
// find position at which this frequency gets inserted
|
||||
auto index = upper_bound(points.begin(), points.end(), frequency, [](double value, const CorrectionPoint& p){
|
||||
return value < p.frequency;
|
||||
});
|
||||
model.beginInsertRows(QModelIndex(), index - points.begin(), index - points.begin());
|
||||
CorrectionPoint newPoint;
|
||||
newPoint.frequency = frequency;
|
||||
newPoint.correctionPort1 = 0;
|
||||
newPoint.correctionPort2 = 0;
|
||||
newPoint.port1set = false;
|
||||
newPoint.port2set = false;
|
||||
emit newPointCreated(newPoint);
|
||||
points.insert(index, newPoint);
|
||||
model.endInsertRows();
|
||||
edited = true;
|
||||
UpdateSaveButton();
|
||||
}
|
||||
|
||||
void AmplitudeCalDialog::AddPointDialog()
|
||||
{
|
||||
auto d = new QDialog();
|
||||
auto ui = new Ui::AddAmplitudePointsDialog();
|
||||
ui->setupUi(d);
|
||||
ui->frequency->setUnit("Hz");
|
||||
ui->frequency->setPrefixes(" kMG");
|
||||
ui->startFreq->setUnit("Hz");
|
||||
ui->startFreq->setPrefixes(" kMG");
|
||||
ui->stopFreq->setUnit("Hz");
|
||||
ui->stopFreq->setPrefixes(" kMG");
|
||||
ui->frequency->setValue(1000000000.0);
|
||||
ui->startFreq->setValue(Device::Info().limits_minFreq);
|
||||
ui->stopFreq->setValue(Device::Info().limits_maxFreq);
|
||||
connect(ui->singlePoint, &QRadioButton::toggled, [=](bool single) {
|
||||
ui->stopFreq->setEnabled(!single);
|
||||
ui->startFreq->setEnabled(!single);
|
||||
ui->numPoints->setEnabled(!single);
|
||||
ui->frequency->setEnabled(single);
|
||||
});
|
||||
ui->singlePoint->setChecked(true);
|
||||
ui->frequency->setFocus();
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [=](){
|
||||
// okay clicked, apply selected action
|
||||
if(ui->deleteExisting->isChecked()) {
|
||||
RemoveAllPoints();
|
||||
}
|
||||
if(ui->singlePoint->isChecked()) {
|
||||
AddPoint(ui->frequency->value());
|
||||
} else {
|
||||
double freq_start = ui->startFreq->value();
|
||||
double freq_stop = ui->stopFreq->value();
|
||||
unsigned int points = ui->numPoints->value();
|
||||
double freq_step = (freq_stop - freq_start) / (points - 1);
|
||||
for(unsigned int i=0;i<points;i++) {
|
||||
AddPoint(freq_start + i * freq_step);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(d, &QDialog::rejected, ui->buttonBox, &QDialogButtonBox::rejected);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, [=](){
|
||||
// aborted, nothing to do
|
||||
delete d;
|
||||
});
|
||||
d->show();
|
||||
}
|
||||
|
||||
bool AmplitudeCalDialog::ConfirmActionIfEdited()
|
||||
{
|
||||
if(edited) {
|
||||
auto reply = QMessageBox::question(this, "Confirm action", "Some points have been edited but not saved in the device yet. If you continue, all changes will be lost. Do you want to continue?",
|
||||
QMessageBox::Yes|QMessageBox::No);
|
||||
return reply == QMessageBox::Yes;
|
||||
} else {
|
||||
// not edited yet, nothing to confirm
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void AmplitudeCalDialog::AddPoint()
|
||||
void AmplitudeCalDialog::UpdateSaveButton()
|
||||
{
|
||||
bool enable = true;
|
||||
if(points.size() == 0) {
|
||||
// needs at least one point
|
||||
enable = false;
|
||||
}
|
||||
for(auto p : points) {
|
||||
if(!p.port1set || !p.port2set) {
|
||||
// some points are not set yet
|
||||
enable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ui->save->setEnabled(enable);
|
||||
}
|
||||
|
||||
AmplitudeCalDialog::CalibrationMode AmplitudeCalDialog::getMode() const
|
||||
{
|
||||
return mode;
|
||||
}
|
||||
|
||||
AmplitudeModel::AmplitudeModel(AmplitudeCalDialog *c) :
|
||||
@ -134,10 +304,18 @@ QVariant AmplitudeModel::data(const QModelIndex &index, int role) const
|
||||
return QString::number(p.correctionPort1) + ", " + QString::number(p.correctionPort2);
|
||||
break;
|
||||
case ColIndexPort1:
|
||||
if (p.port1set) {
|
||||
return Unit::ToString(p.amplitudePort1, "dbm", " ", 4);
|
||||
} else {
|
||||
return "No data";
|
||||
}
|
||||
break;
|
||||
case ColIndexPort2:
|
||||
if (p.port2set) {
|
||||
return Unit::ToString(p.amplitudePort2, "dbm", " ", 4);
|
||||
} else {
|
||||
return "No data";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -180,8 +358,16 @@ Qt::ItemFlags AmplitudeModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
int flags = Qt::NoItemFlags;
|
||||
switch(index.column()) {
|
||||
case ColIndexPort1: flags |= Qt::ItemIsEnabled | Qt::ItemIsEditable; break;
|
||||
case ColIndexPort2: flags |= Qt::ItemIsEnabled | Qt::ItemIsEditable; break;
|
||||
case ColIndexPort1:
|
||||
if(c->getMode() != AmplitudeCalDialog::CalibrationMode::OnlyPort2) {
|
||||
flags |= Qt::ItemIsEnabled | Qt::ItemIsEditable;
|
||||
}
|
||||
break;
|
||||
case ColIndexPort2:
|
||||
if(c->getMode() != AmplitudeCalDialog::CalibrationMode::OnlyPort1) {
|
||||
flags |= Qt::ItemIsEnabled | Qt::ItemIsEditable;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (Qt::ItemFlags) flags;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef AMPLITUDECALDIALOG_H
|
||||
#ifndef AMPLITUDECALDIALOG_H
|
||||
#define AMPLITUDECALDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
@ -48,30 +48,53 @@ public:
|
||||
class CorrectionPoint {
|
||||
public:
|
||||
double frequency;
|
||||
double correctionPort1;
|
||||
double correctionPort2;
|
||||
int16_t correctionPort1;
|
||||
int16_t correctionPort2;
|
||||
double amplitudePort1;
|
||||
double amplitudePort2;
|
||||
bool port1set;
|
||||
bool port2set;
|
||||
};
|
||||
std::vector<CorrectionPoint> getPoints() const;
|
||||
void setAmplitude(double amplitude, unsigned int point, bool port2);
|
||||
|
||||
enum class CalibrationMode {
|
||||
BothPorts,
|
||||
OnlyPort1,
|
||||
OnlyPort2,
|
||||
};
|
||||
|
||||
CalibrationMode getMode() const;
|
||||
|
||||
protected slots:
|
||||
void ReceivedPoint(Protocol::AmplitudeCorrectionPoint p);
|
||||
void LoadFromDevice();
|
||||
void SaveToDevice();
|
||||
void RemovePoint();
|
||||
void AddPoint();
|
||||
void RemovePoint(unsigned int i);
|
||||
void RemoveAllPoints();
|
||||
void AddPoint(double frequency);
|
||||
void AddPointDialog();
|
||||
signals:
|
||||
void pointsUpdated();
|
||||
void newPointCreated(CorrectionPoint& p);
|
||||
protected:
|
||||
bool ConfirmActionIfEdited();
|
||||
void UpdateSaveButton();
|
||||
virtual Protocol::PacketType requestCommand() = 0;
|
||||
virtual Protocol::PacketType pointType() = 0;
|
||||
// will get called whenever a new cell is selected (frequency=0 means invalid selection)
|
||||
virtual void SelectedPoint(double frequency, bool port2) = 0;
|
||||
// will get called whenever the amplitude is changed. Derived class is responsible for updating correction factor
|
||||
virtual void AmplitudeChanged(CorrectionPoint& point, bool port2) = 0;
|
||||
// called whenver the correction factor have been retrieved from the device and the amplitudes need to be updated
|
||||
virtual void UpdateAmplitude(CorrectionPoint& point) = 0;
|
||||
std::vector<CorrectionPoint> points;
|
||||
Ui::AmplitudeCalDialog *ui;
|
||||
Device *dev;
|
||||
Mode *activeMode;
|
||||
AmplitudeModel model;
|
||||
bool edited;
|
||||
CalibrationMode mode;
|
||||
};
|
||||
|
||||
#endif // SOURCECALDIALOG_H
|
||||
|
@ -28,11 +28,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="add">
|
||||
<property name="text">
|
||||
<string>Add Point</string>
|
||||
<string>Add Point(s)</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="list-add" resource="../icons.qrc">
|
||||
@ -57,7 +57,8 @@
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="help"/>
|
||||
<iconset theme="help">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -74,6 +75,9 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="save">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save to Device</string>
|
||||
</property>
|
||||
@ -83,6 +87,101 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Calibration Mode</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="modeBoth">
|
||||
<property name="text">
|
||||
<string>Both Ports</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">groupMode</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Best accuracy</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="modePort1">
|
||||
<property name="text">
|
||||
<string>Only Port 1</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">groupMode</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use same correction for port 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="modePort2">
|
||||
<property name="text">
|
||||
<string>Only Port 2</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">groupMode</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use same correction for port 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
@ -104,4 +203,7 @@
|
||||
<include location="../icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="groupMode"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
58
Software/PC_Application/Calibration/receivercaldialog.cpp
Normal file
58
Software/PC_Application/Calibration/receivercaldialog.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#include "receivercaldialog.h"
|
||||
|
||||
ReceiverCalDialog::ReceiverCalDialog(Device *dev)
|
||||
: AmplitudeCalDialog(dev)
|
||||
{
|
||||
setWindowTitle("Receiver Calibration Dialog");
|
||||
LoadFromDevice();
|
||||
connect(dev, &Device::SpectrumResultReceived, [=](Protocol::SpectrumAnalyzerResult res) {
|
||||
if(res.pointNum == 1) {
|
||||
// store result in center of sweep of 3 points
|
||||
port1_result = 20*log10(res.port1);
|
||||
port2_result = 20*log10(res.port2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ReceiverCalDialog::SelectedPoint(double frequency, bool port2)
|
||||
{
|
||||
if(frequency > 0) {
|
||||
Protocol::PacketInfo p;
|
||||
p.type = Protocol::PacketType::SpectrumAnalyzerSettings;
|
||||
p.spectrumSettings.RBW = 10000;
|
||||
p.spectrumSettings.UseDFT = 0;
|
||||
// setup 3 points centered around the measurement frequency (zero span not supported yet)
|
||||
p.spectrumSettings.f_stop = frequency + 1.0;
|
||||
p.spectrumSettings.f_start = frequency - 1.0;
|
||||
p.spectrumSettings.pointNum = 3;
|
||||
p.spectrumSettings.Detector = 0;
|
||||
p.spectrumSettings.SignalID = 1;
|
||||
p.spectrumSettings.WindowType = 3;
|
||||
p.spectrumSettings.applyReceiverCorrection = 0;
|
||||
dev->SendPacket(p);
|
||||
} else {
|
||||
// invalid frequency, disable
|
||||
dev->SetIdle();
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiverCalDialog::AmplitudeChanged(AmplitudeCalDialog::CorrectionPoint &point, bool port2)
|
||||
{
|
||||
auto *factor = port2 ? &point.correctionPort2 : &point.correctionPort1;
|
||||
const auto *amplitude = port2 ? &point.amplitudePort2 : &point.amplitudePort1;
|
||||
const auto *measured = port2 ? &port2_result : &port1_result;
|
||||
// calculate correction factor by comparing expected with measured amplitude
|
||||
*factor = (*measured - *amplitude) * 100.0;
|
||||
}
|
||||
|
||||
void ReceiverCalDialog::UpdateAmplitude(AmplitudeCalDialog::CorrectionPoint &point)
|
||||
{
|
||||
// This point was just received from the device, it is not possible to know the actual amplitude because the
|
||||
// applied power level during the calibration is not saved (only the correction value). This is not a problem
|
||||
// because the correction value is still valid but the missing values look weird in the GUI
|
||||
// TODO change this?
|
||||
point.amplitudePort1 = std::numeric_limits<double>::quiet_NaN();
|
||||
point.amplitudePort2 = std::numeric_limits<double>::quiet_NaN();
|
||||
point.port1set = true;
|
||||
point.port2set = true;
|
||||
}
|
22
Software/PC_Application/Calibration/receivercaldialog.h
Normal file
22
Software/PC_Application/Calibration/receivercaldialog.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef RECEIVERCALDIALOG_H
|
||||
#define RECEIVERCALDIALOG_H
|
||||
|
||||
#include "amplitudecaldialog.h"
|
||||
|
||||
class ReceiverCalDialog : public AmplitudeCalDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ReceiverCalDialog(Device *dev);
|
||||
protected:
|
||||
Protocol::PacketType requestCommand() override { return Protocol::PacketType::RequestReceiverCal; }
|
||||
Protocol::PacketType pointType() override { return Protocol::PacketType::ReceiverCalPoint; }
|
||||
void SelectedPoint(double frequency, bool port2) override;
|
||||
void AmplitudeChanged(CorrectionPoint &point, bool port2) override;
|
||||
void UpdateAmplitude(CorrectionPoint& point) override;
|
||||
private:
|
||||
static constexpr double excitationAmplitude = -20.0;
|
||||
double port1_result, port2_result; // raw (uncorrected) measurements from device
|
||||
};
|
||||
|
||||
#endif // RECEIVERCALDIALOG_H
|
@ -1,8 +1,47 @@
|
||||
#include "sourcecaldialog.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
SourceCalDialog::SourceCalDialog(Device *dev)
|
||||
: AmplitudeCalDialog(dev)
|
||||
{
|
||||
setWindowTitle("Source Calibration Dialog");
|
||||
LoadFromDevice();
|
||||
}
|
||||
|
||||
void SourceCalDialog::SelectedPoint(double frequency, bool port2)
|
||||
{
|
||||
Protocol::PacketInfo p;
|
||||
p.type = Protocol::PacketType::Generator;
|
||||
|
||||
p.generator.frequency = frequency;
|
||||
p.generator.cdbm_level = excitationAmplitude * 100.0;
|
||||
if(frequency > 0) {
|
||||
if(port2) {
|
||||
p.generator.activePort = 2;
|
||||
} else {
|
||||
p.generator.activePort = 1;
|
||||
}
|
||||
} else {
|
||||
// invalid frequency, disable both ports
|
||||
p.generator.activePort = 0;
|
||||
}
|
||||
p.generator.applyAmplitudeCorrection = 0;
|
||||
dev->SendPacket(p);
|
||||
}
|
||||
|
||||
void SourceCalDialog::AmplitudeChanged(AmplitudeCalDialog::CorrectionPoint &point, bool port2)
|
||||
{
|
||||
auto *factor = port2 ? &point.correctionPort2 : &point.correctionPort1;
|
||||
const auto *amplitude = port2 ? &point.amplitudePort2 : &point.amplitudePort1;
|
||||
// calculate correction factor by comparing expected with measured amplitude
|
||||
*factor = (excitationAmplitude - *amplitude) * 100.0;
|
||||
}
|
||||
|
||||
void SourceCalDialog::UpdateAmplitude(AmplitudeCalDialog::CorrectionPoint &point)
|
||||
{
|
||||
point.amplitudePort1 = excitationAmplitude - (double) point.correctionPort1 / 100.0;
|
||||
point.amplitudePort2 = excitationAmplitude - (double) point.correctionPort2 / 100.0;
|
||||
point.port1set = true;
|
||||
point.port2set = true;
|
||||
}
|
||||
|
@ -12,6 +12,11 @@ public:
|
||||
protected:
|
||||
Protocol::PacketType requestCommand() override { return Protocol::PacketType::RequestSourceCal; }
|
||||
Protocol::PacketType pointType() override { return Protocol::PacketType::SourceCalPoint; }
|
||||
void SelectedPoint(double frequency, bool port2) override;
|
||||
void AmplitudeChanged(CorrectionPoint &point, bool port2) override;
|
||||
void UpdateAmplitude(CorrectionPoint& point) override;
|
||||
private:
|
||||
static constexpr double excitationAmplitude = -20.0;
|
||||
};
|
||||
|
||||
#endif // SOURCECALDIALOG_H
|
||||
|
@ -136,6 +136,7 @@ static constexpr Protocol::DeviceInfo defaultInfo = {
|
||||
.limits_cdbm_max = 1000,
|
||||
.limits_minRBW = 1,
|
||||
.limits_maxRBW = 1000000,
|
||||
.limits_maxAmplitudePoints = 255,
|
||||
};
|
||||
|
||||
Protocol::DeviceInfo Device::lastInfo = defaultInfo;
|
||||
|
@ -53,6 +53,7 @@ Protocol::GeneratorSettings SignalgeneratorWidget::getDeviceStatus()
|
||||
} else {
|
||||
s.activePort = 0;
|
||||
}
|
||||
s.applyAmplitudeCorrection = 1;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -229,9 +229,6 @@ using namespace std;
|
||||
|
||||
void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d)
|
||||
{
|
||||
// TODO level adjustment in device
|
||||
d.port1 /= 126500000.0;
|
||||
d.port2 /= 126500000.0;
|
||||
d = average.process(d);
|
||||
traceModel.addSAData(d, settings);
|
||||
emit dataChanged();
|
||||
@ -248,6 +245,7 @@ void SpectrumAnalyzer::SettingsChanged()
|
||||
} else {
|
||||
settings.pointNum = settings.f_stop - settings.f_start + 1;
|
||||
}
|
||||
settings.applyReceiverCorrection = 1;
|
||||
|
||||
auto pref = Preferences::getInstance();
|
||||
if(pref.Acquisition.useDFTinSAmode && settings.RBW <= pref.Acquisition.RBWLimitForDFT) {
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "Generator/generator.h"
|
||||
#include "SpectrumAnalyzer/spectrumanalyzer.h"
|
||||
#include "Calibration/sourcecaldialog.h"
|
||||
#include "Calibration/receivercaldialog.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -102,6 +103,7 @@ AppWindow::AppWindow(QWidget *parent)
|
||||
connect(ui->actionManual_Control, &QAction::triggered, this, &AppWindow::StartManualControl);
|
||||
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->actionPreferences, &QAction::triggered, [=](){
|
||||
Preferences::getInstance().edit();
|
||||
// settings might have changed, update necessary stuff
|
||||
@ -187,6 +189,7 @@ void AppWindow::ConnectToDevice(QString serial)
|
||||
ui->actionManual_Control->setEnabled(true);
|
||||
ui->actionFirmware_Update->setEnabled(true);
|
||||
ui->actionSource_Calibration->setEnabled(true);
|
||||
ui->actionReceiver_Calibration->setEnabled(true);
|
||||
|
||||
Mode::getActiveMode()->initializeDevice();
|
||||
UpdateReference();
|
||||
@ -214,6 +217,7 @@ void AppWindow::DisconnectDevice()
|
||||
ui->actionManual_Control->setEnabled(false);
|
||||
ui->actionFirmware_Update->setEnabled(false);
|
||||
ui->actionSource_Calibration->setEnabled(false);
|
||||
ui->actionReceiver_Calibration->setEnabled(false);
|
||||
for(auto a : deviceActionGroup->actions()) {
|
||||
a->setChecked(false);
|
||||
}
|
||||
@ -362,6 +366,12 @@ void AppWindow::SourceCalibrationDialog()
|
||||
d->exec();
|
||||
}
|
||||
|
||||
void AppWindow::ReceiverCalibrationDialog()
|
||||
{
|
||||
auto d = new ReceiverCalDialog(device);
|
||||
d->exec();
|
||||
}
|
||||
|
||||
Device *AppWindow::getDevice() const
|
||||
{
|
||||
return device;
|
||||
|
@ -45,6 +45,7 @@ private slots:
|
||||
void StartFirmwareUpdateDialog();
|
||||
void DeviceNeedsUpdate(int reported, int expected);
|
||||
void SourceCalibrationDialog();
|
||||
void ReceiverCalibrationDialog();
|
||||
private:
|
||||
void DeviceConnectionLost();
|
||||
void CreateToolbars();
|
||||
|
@ -50,6 +50,7 @@
|
||||
<addaction name="actionFirmware_Update"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSource_Calibration"/>
|
||||
<addaction name="actionReceiver_Calibration"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuWindow">
|
||||
<property name="title">
|
||||
@ -161,6 +162,14 @@
|
||||
<string>Source Calibration</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionReceiver_Calibration">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Receiver Calibration</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="icons.qrc"/>
|
||||
|
@ -44,7 +44,12 @@ bool AmplitudeCal::Save() {
|
||||
if(!HWHAL::flash.eraseRange(flash_address, flash_size)) {
|
||||
return false;
|
||||
}
|
||||
return HWHAL::flash.write(flash_address, sizeof(cal), &cal);
|
||||
uint32_t write_size = sizeof(cal);
|
||||
if(write_size % Flash::PageSize != 0) {
|
||||
// round up to next page
|
||||
write_size += Flash::PageSize - write_size % Flash::PageSize;
|
||||
}
|
||||
return HWHAL::flash.write(flash_address, write_size, &cal);
|
||||
}
|
||||
|
||||
void AmplitudeCal::SetDefault() {
|
||||
@ -78,9 +83,9 @@ static AmplitudeCal::Correction InterpolateCorrection(const CorrectionTable& tab
|
||||
ret.port2 = table.port2Correction[table.usedPoints - 1];
|
||||
} else {
|
||||
// frequency is between i and i-1, interpolate
|
||||
float alpha = (freq - table.freq[i - 1]) / (table.freq[i] - table.freq[i - 1]);
|
||||
ret.port1 = table.port1Correction[i - 1] * (1 - alpha) + table.port1Correction[i] * alpha;
|
||||
ret.port2 = table.port2Correction[i - 1] * (1 - alpha) + table.port2Correction[i] * alpha;
|
||||
float alpha = (float) (freq - table.freq[i - 1]) / (table.freq[i] - table.freq[i - 1]);
|
||||
ret.port1 = table.port1Correction[i - 1] * (1.0f - alpha) + table.port1Correction[i] * alpha;
|
||||
ret.port2 = table.port2Correction[i - 1] * (1.0f - alpha) + table.port2Correction[i] * alpha;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -116,6 +121,10 @@ void AmplitudeCal::SendReceiver() {
|
||||
}
|
||||
|
||||
static void addPoint(CorrectionTable& table, const Protocol::AmplitudeCorrectionPoint& p) {
|
||||
if(p.pointNum >= AmplitudeCal::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;
|
||||
|
@ -223,7 +223,8 @@ static Protocol::GeneratorSettings DecodeGeneratorSettings(uint8_t *buf) {
|
||||
Decoder e(buf);
|
||||
e.get<uint64_t>(d.frequency);
|
||||
e.get<int16_t>(d.cdbm_level);
|
||||
e.get<uint8_t>(d.activePort);
|
||||
d.activePort = e.getBits(2);
|
||||
d.applyAmplitudeCorrection = e.getBits(1);
|
||||
return d;
|
||||
}
|
||||
static int16_t EncodeGeneratorSettings(Protocol::GeneratorSettings d, uint8_t *buf,
|
||||
@ -231,7 +232,8 @@ static int16_t EncodeGeneratorSettings(Protocol::GeneratorSettings d, uint8_t *b
|
||||
Encoder e(buf, bufSize);
|
||||
e.add<uint64_t>(d.frequency);
|
||||
e.add<int16_t>(d.cdbm_level);
|
||||
e.add<uint8_t>(d.activePort);
|
||||
e.addBits(d.activePort, 2);
|
||||
e.addBits(d.applyAmplitudeCorrection, 1);
|
||||
return e.getSize();
|
||||
}
|
||||
|
||||
@ -261,6 +263,7 @@ static Protocol::DeviceInfo DecodeDeviceInfo(uint8_t *buf) {
|
||||
e.get(d.limits_cdbm_max);
|
||||
e.get(d.limits_minRBW);
|
||||
e.get(d.limits_maxRBW);
|
||||
e.get(d.limits_maxAmplitudePoints);
|
||||
return d;
|
||||
}
|
||||
static int16_t EncodeDeviceInfo(Protocol::DeviceInfo d, uint8_t *buf,
|
||||
@ -290,6 +293,7 @@ static int16_t EncodeDeviceInfo(Protocol::DeviceInfo d, uint8_t *buf,
|
||||
e.add(d.limits_cdbm_max);
|
||||
e.add(d.limits_minRBW);
|
||||
e.add(d.limits_maxRBW);
|
||||
e.add(d.limits_maxAmplitudePoints);
|
||||
return e.getSize();
|
||||
}
|
||||
|
||||
@ -402,6 +406,7 @@ static Protocol::SpectrumAnalyzerSettings DecodeSpectrumAnalyzerSettings(uint8_t
|
||||
d.SignalID = e.getBits(1);
|
||||
d.Detector = e.getBits(3);
|
||||
d.UseDFT = e.getBits(1);
|
||||
d.applyReceiverCorrection = e.getBits(1);
|
||||
return d;
|
||||
}
|
||||
static int16_t EncodeSpectrumAnalyzerSettings(Protocol::SpectrumAnalyzerSettings d, uint8_t *buf,
|
||||
@ -415,6 +420,7 @@ static int16_t EncodeSpectrumAnalyzerSettings(Protocol::SpectrumAnalyzerSettings
|
||||
e.addBits(d.SignalID, 1);
|
||||
e.addBits(d.Detector, 3);
|
||||
e.addBits(d.UseDFT, 1);
|
||||
e.addBits(d.applyReceiverCorrection, 1);
|
||||
return e.getSize();
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
namespace Protocol {
|
||||
|
||||
static constexpr uint16_t Version = 1;
|
||||
static constexpr uint16_t Version = 2;
|
||||
|
||||
// When changing/adding/removing variables from these structs also adjust the decode/encode functions in Protocol.cpp
|
||||
|
||||
@ -37,7 +37,8 @@ using ReferenceSettings = struct _referenceSettings {
|
||||
using GeneratorSettings = struct _generatorSettings {
|
||||
uint64_t frequency;
|
||||
int16_t cdbm_level;
|
||||
uint8_t activePort;
|
||||
uint8_t activePort :2;
|
||||
uint8_t applyAmplitudeCorrection :1;
|
||||
};
|
||||
|
||||
using DeviceInfo = struct _deviceInfo {
|
||||
@ -64,6 +65,7 @@ using DeviceInfo = struct _deviceInfo {
|
||||
int16_t limits_cdbm_max;
|
||||
uint32_t limits_minRBW;
|
||||
uint32_t limits_maxRBW;
|
||||
uint8_t limits_maxAmplitudePoints;
|
||||
};
|
||||
|
||||
using ManualStatus = struct _manualstatus {
|
||||
@ -119,6 +121,7 @@ using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings {
|
||||
uint8_t SignalID :1;
|
||||
uint8_t Detector :3;
|
||||
uint8_t UseDFT :1;
|
||||
uint8_t applyReceiverCorrection :1;
|
||||
};
|
||||
|
||||
using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult {
|
||||
|
@ -30,7 +30,7 @@ void Flash::read(uint32_t address, uint16_t length, void *dest) {
|
||||
}
|
||||
|
||||
bool Flash::write(uint32_t address, uint16_t length, void *src) {
|
||||
if((address & 0xFF) != 0 || length%256 != 0) {
|
||||
if(address % PageSize != 0 || length%PageSize != 0) {
|
||||
// only writes to complete pages allowed
|
||||
LOG_ERR("Invalid write address/size: %lu/%u", address, length);
|
||||
return false;
|
||||
@ -46,7 +46,7 @@ bool Flash::write(uint32_t address, uint16_t length, void *src) {
|
||||
(uint8_t) (address >> 8) & 0xFF,
|
||||
(uint8_t) (address & 0xFF),
|
||||
};
|
||||
// issue read command
|
||||
// issue write command
|
||||
HAL_SPI_Transmit(spi, cmd, 4, 100);
|
||||
// write data
|
||||
HAL_SPI_Transmit(spi, (uint8_t*) src, 256, 1000);
|
||||
|
@ -28,11 +28,12 @@ public:
|
||||
const SPI_HandleTypeDef* const getSpi() const {
|
||||
return spi;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr uint32_t PageSize = 256;
|
||||
static constexpr uint32_t SectorSize = 4096;
|
||||
static constexpr uint32_t Block32Size = 32768;
|
||||
static constexpr uint32_t Block64Size = 65536;
|
||||
|
||||
private:
|
||||
void CS(bool high) {
|
||||
if(high) {
|
||||
CS_gpio->BSRR = CS_pin;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "Hardware.hpp"
|
||||
#include "max2871.hpp"
|
||||
#include "Si5351C.hpp"
|
||||
#include "AmplitudeCal.hpp"
|
||||
|
||||
static constexpr uint32_t BandSwitchFrequency = 25000000;
|
||||
|
||||
@ -25,6 +26,25 @@ void Generator::Setup(Protocol::GeneratorSettings g) {
|
||||
m.RefEN = 0;
|
||||
m.Samples = 131072;
|
||||
m.WindowType = (int) FPGA::Window::None;
|
||||
|
||||
switch(g.activePort) {
|
||||
case 1:
|
||||
m.AmplifierEN = 1;
|
||||
m.PortSwitch = 0;
|
||||
break;
|
||||
case 2:
|
||||
m.AmplifierEN = 1;
|
||||
m.PortSwitch = 1;
|
||||
break;
|
||||
}
|
||||
if (g.applyAmplitudeCorrection) {
|
||||
auto correction = AmplitudeCal::SourceCorrection(g.frequency);
|
||||
if (g.activePort == 1) {
|
||||
g.cdbm_level += correction.port1;
|
||||
} else {
|
||||
g.cdbm_level += correction.port2;
|
||||
}
|
||||
}
|
||||
// Select correct source
|
||||
if(g.frequency < BandSwitchFrequency) {
|
||||
m.SourceLowEN = 1;
|
||||
@ -35,6 +55,16 @@ void Generator::Setup(Protocol::GeneratorSettings g) {
|
||||
m.SourceHighLowpass = (int) FPGA::LowpassFilter::M947;
|
||||
m.SourceHighPower = (int) MAX2871::Power::n4dbm;
|
||||
m.SourceHighband = false;
|
||||
if(g.cdbm_level <= HW::LowBandMinPower) {
|
||||
// can use the low power setting
|
||||
m.SourceLowPower = (int) Si5351C::DriveStrength::mA2;
|
||||
g.cdbm_level -= HW::LowBandMinPower;
|
||||
} else {
|
||||
// needs the high power setting
|
||||
m.SourceLowPower = (int) Si5351C::DriveStrength::mA8;
|
||||
g.cdbm_level -= HW::LowBandMaxPower;
|
||||
}
|
||||
m.SourceHighPower = (int) MAX2871::Power::n4dbm;
|
||||
} else {
|
||||
m.SourceLowEN = 0;
|
||||
m.SourceLowFrequency = BandSwitchFrequency;
|
||||
@ -51,32 +81,25 @@ void Generator::Setup(Protocol::GeneratorSettings g) {
|
||||
m.SourceHighLowpass = (int) FPGA::LowpassFilter::None;
|
||||
}
|
||||
m.SourceHighband = true;
|
||||
}
|
||||
switch(g.activePort) {
|
||||
case 1:
|
||||
m.AmplifierEN = 1;
|
||||
m.PortSwitch = 0;
|
||||
break;
|
||||
case 2:
|
||||
m.AmplifierEN = 1;
|
||||
m.PortSwitch = 1;
|
||||
break;
|
||||
}
|
||||
// Set level (not very accurate)
|
||||
if(g.cdbm_level > -1000) {
|
||||
// use higher source power (approx 0dbm with no attenuation)
|
||||
m.SourceHighPower = (int) MAX2871::Power::p5dbm;
|
||||
m.SourceLowPower = (int) Si5351C::DriveStrength::mA8;
|
||||
} else {
|
||||
// use lower source power (approx -10dbm with no attenuation)
|
||||
if(g.cdbm_level <= HW::HighBandMinPower) {
|
||||
// can use the low power setting
|
||||
m.SourceHighPower = (int) MAX2871::Power::n4dbm;
|
||||
m.SourceLowPower = (int) Si5351C::DriveStrength::mA4;
|
||||
g.cdbm_level += 1000;
|
||||
g.cdbm_level -= HW::HighBandMinPower;
|
||||
} else {
|
||||
// needs the high power setting
|
||||
m.SourceHighPower = (int) MAX2871::Power::p5dbm;
|
||||
g.cdbm_level -= HW::HighBandMaxPower;
|
||||
}
|
||||
m.SourceLowPower = (int) MAX2871::Power::n4dbm;
|
||||
}
|
||||
|
||||
// calculate required attenuation
|
||||
uint16_t attval = -g.cdbm_level / 25;
|
||||
int16_t attval = -g.cdbm_level / 25;
|
||||
// TODO set some flag if attenuator limit reached?
|
||||
if(attval > 127) {
|
||||
attval = 127;
|
||||
} else if(attval < 0) {
|
||||
attval = 0;
|
||||
}
|
||||
m.attenuator = attval;
|
||||
Manual::Setup(m);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <cstdint>
|
||||
#include "Protocol.hpp"
|
||||
#include "FPGA/FPGA.hpp"
|
||||
#include "AmplitudeCal.hpp"
|
||||
|
||||
#define USE_DEBUG_PINS
|
||||
|
||||
@ -38,6 +39,12 @@ static_assert(ADCprescaler * ADCSamplerate == FPGA::Clockrate, "ADCSamplerate ca
|
||||
static constexpr uint16_t DFTphaseInc = 4096 * IF2 / ADCSamplerate;
|
||||
static_assert(DFTphaseInc * ADCSamplerate == 4096 * IF2, "DFT can not be computed for 2.IF");
|
||||
|
||||
// approximate output power at low frequencies with different source strength settings (attenuator = 0) in cdbm
|
||||
static constexpr int16_t LowBandMinPower = -1350;
|
||||
static constexpr int16_t LowBandMaxPower = -190;
|
||||
static constexpr int16_t HighBandMinPower = -1060;
|
||||
static constexpr int16_t HighBandMaxPower = -160;
|
||||
|
||||
static constexpr Protocol::DeviceInfo Info = {
|
||||
.ProtocolVersion = Protocol::Version,
|
||||
.FW_major = FW_MAJOR,
|
||||
@ -62,6 +69,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,
|
||||
};
|
||||
|
||||
enum class Mode {
|
||||
|
@ -219,8 +219,8 @@ bool SA::MeasurementDone(const FPGA::SamplingResult &result) {
|
||||
port1 = dft.P1;
|
||||
port2 = dft.P2;
|
||||
} else {
|
||||
port1 = abs(std::complex<float>(result.P1I, result.P1Q));
|
||||
port2 = abs(std::complex<float>(result.P2I, result.P2Q));
|
||||
port1 = fabs(std::complex<float>(result.P1I, result.P1Q));
|
||||
port2 = fabs(std::complex<float>(result.P2I, result.P2Q));
|
||||
}
|
||||
port1 /= sampleNum;
|
||||
port2 /= sampleNum;
|
||||
@ -315,8 +315,16 @@ void SA::Work() {
|
||||
// Send result to application
|
||||
p.type = Protocol::PacketType::SpectrumAnalyzerResult;
|
||||
// measurements are already up to date, fill remaining fields
|
||||
p.spectrumResult.pointNum = binIndex;
|
||||
p.spectrumResult.frequency = s.f_start + (s.f_stop - s.f_start) * binIndex / (s.pointNum - 1);
|
||||
// scale approximately (constant determined empirically)
|
||||
p.spectrumResult.port1 /= 253000000.0;
|
||||
p.spectrumResult.port2 /= 253000000.0;
|
||||
if (s.applyReceiverCorrection) {
|
||||
auto correction = AmplitudeCal::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);
|
||||
}
|
||||
p.spectrumResult.pointNum = binIndex;
|
||||
Communication::Send(p);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user