Experimental feature: only excite one port when other traces are paused

This commit is contained in:
Jan Käberich 2020-09-15 23:22:08 +02:00
parent 44124bc09e
commit de8761545d
18 changed files with 130 additions and 40 deletions

View File

@ -77,7 +77,7 @@ end Sweep;
architecture Behavioral of Sweep is
signal point_cnt : unsigned(12 downto 0);
type Point_states is (TriggerSetup, SettingUp, SettlingPort1, ExcitingPort1, SettlingPort2, ExcitingPort2, Done);
type Point_states is (TriggerSetup, SettingUp, SettlingPort1, ExcitingPort1, SettlingPort2, ExcitingPort2, NextPoint, Done);
signal state : Point_states;
signal settling_cnt : unsigned(15 downto 0);
signal settling_time : unsigned(15 downto 0);
@ -187,7 +187,7 @@ begin
if EXCITE_PORT2 = '1' then
state <= SettlingPort2;
else
state <= Done;
state <= NextPoint;
end if;
settling_cnt <= unsigned(SETTLING_TIME);
end if;
@ -206,15 +206,18 @@ begin
-- wait for sampling to finish
START_SAMPLING <= '0';
if SAMPLING_BUSY = '0' then
if point_cnt < unsigned(NPOINTS) then
point_cnt <= point_cnt + 1;
state <= TriggerSetup;
PORT_SELECT <= '1';
else
point_cnt <= (others => '0');
state <= Done;
end if;
state <= NextPoint;
end if;
when NextPoint =>
if point_cnt < unsigned(NPOINTS) then
point_cnt <= point_cnt + 1;
state <= TriggerSetup;
-- initial port depends on whether port 1 is exited
PORT_SELECT <= EXCITE_PORT1;
else
point_cnt <= (others => '0');
state <= Done;
end if;
when others =>
end case;
end if;

View File

@ -223,7 +223,7 @@
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
</transform>
<transform xil_pn:end_ts="1600104613" xil_pn:in_ck="-94812602667091528" xil_pn:name="TRANEXT_xstsynthesize_spartan6" xil_pn:prop_ck="3256065936432453276" xil_pn:start_ts="1600104595">
<transform xil_pn:end_ts="1600202513" xil_pn:in_ck="-94812602667091528" xil_pn:name="TRANEXT_xstsynthesize_spartan6" xil_pn:prop_ck="3256065936432453276" xil_pn:start_ts="1600202496">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="WarningsGenerated"/>
<status xil_pn:value="ReadyToRun"/>
@ -245,7 +245,7 @@
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
</transform>
<transform xil_pn:end_ts="1600116413" xil_pn:in_ck="490340488621696080" xil_pn:name="TRANEXT_ngdbuild_FPGA" xil_pn:prop_ck="4604875190571501774" xil_pn:start_ts="1600116406">
<transform xil_pn:end_ts="1600202519" xil_pn:in_ck="490340488621696080" xil_pn:name="TRANEXT_ngdbuild_FPGA" xil_pn:prop_ck="4604875190571501774" xil_pn:start_ts="1600202513">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_ngo"/>
@ -254,12 +254,10 @@
<outfile xil_pn:name="top.ngd"/>
<outfile xil_pn:name="top_ngdbuild.xrpt"/>
</transform>
<transform xil_pn:end_ts="1600116446" xil_pn:in_ck="8512332261572065657" xil_pn:name="TRANEXT_map_spartan6" xil_pn:prop_ck="1448924893915930207" xil_pn:start_ts="1600116413">
<transform xil_pn:end_ts="1600202564" xil_pn:in_ck="8512332261572065657" xil_pn:name="TRANEXT_map_spartan6" xil_pn:prop_ck="1448924893915930207" xil_pn:start_ts="1600202519">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="WarningsGenerated"/>
<status xil_pn:value="ReadyToRun"/>
<status xil_pn:value="OutOfDateForOutputs"/>
<status xil_pn:value="OutputChanged"/>
<outfile xil_pn:name="_xmsgs/map.xmsgs"/>
<outfile xil_pn:name="top.pcf"/>
<outfile xil_pn:name="top_map.map"/>
@ -270,7 +268,7 @@
<outfile xil_pn:name="top_summary.xml"/>
<outfile xil_pn:name="top_usage.xml"/>
</transform>
<transform xil_pn:end_ts="1600116473" xil_pn:in_ck="1117507038335044978" xil_pn:name="TRANEXT_par_spartan6" xil_pn:prop_ck="93661965788626211" xil_pn:start_ts="1600116446">
<transform xil_pn:end_ts="1600202589" xil_pn:in_ck="1117507038335044978" xil_pn:name="TRANEXT_par_spartan6" xil_pn:prop_ck="93661965788626211" xil_pn:start_ts="1600202564">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_xmsgs/par.xmsgs"/>
@ -284,7 +282,7 @@
<outfile xil_pn:name="top_pad.txt"/>
<outfile xil_pn:name="top_par.xrpt"/>
</transform>
<transform xil_pn:end_ts="1600116486" xil_pn:in_ck="154288912438" xil_pn:name="TRANEXT_bitFile_spartan6" xil_pn:prop_ck="3274353840855015246" xil_pn:start_ts="1600116473">
<transform xil_pn:end_ts="1600202602" xil_pn:in_ck="154288912438" xil_pn:name="TRANEXT_bitFile_spartan6" xil_pn:prop_ck="3274353840855015246" xil_pn:start_ts="1600202589">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="WarningsGenerated"/>
<status xil_pn:value="ReadyToRun"/>
@ -330,7 +328,7 @@
<status xil_pn:value="OutputChanged"/>
<status xil_pn:value="OutputRemoved"/>
</transform>
<transform xil_pn:end_ts="1600116473" xil_pn:in_ck="8512326635937592693" xil_pn:name="TRAN_postRouteTrce" xil_pn:prop_ck="445577401284416184" xil_pn:start_ts="1600116466">
<transform xil_pn:end_ts="1600202589" xil_pn:in_ck="8512326635937592693" xil_pn:name="TRAN_postRouteTrce" xil_pn:prop_ck="445577401284416184" xil_pn:start_ts="1600202583">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_xmsgs/trce.xmsgs"/>

