Preparations for math functions on traces
This commit is contained in:
parent
978842a2ff
commit
66f8b86159
@ -25,6 +25,8 @@ HEADERS += \
|
|||||||
SpectrumAnalyzer/tracewidgetsa.h \
|
SpectrumAnalyzer/tracewidgetsa.h \
|
||||||
Tools/eseries.h \
|
Tools/eseries.h \
|
||||||
Tools/impedancematchdialog.h \
|
Tools/impedancematchdialog.h \
|
||||||
|
Traces/Math/tracemath.h \
|
||||||
|
Traces/Math/tracematheditdialog.h \
|
||||||
Traces/fftcomplex.h \
|
Traces/fftcomplex.h \
|
||||||
Traces/markerwidget.h \
|
Traces/markerwidget.h \
|
||||||
Traces/trace.h \
|
Traces/trace.h \
|
||||||
@ -77,6 +79,8 @@ SOURCES += \
|
|||||||
SpectrumAnalyzer/tracewidgetsa.cpp \
|
SpectrumAnalyzer/tracewidgetsa.cpp \
|
||||||
Tools/eseries.cpp \
|
Tools/eseries.cpp \
|
||||||
Tools/impedancematchdialog.cpp \
|
Tools/impedancematchdialog.cpp \
|
||||||
|
Traces/Math/tracemath.cpp \
|
||||||
|
Traces/Math/tracematheditdialog.cpp \
|
||||||
Traces/fftcomplex.cpp \
|
Traces/fftcomplex.cpp \
|
||||||
Traces/markerwidget.cpp \
|
Traces/markerwidget.cpp \
|
||||||
Traces/trace.cpp \
|
Traces/trace.cpp \
|
||||||
@ -121,6 +125,7 @@ FORMS += \
|
|||||||
Device/manualcontroldialog.ui \
|
Device/manualcontroldialog.ui \
|
||||||
Generator/signalgenwidget.ui \
|
Generator/signalgenwidget.ui \
|
||||||
Tools/impedancematchdialog.ui \
|
Tools/impedancematchdialog.ui \
|
||||||
|
Traces/Math/tracematheditdialog.ui \
|
||||||
Traces/markerwidget.ui \
|
Traces/markerwidget.ui \
|
||||||
Traces/smithchartdialog.ui \
|
Traces/smithchartdialog.ui \
|
||||||
Traces/traceeditdialog.ui \
|
Traces/traceeditdialog.ui \
|
||||||
|
@ -599,21 +599,21 @@ std::vector<Trace *> Calibration::getErrorTermTraces()
|
|||||||
}
|
}
|
||||||
for(auto p : points) {
|
for(auto p : points) {
|
||||||
Trace::Data d;
|
Trace::Data d;
|
||||||
d.frequency = p.frequency;
|
d.x = p.frequency;
|
||||||
for(int i=0;i<12;i++) {
|
for(int i=0;i<12;i++) {
|
||||||
switch(i) {
|
switch(i) {
|
||||||
case 0: d.S = p.fe00; break;
|
case 0: d.y = p.fe00; break;
|
||||||
case 1: d.S = p.fe11; break;
|
case 1: d.y = p.fe11; break;
|
||||||
case 2: d.S = p.fe10e01; break;
|
case 2: d.y = p.fe10e01; break;
|
||||||
case 3: d.S = p.fe10e32; break;
|
case 3: d.y = p.fe10e32; break;
|
||||||
case 4: d.S = p.fe22; break;
|
case 4: d.y = p.fe22; break;
|
||||||
case 5: d.S = p.fe30; break;
|
case 5: d.y = p.fe30; break;
|
||||||
case 6: d.S = p.re33; break;
|
case 6: d.y = p.re33; break;
|
||||||
case 7: d.S = p.re11; break;
|
case 7: d.y = p.re11; break;
|
||||||
case 8: d.S = p.re23e32; break;
|
case 8: d.y = p.re23e32; break;
|
||||||
case 9: d.S = p.re23e01; break;
|
case 9: d.y = p.re23e01; break;
|
||||||
case 10: d.S = p.re22; break;
|
case 10: d.y = p.re22; break;
|
||||||
case 11: d.S = p.re03; break;
|
case 11: d.y = p.re03; break;
|
||||||
}
|
}
|
||||||
traces[i]->addData(d);
|
traces[i]->addData(d);
|
||||||
}
|
}
|
||||||
|
61
Software/PC_Application/Traces/Math/tracemath.cpp
Normal file
61
Software/PC_Application/Traces/Math/tracemath.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "tracemath.h"
|
||||||
|
|
||||||
|
TraceMath::TraceMath()
|
||||||
|
{
|
||||||
|
input = nullptr;
|
||||||
|
dataType = DataType::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceMath::Data TraceMath::getSample(unsigned int index)
|
||||||
|
{
|
||||||
|
return data.at(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int TraceMath::numSamples()
|
||||||
|
{
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceMath::removeInput()
|
||||||
|
{
|
||||||
|
if(input) {
|
||||||
|
// disconnect everything from the input
|
||||||
|
disconnect(input, nullptr, this, nullptr);
|
||||||
|
input = nullptr;
|
||||||
|
data.clear();
|
||||||
|
dataType = DataType::Invalid;
|
||||||
|
emit outputTypeChanged(dataType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceMath::assignInput(TraceMath *input)
|
||||||
|
{
|
||||||
|
Q_ASSERT(input != nullptr);
|
||||||
|
if(input != this->input) {
|
||||||
|
removeInput();
|
||||||
|
this->input = input;
|
||||||
|
inputTypeChanged(input->dataType);
|
||||||
|
// do initial calculation
|
||||||
|
inputDataChanged();
|
||||||
|
// connect to input
|
||||||
|
connect(input, &TraceMath::outputDataChanged, this, &TraceMath::inputDataChanged);
|
||||||
|
connect(input, &TraceMath::outputSampleChanged, this, &TraceMath::inputSampleChanged);
|
||||||
|
connect(input, &TraceMath::outputTypeChanged, this, &TraceMath::inputTypeChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceMath::inputTypeChanged(TraceMath::DataType type)
|
||||||
|
{
|
||||||
|
auto newType = outputType(type);
|
||||||
|
if(newType != dataType) {
|
||||||
|
dataType = newType;
|
||||||
|
data.clear();
|
||||||
|
inputDataChanged();
|
||||||
|
emit outputTypeChanged(dataType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceMath::DataType TraceMath::getDataType() const
|
||||||
|
{
|
||||||
|
return dataType;
|
||||||
|
}
|
60
Software/PC_Application/Traces/Math/tracemath.h
Normal file
60
Software/PC_Application/Traces/Math/tracemath.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef TRACEMATH_H
|
||||||
|
#define TRACEMATH_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <vector>
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
|
class TraceMath : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
TraceMath();
|
||||||
|
|
||||||
|
class Data {
|
||||||
|
public:
|
||||||
|
double x;
|
||||||
|
std::complex<double> y;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DataType {
|
||||||
|
Frequency,
|
||||||
|
Time,
|
||||||
|
Invalid,
|
||||||
|
};
|
||||||
|
|
||||||
|
Data getSample(unsigned int index);
|
||||||
|
unsigned int numSamples();
|
||||||
|
|
||||||
|
// indicate whether this function produces time or frequency domain data
|
||||||
|
virtual DataType outputType(DataType inputType) = 0;
|
||||||
|
|
||||||
|
virtual QString description() = 0;
|
||||||
|
|
||||||
|
void removeInput();
|
||||||
|
void assignInput(TraceMath *input);
|
||||||
|
|
||||||
|
DataType getDataType() const;
|
||||||
|
std::vector<Data>& rData() { return data;};
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
// a single value of the input data has changed, index determines which sample has changed
|
||||||
|
virtual void inputSampleChanged(unsigned int index){Q_UNUSED(index)};
|
||||||
|
// the complete input data has changed (e.g. cleared or all data modified by some operation)
|
||||||
|
virtual void inputDataChanged(){};
|
||||||
|
|
||||||
|
void inputTypeChanged(DataType type);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// emit this whenever a sample changed (alternatively, if all samples are about to change, emit outputDataChanged after they have changed)
|
||||||
|
void outputSampleChanged(unsigned int index);
|
||||||
|
void outputDataChanged();
|
||||||
|
// emit when the output type changed
|
||||||
|
void outputTypeChanged(DataType type);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<Data> data;
|
||||||
|
TraceMath *input;
|
||||||
|
DataType dataType;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TRACEMATH_H
|
81
Software/PC_Application/Traces/Math/tracematheditdialog.cpp
Normal file
81
Software/PC_Application/Traces/Math/tracematheditdialog.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "tracematheditdialog.h"
|
||||||
|
#include "ui_tracematheditdialog.h"
|
||||||
|
|
||||||
|
TraceMathEditDialog::TraceMathEditDialog(Trace &t, QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::TraceMathEditDialog)
|
||||||
|
{
|
||||||
|
auto model = new MathModel(t);
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->view->setModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceMathEditDialog::~TraceMathEditDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
MathModel::MathModel(Trace &t, QObject *parent)
|
||||||
|
: QAbstractTableModel(parent),
|
||||||
|
t(t)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int MathModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return t.getMath().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MathModel::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return ColIndexLast;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant MathModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if(!index.isValid()) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
auto math = t.getMath().at(index.row());
|
||||||
|
switch(index.column()) {
|
||||||
|
case ColIndexEnabled:
|
||||||
|
if(role == Qt::CheckStateRole) {
|
||||||
|
return math.enabled ? Qt::Checked : Qt::Unchecked;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ColIndexDescription:
|
||||||
|
if(role == Qt::DisplayRole) {
|
||||||
|
return math.math->description();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant MathModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if(orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||||
|
switch(section) {
|
||||||
|
case ColIndexEnabled: return "Enabled"; break;
|
||||||
|
case ColIndexDescription: return "Description"; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags MathModel::flags(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
int flags = Qt::NoItemFlags;
|
||||||
|
if(index.row() > 1) {
|
||||||
|
// the first entry is always the trace itself and not enabled
|
||||||
|
flags |= Qt::ItemIsEnabled;
|
||||||
|
}
|
||||||
|
switch(index.column()) {
|
||||||
|
case ColIndexEnabled: flags |= Qt::ItemIsUserCheckable; break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (Qt::ItemFlags) flags;
|
||||||
|
}
|
46
Software/PC_Application/Traces/Math/tracematheditdialog.h
Normal file
46
Software/PC_Application/Traces/Math/tracematheditdialog.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef TRACEMATHEDITDIALOG_H
|
||||||
|
#define TRACEMATHEDITDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
#include "Traces/trace.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class TraceMathEditDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MathModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
MathModel(Trace &t, QObject *parent = 0);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ColIndexEnabled = 0,
|
||||||
|
ColIndexDescription = 1,
|
||||||
|
ColIndexLast,
|
||||||
|
};
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Trace &t;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TraceMathEditDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TraceMathEditDialog(Trace &t, QWidget *parent = nullptr);
|
||||||
|
~TraceMathEditDialog();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::TraceMathEditDialog *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TRACEMATHEDITDIALOG_H
|
130
Software/PC_Application/Traces/Math/tracematheditdialog.ui
Normal file
130
Software/PC_Application/Traces/Math/tracematheditdialog.ui
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>TraceMathEditDialog</class>
|
||||||
|
<widget class="QDialog" name="TraceMathEditDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>411</width>
|
||||||
|
<height>302</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Math functions</string>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="view">
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<attribute name="horizontalHeaderMinimumSectionSize">
|
||||||
|
<number>20</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="horizontalHeaderDefaultSectionSize">
|
||||||
|
<number>70</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="horizontalHeaderStretchLastSection">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="bAdd">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Add</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="list-add" resource="../../icons.qrc">
|
||||||
|
<normaloff>:/icons/add.png</normaloff>:/icons/add.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="bDelete">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="list-remove" resource="../../icons.qrc">
|
||||||
|
<normaloff>:/icons/remove.png</normaloff>:/icons/remove.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>18</width>
|
||||||
|
<height>186</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../icons.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>TraceMathEditDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>216</x>
|
||||||
|
<y>280</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>216</x>
|
||||||
|
<y>150</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -14,9 +14,12 @@ Trace::Trace(QString name, QColor color, LiveParameter live)
|
|||||||
visible(true),
|
visible(true),
|
||||||
paused(false),
|
paused(false),
|
||||||
touchstone(false),
|
touchstone(false),
|
||||||
calibration(false)
|
calibration(false),
|
||||||
|
lastMath(nullptr)
|
||||||
{
|
{
|
||||||
|
MathInfo self = {.math = this, .enabled = true};
|
||||||
|
math.push_back(self);
|
||||||
|
updateLastMath(math.rbegin());
|
||||||
}
|
}
|
||||||
|
|
||||||
Trace::~Trace()
|
Trace::~Trace()
|
||||||
@ -28,21 +31,21 @@ void Trace::clear() {
|
|||||||
if(paused) {
|
if(paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_data.clear();
|
data.clear();
|
||||||
settings.valid = false;
|
settings.valid = false;
|
||||||
emit cleared(this);
|
emit cleared(this);
|
||||||
emit dataChanged();
|
emit outputDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trace::addData(const Trace::Data& d) {
|
void Trace::addData(const Trace::Data& d) {
|
||||||
// add or replace data in vector while keeping it sorted with increasing frequency
|
// add or replace data in vector while keeping it sorted with increasing frequency
|
||||||
auto lower = lower_bound(_data.begin(), _data.end(), d, [](const Data &lhs, const Data &rhs) -> bool {
|
auto lower = lower_bound(data.begin(), data.end(), d, [](const Data &lhs, const Data &rhs) -> bool {
|
||||||
return lhs.frequency < rhs.frequency;
|
return lhs.x < rhs.x;
|
||||||
});
|
});
|
||||||
if(lower == _data.end()) {
|
if(lower == data.end()) {
|
||||||
// highest frequency yet, add to vector
|
// highest frequency yet, add to vector
|
||||||
_data.push_back(d);
|
data.push_back(d);
|
||||||
} else if(lower->frequency == d.frequency) {
|
} else if(lower->x == d.x) {
|
||||||
switch(_liveType) {
|
switch(_liveType) {
|
||||||
case LivedataType::Overwrite:
|
case LivedataType::Overwrite:
|
||||||
// replace this data element
|
// replace this data element
|
||||||
@ -50,13 +53,13 @@ void Trace::addData(const Trace::Data& d) {
|
|||||||
break;
|
break;
|
||||||
case LivedataType::MaxHold:
|
case LivedataType::MaxHold:
|
||||||
// replace this data element
|
// replace this data element
|
||||||
if(abs(d.S) > abs(lower->S)) {
|
if(abs(d.y) > abs(lower->y)) {
|
||||||
*lower = d;
|
*lower = d;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LivedataType::MinHold:
|
case LivedataType::MinHold:
|
||||||
// replace this data element
|
// replace this data element
|
||||||
if(abs(d.S) < abs(lower->S)) {
|
if(abs(d.y) < abs(lower->y)) {
|
||||||
*lower = d;
|
*lower = d;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -64,11 +67,10 @@ void Trace::addData(const Trace::Data& d) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// insert at this position
|
// insert at this position
|
||||||
_data.insert(lower, d);
|
data.insert(lower, d);
|
||||||
}
|
}
|
||||||
emit dataAdded(this, d);
|
emit outputSampleChanged(lower - data.begin());
|
||||||
emit dataChanged();
|
if(lower == data.begin()) {
|
||||||
if(lower == _data.begin()) {
|
|
||||||
// received the first point, which means the last sweep just finished
|
// received the first point, which means the last sweep just finished
|
||||||
if(tdr_users) {
|
if(tdr_users) {
|
||||||
updateTimeDomainData();
|
updateTimeDomainData();
|
||||||
@ -106,8 +108,8 @@ void Trace::fillFromTouchstone(Touchstone &t, unsigned int parameter, QString fi
|
|||||||
for(unsigned int i=0;i<t.points();i++) {
|
for(unsigned int i=0;i<t.points();i++) {
|
||||||
auto tData = t.point(i);
|
auto tData = t.point(i);
|
||||||
Data d;
|
Data d;
|
||||||
d.frequency = tData.frequency;
|
d.x = tData.frequency;
|
||||||
d.S = t.point(i).S[parameter];
|
d.y = t.point(i).S[parameter];
|
||||||
addData(d);
|
addData(d);
|
||||||
}
|
}
|
||||||
// check if parameter is square (e.i. S11/S22/S33/...)
|
// check if parameter is square (e.i. S11/S22/S33/...)
|
||||||
@ -174,7 +176,7 @@ void Trace::updateTimeDomainData()
|
|||||||
auto firstStep = minFreq();
|
auto firstStep = minFreq();
|
||||||
if(firstStep == 0) {
|
if(firstStep == 0) {
|
||||||
// zero as first step would result in infinite number of points, skip and start with second
|
// zero as first step would result in infinite number of points, skip and start with second
|
||||||
firstStep = _data[1].frequency;
|
firstStep = lastMath->rData()[1].x;
|
||||||
steps--;
|
steps--;
|
||||||
}
|
}
|
||||||
if(firstStep * steps != maxFreq()) {
|
if(firstStep * steps != maxFreq()) {
|
||||||
@ -226,7 +228,34 @@ void Trace::updateTimeDomainData()
|
|||||||
// auto duration = duration_cast< milliseconds >(
|
// auto duration = duration_cast< milliseconds >(
|
||||||
// system_clock::now().time_since_epoch()
|
// system_clock::now().time_since_epoch()
|
||||||
// ).count() - starttime;
|
// ).count() - starttime;
|
||||||
// cout << "TDR: " << this << " (took " << duration << "ms)" <<endl;
|
// cout << "TDR: " << this << " (took " << duration << "ms)" <<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Trace::MathInfo>& Trace::getMath() const
|
||||||
|
{
|
||||||
|
return math;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::updateLastMath(vector<MathInfo>::reverse_iterator start)
|
||||||
|
{
|
||||||
|
TraceMath *newLast = nullptr;
|
||||||
|
for(auto it = start;it != math.rend();it++) {
|
||||||
|
if(it->enabled) {
|
||||||
|
newLast = it->math;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Q_ASSERT(newLast != nullptr);
|
||||||
|
if(newLast != lastMath) {
|
||||||
|
if(lastMath != nullptr) {
|
||||||
|
disconnect(lastMath, &TraceMath::outputDataChanged, this, nullptr);
|
||||||
|
disconnect(lastMath, &TraceMath::outputSampleChanged, this, nullptr);
|
||||||
|
}
|
||||||
|
lastMath = newLast;
|
||||||
|
// relay signals of end of math chain
|
||||||
|
connect(lastMath, &TraceMath::outputDataChanged, this, &Trace::dataChanged);
|
||||||
|
connect(lastMath, &TraceMath::outputSampleChanged, this, &Trace::dataChanged);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trace::setReflection(bool value)
|
void Trace::setReflection(bool value)
|
||||||
@ -305,6 +334,11 @@ Trace::TimedomainData Trace::getTDR(double position)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Trace::description()
|
||||||
|
{
|
||||||
|
return name() + ": measured data";
|
||||||
|
}
|
||||||
|
|
||||||
void Trace::setCalibration(bool value)
|
void Trace::setCalibration(bool value)
|
||||||
{
|
{
|
||||||
calibration = value;
|
calibration = value;
|
||||||
@ -363,16 +397,55 @@ bool Trace::isReflection()
|
|||||||
return reflection;
|
return reflection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Trace::mathEnabled()
|
||||||
|
{
|
||||||
|
return lastMath != this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Trace::hasMathOperations()
|
||||||
|
{
|
||||||
|
return math.size() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::enableMath(bool enable)
|
||||||
|
{
|
||||||
|
auto start = enable ? math.rbegin() : make_reverse_iterator(math.begin());
|
||||||
|
updateLastMath(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Trace::size()
|
||||||
|
{
|
||||||
|
return lastMath->numSamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
double Trace::minFreq()
|
||||||
|
{
|
||||||
|
if(size() > 0) {
|
||||||
|
return data.front().x;
|
||||||
|
} else {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double Trace::maxFreq()
|
||||||
|
{
|
||||||
|
if(size() > 0) {
|
||||||
|
return data.back().x;
|
||||||
|
} else {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double Trace::findExtremumFreq(bool max)
|
double Trace::findExtremumFreq(bool max)
|
||||||
{
|
{
|
||||||
double compare = max ? numeric_limits<double>::min() : numeric_limits<double>::max();
|
double compare = max ? numeric_limits<double>::min() : numeric_limits<double>::max();
|
||||||
double freq = 0.0;
|
double freq = 0.0;
|
||||||
for(auto d : _data) {
|
for(auto sample : lastMath->rData()) {
|
||||||
double amplitude = abs(d.S);
|
double amplitude = abs(sample.y);
|
||||||
if((max && (amplitude > compare)) || (!max && (amplitude < compare))) {
|
if((max && (amplitude > compare)) || (!max && (amplitude < compare))) {
|
||||||
// higher/lower extremum found
|
// higher/lower extremum found
|
||||||
compare = amplitude;
|
compare = amplitude;
|
||||||
freq = d.frequency;
|
freq = sample.x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return freq;
|
return freq;
|
||||||
@ -388,11 +461,11 @@ std::vector<double> Trace::findPeakFrequencies(unsigned int maxPeaks, double min
|
|||||||
double frequency = 0.0;
|
double frequency = 0.0;
|
||||||
double max_dbm = -200.0;
|
double max_dbm = -200.0;
|
||||||
double min_dbm = 200.0;
|
double min_dbm = 200.0;
|
||||||
for(auto d : _data) {
|
for(auto d : lastMath->rData()) {
|
||||||
double dbm = 20*log10(abs(d.S));
|
double dbm = 20*log10(abs(d.y));
|
||||||
if((dbm >= max_dbm) && (min_dbm <= dbm - minValley)) {
|
if((dbm >= max_dbm) && (min_dbm <= dbm - minValley)) {
|
||||||
// potential peak frequency
|
// potential peak frequency
|
||||||
frequency = d.frequency;
|
frequency = d.x;
|
||||||
max_dbm = dbm;
|
max_dbm = dbm;
|
||||||
}
|
}
|
||||||
if(dbm <= min_dbm) {
|
if(dbm <= min_dbm) {
|
||||||
@ -430,6 +503,11 @@ std::vector<double> Trace::findPeakFrequencies(unsigned int maxPeaks, double min
|
|||||||
return frequencies;
|
return frequencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Trace::Data Trace::sample(unsigned int index)
|
||||||
|
{
|
||||||
|
return lastMath->getSample(index);
|
||||||
|
}
|
||||||
|
|
||||||
QString Trace::getTouchstoneFilename() const
|
QString Trace::getTouchstoneFilename() const
|
||||||
{
|
{
|
||||||
return touchstoneFilename;
|
return touchstoneFilename;
|
||||||
@ -447,19 +525,19 @@ unsigned int Trace::getTouchstoneParameter() const
|
|||||||
|
|
||||||
std::complex<double> Trace::getData(double frequency)
|
std::complex<double> Trace::getData(double frequency)
|
||||||
{
|
{
|
||||||
if(_data.size() == 0 || frequency < minFreq() || frequency > maxFreq()) {
|
if(lastMath->numSamples() == 0 || frequency < minFreq() || frequency > maxFreq()) {
|
||||||
return std::numeric_limits<std::complex<double>>::quiet_NaN();
|
return std::numeric_limits<std::complex<double>>::quiet_NaN();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto i = index(frequency);
|
auto i = index(frequency);
|
||||||
if(_data.at(i).frequency == frequency) {
|
if(lastMath->getSample(i).x == frequency) {
|
||||||
return _data[i].S;
|
return lastMath->getSample(i).y;
|
||||||
} else {
|
} else {
|
||||||
// no exact frequency match, needs to interpolate
|
// no exact frequency match, needs to interpolate
|
||||||
auto high = _data[i];
|
auto high = lastMath->getSample(i);
|
||||||
auto low = _data[i-1];
|
auto low = lastMath->getSample(i - 1);
|
||||||
double alpha = (frequency - low.frequency) / (high.frequency - low.frequency);
|
double alpha = (frequency - low.x) / (high.x - low.x);
|
||||||
return low.S * (1 - alpha) + high.S * alpha;
|
return low.y * (1 - alpha) + high.y * alpha;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,10 +556,10 @@ double Trace::getNoise(double frequency)
|
|||||||
|
|
||||||
int Trace::index(double frequency)
|
int Trace::index(double frequency)
|
||||||
{
|
{
|
||||||
auto lower = lower_bound(_data.begin(), _data.end(), frequency, [](const Data &lhs, const double freq) -> bool {
|
auto lower = lower_bound(lastMath->rData().begin(), lastMath->rData().end(), frequency, [](const Data &lhs, const double freq) -> bool {
|
||||||
return lhs.frequency < freq;
|
return lhs.x < freq;
|
||||||
});
|
});
|
||||||
return lower - _data.begin();
|
return lower - lastMath->rData().begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trace::setTouchstoneParameter(int value)
|
void Trace::setTouchstoneParameter(int value)
|
||||||
|
@ -8,19 +8,16 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include "touchstone.h"
|
#include "touchstone.h"
|
||||||
#include "Device/device.h"
|
#include "Device/device.h"
|
||||||
|
#include "Math/tracemath.h"
|
||||||
|
|
||||||
class TraceMarker;
|
class TraceMarker;
|
||||||
|
|
||||||
class Trace : public QObject
|
class Trace : public TraceMath
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
||||||
class Data {
|
using Data = TraceMath::Data;
|
||||||
public:
|
|
||||||
double frequency;
|
|
||||||
std::complex<double> S;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TimedomainData {
|
class TimedomainData {
|
||||||
public:
|
public:
|
||||||
@ -67,11 +64,14 @@ public:
|
|||||||
bool isCalibration();
|
bool isCalibration();
|
||||||
bool isLive();
|
bool isLive();
|
||||||
bool isReflection();
|
bool isReflection();
|
||||||
|
bool mathEnabled(); // check if math operations are enabled
|
||||||
|
bool hasMathOperations(); // check if math operations are set up (not necessarily enabled)
|
||||||
|
void enableMath(bool enable);
|
||||||
LiveParameter liveParameter() { return _liveParam; }
|
LiveParameter liveParameter() { return _liveParam; }
|
||||||
LivedataType liveType() { return _liveType; }
|
LivedataType liveType() { return _liveType; }
|
||||||
unsigned int size() { return _data.size(); }
|
unsigned int size();
|
||||||
double minFreq() { return size() > 0 ? _data.front().frequency : 0.0; };
|
double minFreq();
|
||||||
double maxFreq() { return size() > 0 ? _data.back().frequency : 0.0; };
|
double maxFreq();
|
||||||
double findExtremumFreq(bool max);
|
double findExtremumFreq(bool max);
|
||||||
/* Searches for peaks in the trace data and returns the peak frequencies in ascending order.
|
/* Searches for peaks in the trace data and returns the peak frequencies in ascending order.
|
||||||
* Up to maxPeaks will be returned, with higher level peaks taking priority over lower level peaks.
|
* Up to maxPeaks will be returned, with higher level peaks taking priority over lower level peaks.
|
||||||
@ -79,7 +79,7 @@ public:
|
|||||||
* To detect the next peak, the signal first has to drop at least minValley below the peak level.
|
* To detect the next peak, the signal first has to drop at least minValley below the peak level.
|
||||||
*/
|
*/
|
||||||
std::vector<double> findPeakFrequencies(unsigned int maxPeaks = 100, double minLevel = -100.0, double minValley = 3.0);
|
std::vector<double> findPeakFrequencies(unsigned int maxPeaks = 100, double minLevel = -100.0, double minValley = 3.0);
|
||||||
Data sample(unsigned int index) { return _data.at(index); }
|
Data sample(unsigned int index);
|
||||||
QString getTouchstoneFilename() const;
|
QString getTouchstoneFilename() const;
|
||||||
unsigned int getTouchstoneParameter() const;
|
unsigned int getTouchstoneParameter() const;
|
||||||
std::complex<double> getData(double frequency);
|
std::complex<double> getData(double frequency);
|
||||||
@ -103,6 +103,16 @@ public:
|
|||||||
// Since the usual delay values are way smaller than the distance values this should work
|
// Since the usual delay values are way smaller than the distance values this should work
|
||||||
TimedomainData getTDR(double position);
|
TimedomainData getTDR(double position);
|
||||||
|
|
||||||
|
DataType outputType(DataType inputType) override { Q_UNUSED(inputType) return DataType::Frequency;};
|
||||||
|
QString description() override;
|
||||||
|
|
||||||
|
class MathInfo {
|
||||||
|
public:
|
||||||
|
TraceMath *math;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
const std::vector<MathInfo>& getMath() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setTouchstoneParameter(int value);
|
void setTouchstoneParameter(int value);
|
||||||
void setTouchstoneFilename(const QString &value);
|
void setTouchstoneFilename(const QString &value);
|
||||||
@ -115,7 +125,6 @@ private:
|
|||||||
signals:
|
signals:
|
||||||
void cleared(Trace *t);
|
void cleared(Trace *t);
|
||||||
void typeChanged(Trace *t);
|
void typeChanged(Trace *t);
|
||||||
void dataAdded(Trace *t, Data d);
|
|
||||||
void deleted(Trace *t);
|
void deleted(Trace *t);
|
||||||
void visibilityChanged(Trace *t);
|
void visibilityChanged(Trace *t);
|
||||||
void dataChanged();
|
void dataChanged();
|
||||||
@ -128,7 +137,7 @@ signals:
|
|||||||
private:
|
private:
|
||||||
void updateTimeDomainData();
|
void updateTimeDomainData();
|
||||||
void printTimeDomain();
|
void printTimeDomain();
|
||||||
std::vector<Data> _data;
|
// std::vector<Data> _data;
|
||||||
std::vector<TimedomainData> timeDomain;
|
std::vector<TimedomainData> timeDomain;
|
||||||
unsigned int tdr_users;
|
unsigned int tdr_users;
|
||||||
QString _name;
|
QString _name;
|
||||||
@ -150,6 +159,10 @@ private:
|
|||||||
};
|
};
|
||||||
bool valid;
|
bool valid;
|
||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
|
std::vector<MathInfo> math;
|
||||||
|
TraceMath *lastMath;
|
||||||
|
void updateLastMath(std::vector<MathInfo>::reverse_iterator start);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRACE_H
|
#endif // TRACE_H
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "ui_traceeditdialog.h"
|
#include "ui_traceeditdialog.h"
|
||||||
#include <QColorDialog>
|
#include <QColorDialog>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
#include "Math/tracematheditdialog.h"
|
||||||
|
|
||||||
TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) :
|
TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
@ -92,6 +93,10 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) :
|
|||||||
connect(ui->GSource, qOverload<int>(&QButtonGroup::buttonClicked), updateFileStatus);
|
connect(ui->GSource, qOverload<int>(&QButtonGroup::buttonClicked), updateFileStatus);
|
||||||
connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, updateFileStatus);
|
connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, updateFileStatus);
|
||||||
connect(ui->touchstoneImport, &TouchstoneImport::filenameChanged, updateFileStatus);
|
connect(ui->touchstoneImport, &TouchstoneImport::filenameChanged, updateFileStatus);
|
||||||
|
connect(ui->mathSetup, &QPushButton::clicked, [&](){
|
||||||
|
auto dialog = new TraceMathEditDialog(t);
|
||||||
|
dialog->show();
|
||||||
|
});
|
||||||
|
|
||||||
updateFileStatus();
|
updateFileStatus();
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
<widget class="ColorPickerButton" name="color">
|
<widget class="ColorPickerButton" name="color">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
@ -49,6 +51,15 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="mathSetup">
|
||||||
|
<property name="text">
|
||||||
|
<string>Math</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -72,9 +72,9 @@ void TraceExportDialog::on_buttonBox_accepted()
|
|||||||
} else {
|
} else {
|
||||||
Trace *t = qvariant_cast<Trace*>(cTraces[i][j]->itemData(cTraces[i][j]->currentIndex()));
|
Trace *t = qvariant_cast<Trace*>(cTraces[i][j]->itemData(cTraces[i][j]->currentIndex()));
|
||||||
// extract frequency (will overwrite for each trace but all traces have the same frequency points anyway)
|
// extract frequency (will overwrite for each trace but all traces have the same frequency points anyway)
|
||||||
tData.frequency = t->sample(s).frequency;
|
tData.frequency = t->sample(s).x;
|
||||||
// add S parameter from trace to touchstone
|
// add S parameter from trace to touchstone
|
||||||
tData.S.push_back(t->sample(s).S);
|
tData.S.push_back(t->sample(s).y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -695,11 +695,11 @@ void TraceMarker::update()
|
|||||||
setPosition(peakFreq);
|
setPosition(peakFreq);
|
||||||
// find the cutoff frequency
|
// find the cutoff frequency
|
||||||
auto index = parentTrace->index(peakFreq);
|
auto index = parentTrace->index(peakFreq);
|
||||||
auto peakAmplitude = 20*log10(abs(parentTrace->sample(index).S));
|
auto peakAmplitude = 20*log10(abs(parentTrace->sample(index).y));
|
||||||
auto cutoff = peakAmplitude + cutoffAmplitude;
|
auto cutoff = peakAmplitude + cutoffAmplitude;
|
||||||
int inc = type == Type::Lowpass ? 1 : -1;
|
int inc = type == Type::Lowpass ? 1 : -1;
|
||||||
while(index >= 0 && index < (int) parentTrace->size()) {
|
while(index >= 0 && index < (int) parentTrace->size()) {
|
||||||
auto amplitude = 20*log10(abs(parentTrace->sample(index).S));
|
auto amplitude = 20*log10(abs(parentTrace->sample(index).y));
|
||||||
if(amplitude <= cutoff) {
|
if(amplitude <= cutoff) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -711,7 +711,7 @@ void TraceMarker::update()
|
|||||||
index = parentTrace->size() - 1;
|
index = parentTrace->size() - 1;
|
||||||
}
|
}
|
||||||
// set position of cutoff marker
|
// set position of cutoff marker
|
||||||
helperMarkers[0]->setPosition(parentTrace->sample(index).frequency);
|
helperMarkers[0]->setPosition(parentTrace->sample(index).x);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type::Bandpass:
|
case Type::Bandpass:
|
||||||
@ -725,12 +725,12 @@ void TraceMarker::update()
|
|||||||
setPosition(peakFreq);
|
setPosition(peakFreq);
|
||||||
// find the cutoff frequencies
|
// find the cutoff frequencies
|
||||||
auto index = parentTrace->index(peakFreq);
|
auto index = parentTrace->index(peakFreq);
|
||||||
auto peakAmplitude = 20*log10(abs(parentTrace->sample(index).S));
|
auto peakAmplitude = 20*log10(abs(parentTrace->sample(index).y));
|
||||||
auto cutoff = peakAmplitude + cutoffAmplitude;
|
auto cutoff = peakAmplitude + cutoffAmplitude;
|
||||||
|
|
||||||
auto low_index = index;
|
auto low_index = index;
|
||||||
while(low_index >= 0) {
|
while(low_index >= 0) {
|
||||||
auto amplitude = 20*log10(abs(parentTrace->sample(low_index).S));
|
auto amplitude = 20*log10(abs(parentTrace->sample(low_index).y));
|
||||||
if(amplitude <= cutoff) {
|
if(amplitude <= cutoff) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -740,11 +740,11 @@ void TraceMarker::update()
|
|||||||
low_index = 0;
|
low_index = 0;
|
||||||
}
|
}
|
||||||
// set position of cutoff marker
|
// set position of cutoff marker
|
||||||
helperMarkers[0]->setPosition(parentTrace->sample(low_index).frequency);
|
helperMarkers[0]->setPosition(parentTrace->sample(low_index).x);
|
||||||
|
|
||||||
auto high_index = index;
|
auto high_index = index;
|
||||||
while(high_index < (int) parentTrace->size()) {
|
while(high_index < (int) parentTrace->size()) {
|
||||||
auto amplitude = 20*log10(abs(parentTrace->sample(high_index).S));
|
auto amplitude = 20*log10(abs(parentTrace->sample(high_index).y));
|
||||||
if(amplitude <= cutoff) {
|
if(amplitude <= cutoff) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -754,7 +754,7 @@ void TraceMarker::update()
|
|||||||
high_index = parentTrace->size() - 1;
|
high_index = parentTrace->size() - 1;
|
||||||
}
|
}
|
||||||
// set position of cutoff marker
|
// set position of cutoff marker
|
||||||
helperMarkers[1]->setPosition(parentTrace->sample(high_index).frequency);
|
helperMarkers[1]->setPosition(parentTrace->sample(high_index).x);
|
||||||
// set center marker inbetween cutoff markers
|
// set center marker inbetween cutoff markers
|
||||||
helperMarkers[2]->setPosition((helperMarkers[0]->position + helperMarkers[1]->position) / 2);
|
helperMarkers[2]->setPosition((helperMarkers[0]->position + helperMarkers[1]->position) / 2);
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ void TraceModel::toggleVisibility(unsigned int index)
|
|||||||
{
|
{
|
||||||
if (index < traces.size()) {
|
if (index < traces.size()) {
|
||||||
traces[index]->setVisible(!traces[index]->isVisible());
|
traces[index]->setVisible(!traces[index]->isVisible());
|
||||||
emit dataChanged(createIndex(index, 0), createIndex(index, 0));
|
emit dataChanged(createIndex(index, ColIndexVisible), createIndex(index, ColIndexVisible));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,11 +64,23 @@ void TraceModel::togglePause(unsigned int index)
|
|||||||
} else {
|
} else {
|
||||||
traces[index]->pause();
|
traces[index]->pause();
|
||||||
}
|
}
|
||||||
emit dataChanged(createIndex(index, 1), createIndex(index, 1));
|
emit dataChanged(createIndex(index, ColIndexPlayPause), createIndex(index, ColIndexPlayPause));
|
||||||
emit requiredExcitation(PortExcitationRequired(1), PortExcitationRequired(2));
|
emit requiredExcitation(PortExcitationRequired(1), PortExcitationRequired(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TraceModel::toggleMath(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index >= traces.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto trace = traces[index];
|
||||||
|
if(trace->hasMathOperations()) {
|
||||||
|
trace->enableMath(!trace->mathEnabled());
|
||||||
|
emit dataChanged(createIndex(index, ColIndexMath), createIndex(index, ColIndexMath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int TraceModel::rowCount(const QModelIndex &) const
|
int TraceModel::rowCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
return traces.size();
|
return traces.size();
|
||||||
@ -76,7 +88,7 @@ int TraceModel::rowCount(const QModelIndex &) const
|
|||||||
|
|
||||||
int TraceModel::columnCount(const QModelIndex &) const
|
int TraceModel::columnCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
return 3;
|
return ColIndexLast;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant TraceModel::data(const QModelIndex &index, int role) const
|
QVariant TraceModel::data(const QModelIndex &index, int role) const
|
||||||
@ -86,37 +98,47 @@ QVariant TraceModel::data(const QModelIndex &index, int role) const
|
|||||||
|
|
||||||
if ((unsigned int) index.row() >= traces.size())
|
if ((unsigned int) index.row() >= traces.size())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
if (index.column() == 0) {
|
|
||||||
|
auto trace = traces[index.row()];
|
||||||
|
switch(index.column()) {
|
||||||
|
case ColIndexVisible:
|
||||||
if (role == Qt::DecorationRole) {
|
if (role == Qt::DecorationRole) {
|
||||||
if (traces[index.row()]->isVisible()) {
|
if (trace->isVisible()) {
|
||||||
return QIcon(":/icons/visible.svg");
|
return QIcon(":/icons/visible.svg");
|
||||||
} else {
|
} else {
|
||||||
return QIcon(":/icons/invisible.svg");
|
return QIcon(":/icons/invisible.svg");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return QVariant();
|
|
||||||
}
|
}
|
||||||
} else if (index.column() == 1) {
|
break;
|
||||||
if (role == Qt::DecorationRole && !traces[index.row()]->isTouchstone()) {
|
case ColIndexPlayPause:
|
||||||
if (traces[index.row()]->isPaused()) {
|
if (role == Qt::DecorationRole && !trace->isTouchstone()) {
|
||||||
|
if (trace->isPaused()) {
|
||||||
return QIcon(":/icons/pause.svg");
|
return QIcon(":/icons/pause.svg");
|
||||||
} else {
|
} else {
|
||||||
return QIcon(":/icons/play.svg");
|
return QIcon(":/icons/play.svg");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return QVariant();
|
|
||||||
}
|
}
|
||||||
} else if (index.column() == 2) {
|
break;
|
||||||
|
case ColIndexMath:
|
||||||
|
if (role == Qt::DecorationRole && trace->hasMathOperations()) {
|
||||||
|
if(trace->mathEnabled()) {
|
||||||
|
return QIcon(":icons/math_enabled");
|
||||||
|
} else {
|
||||||
|
return QIcon(":icons/math_disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ColIndexName:
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
return traces[index.row()]->name();
|
return trace->name();
|
||||||
} else if (role == Qt::ForegroundRole) {
|
} else if (role == Qt::ForegroundRole) {
|
||||||
return traces[index.row()]->color();
|
return trace->color();
|
||||||
} else {
|
|
||||||
return QVariant();
|
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
return QVariant();
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Trace *> TraceModel::getTraces()
|
std::vector<Trace *> TraceModel::getTraces()
|
||||||
@ -156,12 +178,12 @@ void TraceModel::addVNAData(const Protocol::Datapoint &d, const Protocol::SweepS
|
|||||||
for(auto t : traces) {
|
for(auto t : traces) {
|
||||||
if (t->isLive() && !t->isPaused()) {
|
if (t->isLive() && !t->isPaused()) {
|
||||||
Trace::Data td;
|
Trace::Data td;
|
||||||
td.frequency = d.frequency;
|
td.x = d.frequency;
|
||||||
switch(t->liveParameter()) {
|
switch(t->liveParameter()) {
|
||||||
case Trace::LiveParameter::S11: td.S = complex<double>(d.real_S11, d.imag_S11); break;
|
case Trace::LiveParameter::S11: td.y = complex<double>(d.real_S11, d.imag_S11); break;
|
||||||
case Trace::LiveParameter::S12: td.S = complex<double>(d.real_S12, d.imag_S12); break;
|
case Trace::LiveParameter::S12: td.y = complex<double>(d.real_S12, d.imag_S12); break;
|
||||||
case Trace::LiveParameter::S21: td.S = complex<double>(d.real_S21, d.imag_S21); break;
|
case Trace::LiveParameter::S21: td.y = complex<double>(d.real_S21, d.imag_S21); break;
|
||||||
case Trace::LiveParameter::S22: td.S = complex<double>(d.real_S22, d.imag_S22); break;
|
case Trace::LiveParameter::S22: td.y = complex<double>(d.real_S22, d.imag_S22); break;
|
||||||
default:
|
default:
|
||||||
// not a VNA trace, skip
|
// not a VNA trace, skip
|
||||||
continue;
|
continue;
|
||||||
@ -176,10 +198,10 @@ void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Prot
|
|||||||
for(auto t : traces) {
|
for(auto t : traces) {
|
||||||
if (t->isLive() && !t->isPaused()) {
|
if (t->isLive() && !t->isPaused()) {
|
||||||
Trace::Data td;
|
Trace::Data td;
|
||||||
td.frequency = d.frequency;
|
td.x = d.frequency;
|
||||||
switch(t->liveParameter()) {
|
switch(t->liveParameter()) {
|
||||||
case Trace::LiveParameter::Port1: td.S = complex<double>(d.port1, 0); break;
|
case Trace::LiveParameter::Port1: td.y = complex<double>(d.port1, 0); break;
|
||||||
case Trace::LiveParameter::Port2: td.S = complex<double>(d.port2, 0); break;
|
case Trace::LiveParameter::Port2: td.y = complex<double>(d.port2, 0); break;
|
||||||
default:
|
default:
|
||||||
// not a SA trace, skip
|
// not a SA trace, skip
|
||||||
continue;
|
continue;
|
||||||
|
@ -13,11 +13,20 @@ public:
|
|||||||
TraceModel(QObject *parent = 0);
|
TraceModel(QObject *parent = 0);
|
||||||
~TraceModel();
|
~TraceModel();
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ColIndexVisible = 0,
|
||||||
|
ColIndexPlayPause = 1,
|
||||||
|
ColIndexMath = 2,
|
||||||
|
ColIndexName = 3,
|
||||||
|
ColIndexLast,
|
||||||
|
};
|
||||||
|
|
||||||
void addTrace(Trace *t);
|
void addTrace(Trace *t);
|
||||||
void removeTrace(unsigned int index);
|
void removeTrace(unsigned int index);
|
||||||
Trace *trace(unsigned int index);
|
Trace *trace(unsigned int index);
|
||||||
void toggleVisibility(unsigned int index);
|
void toggleVisibility(unsigned int index);
|
||||||
void togglePause(unsigned int index);
|
void togglePause(unsigned int index);
|
||||||
|
void toggleMath(unsigned int index);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
@ -41,10 +41,10 @@ void TraceSmithChart::axisSetupDialog()
|
|||||||
|
|
||||||
QPoint TraceSmithChart::dataToPixel(Trace::Data d)
|
QPoint TraceSmithChart::dataToPixel(Trace::Data d)
|
||||||
{
|
{
|
||||||
if(d.frequency < sweep_fmin || d.frequency > sweep_fmax) {
|
if(d.x < sweep_fmin || d.x > sweep_fmax) {
|
||||||
return QPoint();
|
return QPoint();
|
||||||
}
|
}
|
||||||
return transform.map(QPoint(d.S.real() * smithCoordMax, -d.S.imag() * smithCoordMax));
|
return transform.map(QPoint(d.y.real() * smithCoordMax, -d.y.imag() * smithCoordMax));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::complex<double> TraceSmithChart::pixelToData(QPoint p)
|
std::complex<double> TraceSmithChart::pixelToData(QPoint p)
|
||||||
@ -83,7 +83,7 @@ double TraceSmithChart::nearestTracePoint(Trace *t, QPoint pixel)
|
|||||||
closestIndex = i;
|
closestIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return t->sample(closestIndex).frequency;
|
return t->sample(closestIndex).x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceSmithChart::draw(QPainter &p) {
|
void TraceSmithChart::draw(QPainter &p) {
|
||||||
@ -144,17 +144,17 @@ void TraceSmithChart::draw(QPainter &p) {
|
|||||||
for(int i=1;i<nPoints;i++) {
|
for(int i=1;i<nPoints;i++) {
|
||||||
auto last = trace->sample(i-1);
|
auto last = trace->sample(i-1);
|
||||||
auto now = trace->sample(i);
|
auto now = trace->sample(i);
|
||||||
if (limitToSpan && (last.frequency < sweep_fmin || now.frequency > sweep_fmax)) {
|
if (limitToSpan && (last.x < sweep_fmin || now.x > sweep_fmax)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(isnan(now.S.real())) {
|
if(isnan(now.y.real())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// scale to size of smith diagram
|
// scale to size of smith diagram
|
||||||
last.S *= smithCoordMax;
|
last.y *= smithCoordMax;
|
||||||
now.S *= smithCoordMax;
|
now.y *= smithCoordMax;
|
||||||
// draw line
|
// draw line
|
||||||
p.drawLine(std::real(last.S), -std::imag(last.S), std::real(now.S), -std::imag(now.S));
|
p.drawLine(std::real(last.y), -std::imag(last.y), std::real(now.y), -std::imag(now.y));
|
||||||
}
|
}
|
||||||
if(trace->size() > 0) {
|
if(trace->size() > 0) {
|
||||||
// only draw markers if the trace has at least one point
|
// only draw markers if the trace has at least one point
|
||||||
|
@ -109,7 +109,7 @@ void TraceWidget::on_edit_clicked()
|
|||||||
|
|
||||||
void TraceWidget::on_view_doubleClicked(const QModelIndex &index)
|
void TraceWidget::on_view_doubleClicked(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
if(index.column() == 2) {
|
if(index.column() == TraceModel::ColIndexName) {
|
||||||
auto edit = new TraceEditDialog(*model.trace(index.row()));
|
auto edit = new TraceEditDialog(*model.trace(index.row()));
|
||||||
edit->show();
|
edit->show();
|
||||||
}
|
}
|
||||||
@ -117,9 +117,17 @@ void TraceWidget::on_view_doubleClicked(const QModelIndex &index)
|
|||||||
|
|
||||||
void TraceWidget::on_view_clicked(const QModelIndex &index)
|
void TraceWidget::on_view_clicked(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
if(index.column()==0) {
|
switch(index.column()) {
|
||||||
|
case TraceModel::ColIndexVisible:
|
||||||
model.toggleVisibility(index.row());
|
model.toggleVisibility(index.row());
|
||||||
} else if(index.column()==1) {
|
break;
|
||||||
|
case TraceModel::ColIndexPlayPause:
|
||||||
model.togglePause(index.row());
|
model.togglePause(index.row());
|
||||||
|
break;
|
||||||
|
case TraceModel::ColIndexMath:
|
||||||
|
model.toggleMath(index.row());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -654,8 +654,8 @@ QPointF TraceXYPlot::transformY(Trace *t, unsigned int sample, TraceXYPlot::YAxi
|
|||||||
case YAxisType::Phase:
|
case YAxisType::Phase:
|
||||||
case YAxisType::VSWR: {
|
case YAxisType::VSWR: {
|
||||||
auto d = t->sample(sample);
|
auto d = t->sample(sample);
|
||||||
ret.setY(transformY(d.S, type));
|
ret.setY(transformY(d.y, type));
|
||||||
ret.setX(d.frequency);
|
ret.setX(d.x);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case YAxisType::Impulse:
|
case YAxisType::Impulse:
|
||||||
@ -702,12 +702,12 @@ unsigned int TraceXYPlot::numTraceSamples(Trace *t)
|
|||||||
|
|
||||||
QPoint TraceXYPlot::dataToPixel(Trace::Data d)
|
QPoint TraceXYPlot::dataToPixel(Trace::Data d)
|
||||||
{
|
{
|
||||||
if(d.frequency < XAxis.rangeMin || d.frequency > XAxis.rangeMax) {
|
if(d.x < XAxis.rangeMin || d.x > XAxis.rangeMax) {
|
||||||
return QPoint();
|
return QPoint();
|
||||||
}
|
}
|
||||||
auto y = transformY(d.S, YAxis[0].type);
|
auto y = transformY(d.y, YAxis[0].type);
|
||||||
QPoint p;
|
QPoint p;
|
||||||
p.setX(Util::Scale<double>(d.frequency, XAxis.rangeMin, XAxis.rangeMax, plotAreaLeft, plotAreaLeft + plotAreaWidth));
|
p.setX(Util::Scale<double>(d.x, XAxis.rangeMin, XAxis.rangeMax, plotAreaLeft, plotAreaLeft + plotAreaWidth));
|
||||||
p.setY(Util::Scale<double>(y, YAxis[0].rangeMin, YAxis[0].rangeMax, plotAreaBottom, 0));
|
p.setY(Util::Scale<double>(y, YAxis[0].rangeMin, YAxis[0].rangeMax, plotAreaBottom, 0));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -842,5 +842,6 @@ QString TraceXYPlot::AxisUnit(TraceXYPlot::XAxisType type)
|
|||||||
case XAxisType::Frequency: return "Hz"; break;
|
case XAxisType::Frequency: return "Hz"; break;
|
||||||
case XAxisType::Time: return "s"; break;
|
case XAxisType::Time: return "s"; break;
|
||||||
case XAxisType::Distance: return "m"; break;
|
case XAxisType::Distance: return "m"; break;
|
||||||
|
default: return ""; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,5 +33,7 @@
|
|||||||
<file>icons/zoom-fit.png</file>
|
<file>icons/zoom-fit.png</file>
|
||||||
<file>icons/zoom-in.png</file>
|
<file>icons/zoom-in.png</file>
|
||||||
<file>icons/zoom-out.png</file>
|
<file>icons/zoom-out.png</file>
|
||||||
|
<file>icons/math_disabled.svg</file>
|
||||||
|
<file>icons/math_enabled.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
84
Software/PC_Application/icons/math_disabled.svg
Normal file
84
Software/PC_Application/icons/math_disabled.svg
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="17.410528mm"
|
||||||
|
height="9.36625mm"
|
||||||
|
viewBox="0 0 17.410529 9.3662499"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||||
|
sodipodi:docname="math_disabled.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="5.6"
|
||||||
|
inkscape:cx="43.034455"
|
||||||
|
inkscape:cy="-5.145459"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1853"
|
||||||
|
inkscape:window-height="1025"
|
||||||
|
inkscape:window-x="1147"
|
||||||
|
inkscape:window-y="867"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-77.99312,-144.11468)">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Latin Modern Math';-inkscape-font-specification:'Latin Modern Math';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="74.839287"
|
||||||
|
y="158.66071"
|
||||||
|
id="text817"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan815"
|
||||||
|
x="74.839287"
|
||||||
|
y="168.51379"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Latin Modern Math';-inkscape-font-specification:'Latin Modern Math';stroke-width:0.26458332px" /></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Latin Modern Math';-inkscape-font-specification:'Latin Modern Math';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="78.808037"
|
||||||
|
y="151.29018"
|
||||||
|
id="text825"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan823"
|
||||||
|
x="78.808037"
|
||||||
|
y="151.29018"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:FreeSerif;-inkscape-font-specification:'FreeSerif Italic';fill:#969696;fill-opacity:1;stroke-width:0.26458332px">f(x)</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#969696;stroke-width:0.271;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 78.040368,148.85072 h 17.36328"
|
||||||
|
id="path867"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.5 KiB |
79
Software/PC_Application/icons/math_enabled.svg
Normal file
79
Software/PC_Application/icons/math_enabled.svg
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16.50322mm"
|
||||||
|
height="9.36625mm"
|
||||||
|
viewBox="0 0 16.50322 9.36625"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||||
|
sodipodi:docname="math_enabled.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="11.2"
|
||||||
|
inkscape:cx="43.1742"
|
||||||
|
inkscape:cy="5.0657458"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1853"
|
||||||
|
inkscape:window-height="1025"
|
||||||
|
inkscape:window-x="1147"
|
||||||
|
inkscape:window-y="867"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-77.99312,-144.11468)">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Latin Modern Math';-inkscape-font-specification:'Latin Modern Math';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="74.839287"
|
||||||
|
y="158.66071"
|
||||||
|
id="text817"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan815"
|
||||||
|
x="74.839287"
|
||||||
|
y="168.51379"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Latin Modern Math';-inkscape-font-specification:'Latin Modern Math';stroke-width:0.26458332px" /></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:'Latin Modern Math';-inkscape-font-specification:'Latin Modern Math';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="78.808037"
|
||||||
|
y="151.29018"
|
||||||
|
id="text825"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan823"
|
||||||
|
x="78.808037"
|
||||||
|
y="151.29018"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:FreeSerif;-inkscape-font-specification:'FreeSerif Italic';stroke-width:0.26458332px">f(x)</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
Loading…
Reference in New Issue
Block a user