From 1a9a11d9aa9e2ff01f61433536c24c1243b7f84d Mon Sep 17 00:00:00 2001 From: nanovna <54525305+nanovna@users.noreply.github.com> Date: Wed, 17 Jun 2020 18:11:23 +0000 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8B=95=E3=83=99=E3=83=BC=E3=82=B9?= =?UTF-8?q?=E3=83=90=E3=83=B3=E3=83=89=E3=82=B2=E3=82=A4=E3=83=B3=E5=88=B6?= =?UTF-8?q?=E5=BE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 低周波ダイナミックレンジを増加 --- Makefile | 2 +- board_v2_0/board.hpp | 2 ++ board_v2_1/board.hpp | 2 ++ gain_cal.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++++ gain_cal.hpp | 5 +++ main2.cpp | 42 ++++++++++++++++++++----- vna_measurement.cpp | 34 +++++++++++++++++++- vna_measurement.hpp | 16 ++++++++++ 8 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 gain_cal.cpp create mode 100644 gain_cal.hpp diff --git a/Makefile b/Makefile index af748e8..139ae61 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ DEVICE = gd32f303cc_nofpu OBJS += main2.o $(BOARDNAME)/board.o vna_measurement.o xpt2046.o uihw.o common.o synthesizers.o gitversion.hpp OBJS += globals.o ui.o flash.o plot.o ili9341.o Font5x7.o Font7x13b.o numfont20x22.o fft.o command_parser.o stream_fifo.o -OBJS += sin_rom.o +OBJS += sin_rom.o gain_cal.o OBJS += $(MCULIB)/message_log.o $(MCULIB)/printf.o $(MCULIB)/fastwiring.o $(MCULIB)/si5351.o $(MCULIB)/dma_adc.o $(MCULIB)/dma_driver.o $(MCULIB)/usbserial.o CFLAGS += -O2 -g diff --git a/board_v2_0/board.hpp b/board_v2_0/board.hpp index df12a96..7f42bf1 100644 --- a/board_v2_0/board.hpp +++ b/board_v2_0/board.hpp @@ -134,6 +134,8 @@ namespace board { static constexpr int RFSW_RECV_REFL = 1; static constexpr int RFSW_RECV_PORT2 = 0; + static constexpr int RFSW_BBGAIN_MAX = 3; + // gain is an integer from 0 to 3, 0 being lowest gain static inline RFSWState RFSW_BBGAIN_GAIN(int gain) { switch(gain) { diff --git a/board_v2_1/board.hpp b/board_v2_1/board.hpp index 84abbe9..442e3b7 100644 --- a/board_v2_1/board.hpp +++ b/board_v2_1/board.hpp @@ -141,6 +141,8 @@ namespace board { static constexpr int RFSW_RECV_REFL = 0; static constexpr int RFSW_RECV_PORT2 = 1; + static constexpr int RFSW_BBGAIN_MAX = 3; + // gain is an integer from 0 to 3, 0 being lowest gain static inline RFSWState RFSW_BBGAIN_GAIN(int gain) { switch(gain) { diff --git a/gain_cal.cpp b/gain_cal.cpp new file mode 100644 index 0000000..1b0e8b6 --- /dev/null +++ b/gain_cal.cpp @@ -0,0 +1,74 @@ +#include "vna_measurement.hpp" +#include "ui.hpp" +#include "fifo.hpp" +#include "main.hpp" +#include "ili9341.hpp" +#include +#include +#include +#include +#include + +using namespace mculib; +using namespace board; + + +template +static void discardPoints(FIFO& dpFIFO, int n) { + dpFIFO.clear(); + + // skip n data points + for(int i=0; i dpFIFO; + volatile int currGain = 0; + + vnaMeasurement.emitDataPoint = [&](int freqIndex, freqHz_t freqHz, const VNAObservation& v, const complexf* ecal) { + digitalWrite(board::led, vnaMeasurement.clipFlag?1:0); + dpFIFO.enqueue(v[1]); + }; + + // override phaseChanged, set bbgain to desired value + vnaMeasurement.phaseChanged = [&](VNAMeasurementPhases ph) { + old_phaseChanged(ph); + rfsw(RFSW_BBGAIN, RFSW_BBGAIN_GAIN(currGain)); + }; + + vnaMeasurement.ecalIntervalPoints = 10000; + vnaMeasurement.nPeriods = MEASUREMENT_NPERIODS_NORMAL; + + // only > 2.5GHz can we be sure that the max gain setting will not clip when measuring the reference channel + vnaMeasurement.setSweep(2600000000, 0, 1, 1); + + for(currGain=0; currGain <= maxGain; currGain++) { + discardPoints(dpFIFO, 3); + float mag = 0; + for(int i=0; i<10; i++) { + while(!dpFIFO.readable()); + auto& dp = dpFIFO.read(); + mag += abs(dp); + dpFIFO.dequeue(); + } + gainTable[currGain] = 1.f/mag; + } + + // normalize gain table + for(currGain=1; currGain <= maxGain; currGain++) { + gainTable[currGain] /= gainTable[0]; + } + gainTable[0] = 1.f; + + // reset callbacks + vnaMeasurement.emitDataPoint = old_emitDataPoint; + vnaMeasurement.phaseChanged = old_phaseChanged; +} diff --git a/gain_cal.hpp b/gain_cal.hpp new file mode 100644 index 0000000..261724d --- /dev/null +++ b/gain_cal.hpp @@ -0,0 +1,5 @@ +#pragma once + +class VNAMeasurement; + +void performGainCal(VNAMeasurement& vnaMeasurement, float* gainTable, int maxGain); diff --git a/main2.cpp b/main2.cpp index 19f8c43..d018e61 100644 --- a/main2.cpp +++ b/main2.cpp @@ -48,6 +48,7 @@ #include "command_parser.hpp" #include "stream_fifo.hpp" #include "sin_rom.hpp" +#include "gain_cal.hpp" #ifdef HAS_SELF_TEST #include "self_test.hpp" @@ -83,6 +84,8 @@ static StreamFIFO cmdInputFIFO; static uint8_t cmdInputBuffer[128]; +static float gainTable[RFSW_BBGAIN_MAX+1]; + struct usbDataPoint { VNAObservation value; int freqIndex; @@ -106,6 +109,9 @@ static FIFO, 8> eventQueue; static volatile bool usbDataMode = false; +static freqHz_t currFreqHz = 0; // current hardware tx frequency +static int currThruGain = 0; // gain setting used for this thru measurement + // if nonzero, any ecal data in the next ecalIgnoreValues data points will be ignored. // this variable is decremented every time a data point arrives, if nonzero. static volatile int ecalIgnoreValues = 0; @@ -115,6 +121,7 @@ static int collectMeasurementState = 0; static small_function collectMeasurementCB; static void adc_process(); +static int measurementGetDefaultGain(freqHz_t freqHz); #define myassert(x) if(!(x)) do { errorBlink(3); } while(1) @@ -265,13 +272,9 @@ static void updateIFrequency(freqHz_t txFreqHz) { // set the measurement frequency including setting the tx and rx synthesizers static void setFrequency(freqHz_t freqHz) { + currFreqHz = freqHz; updateIFrequency(freqHz); - if(freqHz > 2500000000) - rfsw(RFSW_BBGAIN, RFSW_BBGAIN_GAIN(2)); - else if(freqHz > FREQUENCY_CHANGE_OVER) - rfsw(RFSW_BBGAIN, RFSW_BBGAIN_GAIN(1)); - else - rfsw(RFSW_BBGAIN, RFSW_BBGAIN_GAIN(0)); + rfsw(RFSW_BBGAIN, RFSW_BBGAIN_GAIN(measurementGetDefaultGain(currFreqHz))); // use adf4350 for f > 140MHz if(is_freq_for_adf4350(freqHz)) { @@ -708,8 +711,17 @@ static void cmdInit() { }; } +static int measurementGetDefaultGain(freqHz_t freqHz) { + if(freqHz > 2500000000) + return 2; + else if(freqHz > FREQUENCY_CHANGE_OVER) + return 1; + else + return 0; +} // callback called by VNAMeasurement to change rf switch positions. static void measurementPhaseChanged(VNAMeasurementPhases ph) { + rfsw(RFSW_BBGAIN, RFSW_BBGAIN_GAIN(measurementGetDefaultGain(currFreqHz))); switch(ph) { case VNAMeasurementPhases::REFERENCE: rfsw(RFSW_REFL, RFSW_REFL_ON); @@ -743,6 +755,8 @@ static void measurementPhaseChanged(VNAMeasurementPhases ph) { static void measurementEmitDataPoint(int freqIndex, freqHz_t freqHz, VNAObservation v, const complexf* ecal) { digitalWrite(led, vnaMeasurement.clipFlag?1:0); + v[2] *= gainTable[currThruGain] / gainTable[measurementGetDefaultGain(freqHz)]; + v[2] = applyFixedCorrectionsThru(v[2], freqHz); v[0] = applyFixedCorrections(v[0]/v[1], freqHz) * v[1]; @@ -863,6 +877,10 @@ static void measurement_setup() { vnaMeasurement.phaseChanged = [](VNAMeasurementPhases ph) { measurementPhaseChanged(ph); }; + vnaMeasurement.gainChanged = [](int gain) { + currThruGain = gain; + rfsw(RFSW_BBGAIN, RFSW_BBGAIN_GAIN(currThruGain)); + }; vnaMeasurement.emitDataPoint = [](int freqIndex, freqHz_t freqHz, const VNAObservation& v, const complexf* ecal) { measurementEmitDataPoint(freqIndex, freqHz, v, ecal); }; @@ -870,9 +888,9 @@ static void measurement_setup() { setFrequency(freqHz); }; vnaMeasurement.nPeriods = MEASUREMENT_NPERIODS_NORMAL; + vnaMeasurement.gainMin = 0; + vnaMeasurement.gainMax = RFSW_BBGAIN_MAX; vnaMeasurement.init(); - - setVNASweepToUI(); } static void adc_process() { @@ -1220,12 +1238,20 @@ int main(void) { adf4350_setup(); + performGainCal(vnaMeasurement, gainTable, RFSW_BBGAIN_MAX); + + for(int i=0; i<=RFSW_BBGAIN_MAX; i++) { + printk("BBGAIN %d: %.2f dB\n", i, log10f(gainTable[i])*20.f); + } + #ifdef HAS_SELF_TEST if(SelfTest::shouldEnterSelfTest()) { SelfTest::performSelfTest(vnaMeasurement); } #endif + setVNASweepToUI(); + redraw_frame(); bool testSG = false; diff --git a/vna_measurement.cpp b/vna_measurement.cpp index 6b094ef..22cc296 100644 --- a/vna_measurement.cpp +++ b/vna_measurement.cpp @@ -52,8 +52,10 @@ void VNAMeasurement::sweepAdvance() { if(ecalCounterOffset >= ecalIntervalPoints) ecalCounterOffset = 0; ecalCounter = ecalCounterOffset; - if(sweepCurrPoint == 0) + if(sweepCurrPoint == 0) { periodCounterSynth *= 2; + currGain = gainMax; + } } void VNAMeasurement::sampleProcessor_emitValue(int32_t valRe, int32_t valIm) { @@ -66,12 +68,30 @@ void VNAMeasurement::sampleProcessor_emitValue(int32_t valRe, int32_t valIm) { return; } if(periodCounterSynth > 0) { + // still waiting for synthesizer periodCounterSynth--; periodCounterSwitch = 0; + gainChangeOccurred = false; return; } if(periodCounterSwitch >= nWaitSwitch) { currDP += complexi{valRe, valIm}; + + if(measurementPhase == VNAMeasurementPhases::THRU) { + if(sampleProcessor.clipFlag) { + // ADC clip occurred during a measurement period + if(currGain > gainMin) { + // decrease gain and redo measurement + currGain--; + gainChanged(currGain); + periodCounterSwitch = 0; + sampleProcessor.clipFlag = false; + gainChangeOccurred = true; + return; + } + } + } + if(measurementPhase == VNAMeasurementPhases::THRU) clipFlag2 |= sampleProcessor.clipFlag; else clipFlag |= sampleProcessor.clipFlag; @@ -88,10 +108,22 @@ void VNAMeasurement::sampleProcessor_emitValue(int32_t valRe, int32_t valIm) { && periodCounterSwitch >= (nWaitSwitch + nPeriods)) { currRefl = currDP; setMeasurementPhase(VNAMeasurementPhases::THRU); + gainChanged(currGain); } else if(measurementPhase == VNAMeasurementPhases::THRU && periodCounterSwitch >= (nWaitSwitch + nPeriods)) { currThru = currDP; + float mag = abs(to_complexf(currThru)); + float fullScale = float(adcFullScale) * sampleProcessor.accumPeriod * nPeriods; + if(mag < fullScale * 0.15 && currGain < gainMax && !gainChangeOccurred) { + // signal level too low; increase gain and retry + currGain++; + gainChanged(currGain); + gainChangeOccurred = true; + periodCounterSwitch = 0; + return; + } + if(ecalCounter == 0) { #ifdef ECAL_PARTIAL setMeasurementPhase(VNAMeasurementPhases::ECALLOAD); diff --git a/vna_measurement.hpp b/vna_measurement.hpp index 755e5a1..23b7e43 100644 --- a/vna_measurement.hpp +++ b/vna_measurement.hpp @@ -35,6 +35,12 @@ class VNAMeasurement { // every ecalIntervalPoints we will measure one frequency point for ecal uint32_t ecalIntervalPoints = 8; + // AGC parameters; VNAMeasurement will detect ADC clip events and inform the + // host when baseband/rf gain needs to be changed. + int gainMin = 0, gainMax = 3; + + uint32_t adcFullScale = 30000; + // automatically reset before each measurement; indicates whether the current // S11 data point is corrupted when emitDataPoint() is called. bool clipFlag = false; @@ -55,6 +61,12 @@ class VNAMeasurement { // called to change synthesizer frequency small_function frequencyChanged; + // called to change overall system gain; gain is a user defined value + // and VNAMeasurement will only increment or decrement it if ADC + // clips occur or signal value is too low. + // the gain applies to THRU measurements only. + small_function gainChanged; + VNAMeasurement(); void init(); @@ -93,6 +105,10 @@ class VNAMeasurement { // number of frequency points since start of sweep volatile int sweepCurrPoint = 0; + uint32_t currGain = 0; + bool gainChangeOccurred = false; + + // current data point variables complexi currDP, currFwd, currRefl, currThru;