Binary file not shown.

View File

@ -279,7 +279,12 @@ Calibration::InterpolationType Calibration::getInterpolation(Protocol::SweepSett
return InterpolationType::Extrapolate;
}
// Either exact or interpolation, check individual frequencies
uint32_t f_step = (settings.f_stop - settings.f_start) / (settings.points - 1);
uint32_t f_step;
if(settings.points > 1) {
f_step = (settings.f_stop - settings.f_start) / (settings.points - 1);
} else {
f_step = settings.f_stop - settings.f_start;
}
for(uint64_t f = settings.f_start; f <= settings.f_stop; f += f_step) {
if(find_if(points.begin(), points.end(), [&f](const Point& p){
return abs(f - p.frequency) < 100;
@ -549,8 +554,8 @@ istream& operator >>(istream &in, Calibration &c)
} else {
throw runtime_error("Incomplete calibration data, the requested \"" + line + "\"-Calibration could not be performed.");
}
break;
}
break;
}
}
return in;

View File

@ -51,6 +51,7 @@ void TraceModel::togglePause(unsigned int index)
traces[index]->pause();
}
emit dataChanged(createIndex(index, 1), createIndex(index, 1));
emit requiredExcitation(PortExcitationRequired(1), PortExcitationRequired(2));
}
}
@ -109,6 +110,23 @@ std::vector<Trace *> TraceModel::getTraces()
return traces;
}
bool TraceModel::PortExcitationRequired(int port)
{
for(auto t : traces) {
if(t->isLive() && !t->isPaused()) {
// this trace needs measurements from VNA, check if port has to be excited for its measurement
auto param = t->liveParameter();
if(port == 1 && (param == Trace::LiveParameter::S11 || param == Trace::LiveParameter::S21)) {
return true;
} else if(port == 2 && (param == Trace::LiveParameter::S22 || param == Trace::LiveParameter::S12)) {
return true;
}
}
}
// checked all traces, none requires this port to be excited
return false;
}
void TraceModel::clearVNAData()
{
for(auto t : traces) {

View File

@ -23,9 +23,12 @@ public:
QVariant data(const QModelIndex &index, int role) const override;
std::vector<Trace*> getTraces();
bool PortExcitationRequired(int port);
signals:
void traceAdded(Trace *t);
void traceRemoved(Trace *t);
void requiredExcitation(bool excitePort1, bool excitePort2);
public slots:
void clearVNAData();

View File

@ -43,13 +43,9 @@
VNA::VNA(AppWindow *window)
: Mode(window, "Vector Network Analyzer"),
pref(window->getPreferenceRef()),
central(new TileWidget(traceModel))
{
QCoreApplication::setOrganizationName("VNA");
QCoreApplication::setApplicationName("Application");
pref.load();
averages = 1;
calValid = false;
calMeasuring = false;
@ -79,6 +75,8 @@ VNA::VNA(AppWindow *window)
auto tracebode2 = new TraceBodePlot(traceModel);
tracebode2->enableTrace(tS21, true);
connect(&traceModel, &TraceModel::requiredExcitation, this, &VNA::ExcitationRequired);
central->splitVertically();
central->Child1()->splitHorizontally();
central->Child2()->splitHorizontally();
@ -422,6 +420,13 @@ VNA::VNA(AppWindow *window)
qRegisterMetaType<Protocol::Datapoint>("Datapoint");
// Set initial sweep settings
if(pref.Acquisition.alwaysExciteBothPorts) {
settings.excitePort1 = 1;
settings.excitePort2 = 1;
} else {
settings.excitePort1 = traceModel.PortExcitationRequired(1);
settings.excitePort2 = traceModel.PortExcitationRequired(2);
}
if(pref.Startup.RememberSweepSettings) {
LoadSweepSettings();
} else {
@ -654,6 +659,22 @@ void VNA::SetAveraging(unsigned int averages)
SettingsChanged();
}
void VNA::ExcitationRequired(bool port1, bool port2)
{
qDebug() << pref.Acquisition.alwaysExciteBothPorts;
if(pref.Acquisition.alwaysExciteBothPorts) {
port1 = true;
port2 = true;
}
// check if settings actually changed
if(settings.excitePort1 != port1
|| settings.excitePort2 != port2) {
settings.excitePort1 = port1;
settings.excitePort2 = port2;
SettingsChanged();
}
}
void VNA::DisableCalibration(bool force)
{
if(calValid || force) {

View File

@ -32,6 +32,7 @@ private slots:
void SetPoints(unsigned int points);
void SetIFBandwidth(double bandwidth);
void SetAveraging(unsigned int averages);
void ExcitationRequired(bool port1, bool port2);
// Calibration
void DisableCalibration(bool force = false);
void ApplyCalibration(Calibration::Type type);
@ -47,9 +48,8 @@ private:
void LoadSweepSettings();
void StoreSweepSettings();
Preferences pref;
Preferences &pref;
QActionGroup *deviceActionGroup;
Protocol::SweepSettings settings;
unsigned int averages;
TraceModel traceModel;

View File

@ -105,7 +105,9 @@ AppWindow::AppWindow(QWidget *parent)
}
});
connect(ui->actionPreferences, &QAction::triggered, [=](){
qDebug() << pref.Acquisition.alwaysExciteBothPorts;
pref.edit();
qDebug() << pref.Acquisition.alwaysExciteBothPorts;
});
setWindowTitle("VNA");
@ -248,6 +250,11 @@ void AppWindow::CreateToolbars()
addToolBar(tb_reference);
}
Preferences &AppWindow::getPreferenceRef()
{
return pref;
}
int AppWindow::UpdateDeviceList()
{
deviceActionGroup->setExclusive(true);

View File

@ -34,6 +34,8 @@ public:
QStackedWidget *getCentral() const;
Device *getDevice() const;
Preferences &getPreferenceRef();
protected:
void closeEvent(QCloseEvent *event) override;
private slots:

View File

@ -66,6 +66,7 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
p->Startup.DefaultSweep.bandwidth = ui->StartupSweepBandwidth->value();
p->Startup.DefaultSweep.points = ui->StartupSweepPoints->value();
p->Startup.DefaultSweep.excitation = ui->StartupSweepLevel->value();
p->Acquisition.alwaysExciteBothPorts = ui->AcquisitionAlwaysExciteBoth->isChecked();
accept();
});
@ -90,6 +91,8 @@ void PreferencesDialog::setInitialGUIState()
ui->StartupSweepBandwidth->setValueQuiet(p->Startup.DefaultSweep.bandwidth);
ui->StartupSweepPoints->setValue(p->Startup.DefaultSweep.points);
ui->StartupSweepLevel->setValue(p->Startup.DefaultSweep.excitation);
ui->AcquisitionAlwaysExciteBoth->setChecked(p->Acquisition.alwaysExciteBothPorts);
}
void Preferences::load()

View File

@ -46,13 +46,16 @@ public:
double excitation;
} DefaultSweep;
} Startup;
struct {
bool alwaysExciteBothPorts;
} Acquisition;
private:
using SettingDescription = struct {
QPointerVariant var;
QString name;
QVariant def;
};
const std::array<SettingDescription, 7> descr = {{
const std::array<SettingDescription, 8> descr = {{
{&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true},
{&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false},
{&Startup.DefaultSweep.start, "Startup.DefaultSweep.start", 1000000.0},
@ -60,6 +63,7 @@ private:
{&Startup.DefaultSweep.points, "Startup.DefaultSweep.points", 501},
{&Startup.DefaultSweep.bandwidth, "Startup.DefaultSweep.bandwidth", 1000.0},
{&Startup.DefaultSweep.excitation, "Startup.DefaultSweep.excitation", -10.00},
{&Acquisition.alwaysExciteBothPorts, "Acquisition.alwaysExciteBothPorts", false},
}};
};

View File

@ -232,7 +232,7 @@
<widget class="QWidget" name="Acquisition">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QCheckBox" name="checkBox">
<widget class="QCheckBox" name="AcquisitionAlwaysExciteBoth">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If only S11/S21 or S22/S12 are enabled, faster sweeps are possible by only exciting one port. Checking this option forces the device to always excite both ports even when the measurements from one port will not be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>

View File

@ -178,8 +178,7 @@ void App_Start() {
case Protocol::PacketType::SweepSettings:
LOG_INFO("New settings received");
settings = packet.settings;
VNA::ConfigureSweep(settings, VNACallback);
sweepActive = true;
sweepActive = VNA::ConfigureSweep(settings, VNACallback);
lastNewPoint = HAL_GetTick();
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
break;

View File

@ -174,6 +174,8 @@ static Protocol::SweepSettings DecodeSweepSettings(uint8_t *buf) {
e.get<uint16_t>(d.points);
e.get<uint32_t>(d.if_bandwidth);
e.get<int16_t>(d.cdbm_excitation);
d.excitePort1 = e.getBits(1);
d.excitePort2 = e.getBits(1);
return d;
}
static int16_t EncodeSweepSettings(Protocol::SweepSettings d, uint8_t *buf,
@ -184,6 +186,8 @@ static int16_t EncodeSweepSettings(Protocol::SweepSettings d, uint8_t *buf,
e.add<uint16_t>(d.points);
e.add<uint32_t>(d.if_bandwidth);
e.add<int16_t>(d.cdbm_excitation);
e.addBits(d.excitePort1, 1);
e.addBits(d.excitePort2, 1);
return e.getSize();
}

View File

@ -21,6 +21,8 @@ using SweepSettings = struct _sweepSettings {
uint16_t points;
uint32_t if_bandwidth;
int16_t cdbm_excitation; // in 1/100 dbm
uint8_t excitePort1:1;
uint8_t excitePort2:1;
};
using ReferenceSettings = struct _referenceSettings {

View File

@ -82,9 +82,9 @@ static void ReadComplete(FPGA::SamplingResult result) {
auto ref = std::complex<float>(result.RefI, result.RefQ);
auto port1 = port1_raw / ref;
auto port2 = port2_raw / ref;
data.pointNum = pointCnt;
data.frequency = settings.f_start + (settings.f_stop - settings.f_start) * pointCnt / (settings.points - 1);
if(excitingPort1) {
data.pointNum = pointCnt;
data.frequency = settings.f_start + (settings.f_stop - settings.f_start) * pointCnt / (settings.points - 1);
data.real_S11 = port1.real();
data.imag_S11 = port1.imag();
data.real_S21 = port2.real();
@ -94,6 +94,19 @@ static void ReadComplete(FPGA::SamplingResult result) {
data.imag_S12 = port1.imag();
data.real_S22 = port2.real();
data.imag_S22 = port2.imag();
}
// figure out whether this sweep point is complete and which port gets excited next
bool pointComplete = false;
if(settings.excitePort1 == 1 && settings.excitePort2 == 1) {
// point is complete when port 2 was active
pointComplete = !excitingPort1;
// next measurement will be from other port
excitingPort1 = !excitingPort1;
} else {
// only one port active, point is complete after every measurement
pointComplete = true;
}
if(pointComplete) {
if (sweepCallback) {
sweepCallback(data);
}
@ -102,10 +115,8 @@ static void ReadComplete(FPGA::SamplingResult result) {
// reached end of sweep, start again
pointCnt = 0;
IFTableIndexCnt = 0;
// FPGA::StartSweep();
}
}
excitingPort1 = !excitingPort1;
} else {
// Manual control mode, simply pass on raw result
if(statusCallback) {
@ -218,6 +229,11 @@ bool VNA::ConfigureSweep(Protocol::SweepSettings s, SweepCallback cb) {
// was used in manual mode last, do full initialization before starting sweep
VNA::Init();
}
if(s.excitePort1 == 0 && s.excitePort2 == 0) {
// both ports disabled, set to idle
SetIdle();
return false;
}
sweepCallback = cb;
settings = s;
// Abort possible active sweep first
@ -316,7 +332,7 @@ bool VNA::ConfigureSweep(Protocol::SweepSettings s, SweepCallback cb) {
}
LO1.SetFrequency(freq + used_IF);
FPGA::WriteSweepConfig(i, lowband, Source.GetRegisters(),
LO1.GetRegisters(), attenuator, freq, FPGA::SettlingTime::us540,
LO1.GetRegisters(), attenuator, freq, FPGA::SettlingTime::us20,
FPGA::Samples::SPPRegister, needs_halt);
last_lowband = lowband;
}
@ -332,10 +348,11 @@ bool VNA::ConfigureSweep(Protocol::SweepSettings s, SweepCallback cb) {
FPGA::Enable(FPGA::Periphery::SourceRF);
FPGA::Enable(FPGA::Periphery::LO1Chip);
FPGA::Enable(FPGA::Periphery::LO1RF);
FPGA::Enable(FPGA::Periphery::ExcitePort1);
FPGA::Enable(FPGA::Periphery::ExcitePort2);
FPGA::Enable(FPGA::Periphery::ExcitePort1, s.excitePort1);
FPGA::Enable(FPGA::Periphery::ExcitePort2, s.excitePort2);
pointCnt = 0;
excitingPort1 = true;
// starting port depends on whether port 1 is active in sweep
excitingPort1 = s.excitePort1;
IFTableIndexCnt = 0;
// Start the sweep
FPGA::StartSweep();
@ -461,7 +478,10 @@ bool VNA::Ref::applySettings(Protocol::ReferenceSettings s) {
LOG_INFO("External reference output set to %luHz", extOutFreq);
}
}
bool useExternal = s.UseExternalRef || (s.AutomaticSwitch && Ref::available());
bool useExternal = s.UseExternalRef;
if (s.AutomaticSwitch) {
useExternal = Ref::available();
}
if(useExternal != extRefInUse) {
// switch between internal and external reference
extRefInUse = useExternal;

View File

@ -10,6 +10,7 @@ using SweepCallback = void(*)(Protocol::Datapoint);
using StatusCallback = void(*)(FPGA::SamplingResult);
bool Init();
// returns whether the sweep is actually started
bool ConfigureSweep(Protocol::SweepSettings s, SweepCallback cb);
bool ConfigureManual(Protocol::ManualControl m, StatusCallback cb);
bool ConfigureGenerator(Protocol::GeneratorSettings g);