+ Reply to Thread
Results 1 to 13 of 13
  1. #1
    Join Date
    Sep 2009
    Posts
    774

    Default AD8302 Phase and magnitude to complex impedance

    Hi,
    I didn't know where to put topic, so if it is wrong place...

    I have project where I need to match 868MHz antenna to 50R. So I build sort of antenna analyzer.
    I used this bridge
    https://www.ebay.co.uk/itm/RF-SWR-Re...frcectupt=true
    with
    https://www.analog.com/media/en/tech...ets/ad8302.pdf

    Is there way to get complex impedance from phase and magnitude I get from AD8302.

  2. #2
    Join Date
    Apr 2014
    Location
    Northeast
    Posts
    308

    Default Re: AD8302 Phase and magnitude to complex impedance

    What ideas do you have so far? There are some of us that have no experience with what you are using, but may contribute snippets of wisdom if we have a good starting point. What PIC processor did you have in mind? What Special Function Registers do you think would help you? A better explanation of what you REALLY are trying to accomplish (yes, use the stuff at the links, of course).
    I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.

  3. #3
    Join Date
    Sep 2009
    Posts
    774

    Default Re: AD8302 Phase and magnitude to complex impedance

    Pic and registers etc doesn't mater at all... I do not have problem with code, I have problem with math..
    Complex impedance is just way of representing magnitude and phase. It looks like Z=R+jX, where R is real part, X is imaginary part.
    Here is example of using resistive bridge
    https://circuitsalad.com/2015/12/26/...stive-divider/
    From that 3 voltage you can get complex Z.
    But from AD8302 i have only angle, and magnitude. I can not use reistive bridge on 868MHz, because parasitic would make too much of error.
    My goal is to build matching network for antenna, so it will radiate most of signal(minimize reflection).
    EDIT:
    Problem with mismatched antenna
    https://en.wikipedia.org/wiki/SWR_meter

  4. #4
    Join Date
    Sep 2009
    Posts
    774

    Default Re: AD8302 Phase and magnitude to complex impedance

    I want to create something like this:


    From last video I'm missing Im and denominator.
    Im/Denominator is 0.316, but can't get that value, or formula.

  5. #5
    Join Date
    May 2013
    Location
    australia
    Posts
    1,716

    Default Re: AD8302 Phase and magnitude to complex impedance

    i notice he doubts some of his calculations , the project looks unfinished .
    pity no code or methods provided.

    you can't just trim the antenna the usual way with a swr meter / delta match /tuned snub or make aerial too long and trim length to swr it in
    This is more entertaining than Free to Air TV

  6. #6
    Join Date
    Sep 2009
    Posts
    774

    Default Re: AD8302 Phase and magnitude to complex impedance

    I need to design custom shape of antenna. Antenna is in plastic box, partially potted, low height etc. In short antenna is in place where no antenna should be.
    I already used noise source+bridge+RTL SDR to menage to get minimum SWR. But comparing to simple 1/4 wave antenna, results are not that good. It is OK, but I want to make it little more better, by adding L match network(or to modify antenna to include little more inductance if that is what is needed).

    Just found some python script that should contain all calc need:
    Code:
    /*
     *   (c) Yury Kuchura
     *   kuchura@gmail.com
     *
     *   This code can be used on terms of WTFPL Version 2 (http://www.wtfpl.net/).
     */
    
    #include <string.h>
    #include <math.h>
    #include <limits.h>
    #include <complex.h>
    #include "stm32f10x.h"
    #include "dsp.h"
    #include "dbgprint.h"
    #include "gen.h"
    #include "osl.h"
    #include "config.h"
    
    #define Rmeas 10.0f
    #define RmeasAdd 33.0f
    #define Rload 51.0f
    #define Rtotal (RmeasAdd + Rmeas + Rload)
    #define DSP_Z0 50.0f
    
    #define NSAMPLES 512
    
    #define DSP_SAMPLECYCLES ADC_SampleTime_1Cycles5
    
    extern void Sleep(uint32_t);
    
    int g_favor_precision = 0; //Nonzero value increases number of retries in case of noise detection during calibration
    
    //Considering ADC clock 9 MHz, 1.5 ADC clocks for sampling, and 12.5 clocks for
    //conversion, we obtain sampling frequency for our DSP algorithms:
    static const float fSample = (9000.f / 14.f) * 1000.f;
    static const float targetFreq = 10045.f; //Falls exactly in the middle of bin
    
    //Goertzel algorithm constants
    #define BIN 8 //(int)roundf(((0.5f + NSAMPLES) * targetFreq) / fSample);
    #define GOERTZEL_W ((2. * M_PI / NSAMPLES) * BIN)
    static float cosine = 0.;
    static float sine = 0.;
    static float coeff = 0.;
    
    //Magnitude conversion coefficient (to millivolts):
    //2.34 is amplitude loss because of the Blackman window
    //3.3 is power supply voltage (==Aref)
    //4096 is ADC resolution (12 bits)
    static const float MCF = (2.34 * 3.3 * 2.0 * 1000.) / (NSAMPLES * 4096);
    
    //Sample buffer (filled with DMA)
    static volatile uint32_t adcBuf[NSAMPLES];
    static float windowfunc[NSAMPLES];
    
    //Measurement results
    static float complex magphase_i = 0.1f+0.fi; //Measured magnitude and phase for I channel
    static float complex magphase_q = 0.1f+0.fi; //Measured magnitude and phase for Q channel
    static float magmv_i = 1.;                   //Measured magnitude in millivolts for I channel
    static float magmv_q = 1.;                   //Measured magnitude in millivolts for I channel
    static float magdif = 1.f;                   //Measured magnitude ratio
    static float magdifdb = 0.f;                 //Measured magnitude ratio in dB
    static float phdif = 0.f;                    //Measured phase difference in radians
    static float phdifdeg = 0.f;                 //Measured phase difference in degrees
    static DSP_RX mZ = DSP_Z0 + 0.0fi;
    
    static float DSP_CalcR(void);
    static float DSP_CalcX(void);
    
    static float complex Goertzel(int channel)
    {
        int i;
        float q0, q1, q2;
        float re, im, magnitude, phase;
    
        //initials
        q0 = 0.0;
        q1 = 0.0;
        q2 = 0.0;
        for (i = 0; i < NSAMPLES; i++)
        {
            float sample = (channel ? (float)(adcBuf[i] >> 16) : (float)(adcBuf[i] & 0xFFFF));
            //Remove DC component as much as possible
            sample -= 2048.0;
            //Apply windowing to reduce reaction of this bin on OOB frequencies
            sample *= windowfunc[i];
    
            q0 = coeff * q1 - q2 + sample;
            q2 = q1;
            q1 = q0;
        }
    
        //Run one extra step with sample = 0 to obtain exactly the same result as in DFT
        //for particular bin (see here: http://en.wikipedia.org/wiki/Goertzel_algorithm)
        q0 = coeff * q1 - q2; //considering sample is 0
        q2 = q1;
        q1 = q0;
    
        //Calculate results
        re = q1 - q2 * cosine;
        im = q2 * sine;
        magnitude = sqrtf(powf(re, 2) + powf(im, 2));
        phase = atan2f(im, re);
        return magnitude + phase * I;
    }
    
    
    void ConfigDMA(void)
    {
        DMA_InitTypeDef   DMA_InitStructure;
        //DMA1 for ADC1
        DMA_DeInit(DMA1_Channel1);
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adcBuf;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize = NSAMPLES;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);
        DMA_Cmd(DMA1_Channel1, ENABLE);
    }
    
    //Prepare ADC for sampling two channels
    void DSP_Init(void)
    {
        GPIO_InitTypeDef  GPIO_InitStructure;
        ADC_InitTypeDef   ADC_InitStructure;
        int i;
    
        // PCLK2 is the APB2 clock
        // ADCCLK = PCLK2/6 = 72/6 = 12MHz
        RCC_ADCCLKConfig(RCC_PCLK2_Div8); //1.5 MHz
    
        //Enable DMA clocks
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
        // Enable GPIOC, ADC, TIM1 and AFIO clocks
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO |
                               RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 |
                               RCC_APB2Periph_TIM1, ENABLE);
    
        GPIO_StructInit(&GPIO_InitStructure);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
        GPIO_Init(GPIOC, &GPIO_InitStructure);
    
        ConfigDMA();
    
        //Enable ADC1 on PC0, ADC3 on PC1
        //(ADC Channel10, ADC Channel11)
        ADC_DeInit(ADC1);
        ADC_DeInit(ADC2);
    
        ADC_StructInit(&ADC_InitStructure);
        ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;
        ADC_InitStructure.ADC_ScanConvMode = ENABLE;
        ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
        ADC_InitStructure.ADC_NbrOfChannel = 1;
    
        ADC_Init(ADC1, &ADC_InitStructure);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, DSP_SAMPLECYCLES);
        ADC_DMACmd(ADC1, ENABLE);
    
        ADC_Init(ADC2, &ADC_InitStructure);
        ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, DSP_SAMPLECYCLES);
        ADC_ExternalTrigConvCmd(ADC2, ENABLE);
    
        Sleep(10);
    
        ADC_Cmd(ADC1, ENABLE);
        ADC_ResetCalibration(ADC1);
        while(ADC_GetResetCalibrationStatus(ADC1));
        ADC_StartCalibration(ADC1);
        while(ADC_GetCalibrationStatus(ADC1));
    
        ADC_Cmd(ADC2, ENABLE);
        ADC_ResetCalibration(ADC2);
        while(ADC_GetResetCalibrationStatus(ADC2));
        ADC_StartCalibration(ADC2);
        while(ADC_GetCalibrationStatus(ADC2));
    
        //Generate window function to minimize bin sensitivity to out-of-band noise
        for (i = 0; i < NSAMPLES; i++)
        {
            //Hamming window, 43 dB OOB rejection
            //windowfunc[i] = 0.54f - 0.46f * cosf((2 * M_PI * i) / NSAMPLES);
    
            //Blackman window, >66 dB OOB rejection
            windowfunc[i] = 0.426591f - .496561f * cosf( (2 * M_PI * i) / NSAMPLES) + .076848f * cosf((4 * M_PI * i) / NSAMPLES);
        }
    
        //Goertzel constants
        cosine = cosf(GOERTZEL_W);
        sine = sinf(GOERTZEL_W);
        coeff = 2. * cosine;
    
        DBGPRINT("DSP initialized\n");
    }
    
    #define MAXNMEAS 50
    static float mag_i_buf[MAXNMEAS];
    static float mag_q_buf[MAXNMEAS];
    static float phdif_buf[MAXNMEAS];
    
    //Filter array of floats with nm entries to remove outliers, and return mean
    //of the remaining entries that fall into 1 sigma interval.
    //In normal distribution, which is our case, 68% of entries fall into single
    //standard deviation range.
    static float DSP_FilterArray(float* arr, int nm, int doRetries)
    {
        int i;
        int counter;
        float result;
        float low;
        float high;
        float deviation;
        float mean;
    
        if (nm <= 0)
            return 0.0f;
        else if (nm > MAXNMEAS)
            nm = MAXNMEAS;
    
        //Calculate mean
        mean = 0.0f;
        for (i = 0; i < nm; i++)
            mean += arr[i];
        mean /= nm;
    
        if (nm < 5)
        {//Simple case. Just return mean.
            return mean;
        }
        //============================
        // Filtering outliers
        //============================
    
        //Calculate standard deviation (sigma)
        deviation = 0.0f;
        for (i = 0; i < nm; i++)
        {
            float t = arr[i] - mean;
            t  = t * t;
            deviation += t;
        }
        deviation = sqrtf(deviation / nm);
    
        //Calculate mean of entries within part of standard deviation range
    #ifdef FAVOR_PRECISION
        if (g_favor_precision)
        {
            low = mean - deviation * 0.6;
            high = mean + deviation * 0.6;
        }
        else
    #endif
        {
            low = mean - deviation * 0.75;
            high = mean + deviation * 0.75;
        }
        counter = 0;
        result = 0.0f;
        for (i = 0; i < nm; i++)
        {
            if (arr[i] >= low && arr[i] <= high)
            {
                result += arr[i];
                counter++;
            }
        }
        if (doRetries && counter < nm/2)
        {
            return 0.0;
        }
        if (counter == 0)
        {//Oops! Nothing falls into the range, so let's simply return mean
            return mean;
        }
        result /= counter;
        return result;
    }
    
    //Set frequency, run measurement sampling and calculate phase, magnitude ratio
    //and Z from sampled data, applying hardware error correction and OSL correction
    //if requested. Note that clock source remains turned on after the measurement!
    void DSP_Measure(uint32_t freqHz, int applyErrCorrection, int applyOSL, int nMeasurements)
    {
        #define NMEAS nMeasurements
        float mag_i = 0.0f;
        float mag_q = 0.0f;
        float pdif = 0.0f;
        float complex res_i, res_q;
        int i;
        #ifdef FAVOR_PRECISION
        int retries = g_favor_precision ? 150 : 10;
        #else
        int retries = 3;
        #endif
        OSL_ERRCORR errCorr;
    
        assert_param(nMeasurements > 0);
        if (nMeasurements > MAXNMEAS)
            nMeasurements = MAXNMEAS;
    
        if (freqHz != 0)
        {
            GEN_SetMeasurementFreq(freqHz);
        }
        freqHz = GEN_GetLastFreq();
    
        DBGPRINT("DSP: measuring at %d Hz\n", (int)freqHz);
        if (applyErrCorrection)
        {
            errCorr = OSL_GetADCCorrection(freqHz);
        }
    REMEASURE:
        for (i = 0; i < NMEAS; i++)
        {
            ConfigDMA();
            ADC_SoftwareStartConvCmd(ADC1, ENABLE);
            while(!DMA_GetFlagStatus(DMA1_FLAG_TC1)); //Blocks until measurement is finished
            DMA_ClearFlag(DMA1_FLAG_TC1);
            ADC_SoftwareStartConvCmd(ADC1, DISABLE);
    
            //Apply Goertzel agorithm to sampled data
            res_i = Goertzel(0);
            res_q = Goertzel(1);
    
            mag_i_buf[i] = crealf(res_i);
            mag_q_buf[i] = crealf(res_q);
            pdif = cimagf(res_i) - cimagf(res_q);
            //Correct phase difference quadrant
            pdif = fmodf(pdif + M_PI, 2 * M_PI) - M_PI;
    
            if (pdif < -M_PI)
                pdif += 2 * M_PI;
            else if (pdif > M_PI)
                pdif -= 2 * M_PI;
    #ifdef F_LO_DIVIDED_BY_TWO
            //Correct quadrature phase shift
            if (freqHz > BAND_FMAX) //Working on 3rd harmonic of LO
                pdif -= M_PI_2;
            else
                pdif += M_PI_2;
    #endif
            phdif_buf[i] = pdif;
        }
    
        //Now perform filtering to remove outliers with sigma > 1.0
        mag_i = DSP_FilterArray(mag_i_buf, NMEAS, retries);
        mag_q = DSP_FilterArray(mag_q_buf, NMEAS, retries);
        phdif = DSP_FilterArray(phdif_buf, NMEAS, retries);
        if (mag_i == 0.0f || mag_q == 0.0f || phdif == 0.0f)
        {//need to measure again : too much noise detected
            retries--;
            goto REMEASURE;
        }
    
        if (applyErrCorrection)
        {
            mag_q *= errCorr.mag0;
            phdif  -= errCorr.phase0;
        }
    
        //Calculate derived results
        magmv_i = mag_i * MCF;
        magmv_q = mag_q * MCF;
    
        magdif = mag_q / mag_i;
        phdifdeg = (phdif * 180.) / M_PI;
        magdifdb = 20 * log10f(magdif);
        mZ = DSP_CalcR() + DSP_CalcX() * I;
        DBGPRINT("For f=%u before OSL Z=%.1f%+.1fj\n", (unsigned int)freqHz, crealf(mZ), cimagf(mZ));
    
        //Apply OSL correction if needed
        if (applyOSL)
        {
            mZ = OSL_CorrectZ(freqHz, mZ);
        }
        DBGPRINT("For f=%u measured Z=%.1f%+.1fj\n", (unsigned int)freqHz, crealf(mZ), cimagf(mZ));
    }
    
    //Return last measured Z
    DSP_RX DSP_MeasuredZ(void)
    {
        return mZ;
    }
    
    //Return last measured phase shift
    float DSP_MeasuredPhase(void)
    {
        return phdif;
    }
    
    float DSP_MeasuredPhaseDeg(void)
    {
        return phdifdeg;
    }
    
    float DSP_MeasuredDiffdB(void)
    {
        return magdifdb;
    }
    
    float DSP_MeasuredDiff(void)
    {
        return magdif;
    }
    
    float complex DSP_MeasuredMagPhaseI(void)
    {
        return magphase_i;
    }
    
    float complex DSP_MeasuredMagPhaseQ(void)
    {
        return magphase_q;
    }
    
    float DSP_MeasuredMagImv(void)
    {
        return magmv_i;
    }
    
    float DSP_MeasuredMagQmv(void)
    {
        return magmv_q;
    }
    
    static float DSP_CalcR(void)
    {
        float RR = (cosf(phdif) * Rtotal * magdif) - (Rmeas + RmeasAdd);
        if(RR < 0.0f) //Sometimes this happens due to measurement inaccuracy
            RR = 0.0f;
        return RR;
    }
    
    static float DSP_CalcX(void)
    {
        return sinf(phdif) * Rtotal * magdif;
    }
    
    
    //Calculate VSWR from Z
    float DSP_CalcVSWR(DSP_RX Z)
    {
        float X2 = powf(cimagf(Z), 2);
        float R = crealf(Z);
        if(R < 0.0)
        {
            R = 0.0;
        }
        float ro = sqrtf((powf((R - DSP_Z0), 2) + X2) / (powf((R + DSP_Z0), 2) + X2));
        if(ro > .999)
        {
            ro = 0.999;
        }
        X2 = (1.0 + ro) / (1.0 - ro);
        DBGPRINT("VSWR %.2f\n", X2);
        return X2;
    }
    
    uint32_t DSP_GetIF(void)
    {
        return (uint32_t)targetFreq;
    }
    I think that this is what I needed:
    Code:
    static float DSP_CalcR(void)
    {
        float RR = (cosf(phdif) * Rtotal * magdif) - (Rmeas + RmeasAdd);
      
    
    static float DSP_CalcX(void)
    {
        return sinf(phdif) * Rtotal * magdif;
    But Rtotal and RmeasAdd confuses me...

    Also found this:

    Code:
    '
    '
    'PA3CKR
    '
    'ipana020 20050803 swrtopixval lookup table for mfj-like display
    'ipana021 20050805 improved frequency sweep accuracy
    'ipana022 20050807 corrected sweep pixel layout, included zer-span capability (signal-generator!)
    'ipana023 20050808 code clean-up
    '
    '
    '
    '
    ' iw0bhb  18 Jun 2006
    '
    ' "V 0.41" Mod. Display 240x64 , Mod. Load info , Mod. Characters,
    ' Add fix offset on Z0 (see Zimpl), Center freq. axes
    '
    '
    '
    '
    '
    '*****> Config <****************************************************************
    
    $regfile = "m32def.dat"
    $crystal = 8000000
    
    'config graphlcd
    Config Graphlcd = 240 * 64 , Dataport = Portb , Controlport = Portc , Ce = 5 , Cd = 6 , Wr = 3 , Rd = 4 , Reset = 7 , Fs = 2 , Mode = 8
    
    'config in-outputs
    
    Config Portd.6 = Output
    Fqud Alias Portd.6
    
    Config Portd.5 = Output
    Wclk Alias Portd.5
    
    Config Portd.4 = Output
    Ddsdata Alias Portd.4
    
    Config Portd.7 = Output
    Adccs Alias Portd.7
    
    Config Portc.0 = Output
    Adcclk Alias Portc.0
    
    Config Portc.1 = Input
    Adcphasein Alias Pinc.1
    
    Adcphaseinpullup Alias Portc.1
    
    Config Portc.2 = Input
    Adcmagnin Alias Pinc.2
    
    Adcmagninpullup Alias Portc.2
    
    
    
    
    'Config Portd.3 = Input                                      'not used port
    'Modeswitch Alias Pind.3
    
    
    
    
    Config Portd.1 = Output                                     'out beep keyboard
    Beeper Alias Portd.1
    
    Config Porta = Input
    Buttons Alias Pina
    
    
    
    '180 degrees divided by 1023 adc steps
    Const Adcphres = 0.176
    
    '60 dB divided by 1023 adc steps
    Const Adcmagres = 0.05865
    
    'from radians to degrees
    Const R2d = 57.296
    
    'Standard characteristic impedance
    Const Z0 = 50.0
    
    'Number of frequencies to scan
    Const Frequencies = 115
    
    'mid-frequency number (frequencies/2+1)
    Const Midfreq = 58
    
    'Vertical number of pixels in graph
    Const Vertpix = 49
    
    'vertical pixel erase range
    Const Vertpixerase = Vertpix - 1
    
    'vertical and horizontal offset to place pixel in graph window
    Const Vertpixoffset = 7
    Const Horpixoffset = 11
    
    'keyboard debounce time
    Const Debouncetime = 50
    
    'keypressed beeper duration
    Const Beepduration = 100
    
    'keypressed beeper frequency
    Const Beepfrequency = 500
    
    'bad choice beeper duration
    Const Bcbeepduration = 100
    
    'bad choice beeper frequency
    Const Bcbeepfrequency = 750
    
    'DDS frequency low limit (kHz)
    Const Ddsfreqlowlimit = 1000
    
    'DDS frequency high limit (kHz)
    Const Ddsfreqhighlimit = 65000                              'max 65.500MHz (see aslong)
    
    
    
    
    '-----> Default <---------------------------------------------------------------
    
    'Maximum index of Fsteps data table (see end of program)
    Const Fstepsnum = 4                                         ' 4=6 value step max freq step 10Mhz
    
    'Maximum index of Fspans data table
    Const Fspansnum = 10                                        ' 10= 11 span value
    
    'Default Fsteps data table index
    Const Fstepsdefault = 2                                     ' 2=1MHz step default new value
    
    'Default Fspans data table index
    Const Fspansdefault = 6                                     ' 6=2MHz span default new value
    
    
    '-------------------------------------------------------------------------------
    
    
    
    'buttons
    Dim Buttonvalue As Byte
    Dim Buttonpushed As Byte
    
    'beeper
    Dim Beepcount As Word
    Dim Beeplength As Word
    Dim Beeptone As Byte
    
    
    
    'dds tuningword
    Dim Ddstuningword As Long
    
    'fourth byte holding dds config
    Dim Twbyte4 As Byte
    
    'variables to hold constants to add to dds tuning word
    'it would be nice to have unsigned longs in bascom...
    Dim Mhz10 As Long
    Dim Mhz1 As Long
    Dim Khz100 As Long
    Dim Khz10 As Long
    Dim Khz1 As Long
    
    'frequency variables
    Dim Freqcentre As Long
    Dim Freqspan As Long
    Dim Freqstep As Long
    Dim Freqstart As Long
    Dim Freqaxisintv As Long
    Dim Freqintv As Single
    Dim Freqddstmp As Single
    Dim Freqtmp As Long
    Dim Freqtmp1 As Long
    Dim Freqstsptmp As Long
    Dim Freqstepdisp As String * 6
    Dim Freqstepindex As Byte
    Dim Freqspanindex As Byte
    Dim Freqstspindex As Byte
    
    'additional variables for the calculation of dds tuning word
    Dim Ddsfreq As Long
    Dim Ddstmp As Long
    Dim Ddsnum As Word
    Dim Ddsaddnum As Word
    Dim Ddsdiv As Word
    
    'adc variables
    Dim Adcphase As Word
    Dim Adcmagnitude As Word
    Dim Adcbit As Word
    Dim Adccount As Byte
    
    'swr etc. variables
    Dim Returnloss As Single
    Dim Angle As Single
    Dim Mag As Single
    Dim F As Single
    Dim G As Single
    Dim Rr As Single
    Dim Ss As Single
    Dim Ximp As Single
    Dim Rimp As Single
    
    Dim Zimpl As Single                                         'Offset Z0
    
    Dim Zimp As Single
    Dim Swr As Single
    Dim Rrsqrtmp As Single
    Dim Sssqrtmp As Single
    Dim Tmpsa As Single
    Dim Tmpsb As Single
    Dim Tmpsc As Single
    
    'lcd character placement variables
    Dim Hpos As Byte
    Dim Vpos As Byte
    Dim Charhor As Byte
    Dim Charline As Byte
    'Dim Testcnt As Byte
    'Dim Testint As Integer
    Dim Pixcount As Byte
    Dim Pixhor As Byte
    Dim Pixval As Byte
    Dim Pointcount As Byte
    
    'lcd character string variables
    Dim Shortstr As String * 10
    Dim Valstr As String * 30                                   ' Define LCD max characters
    Dim Charseries As String * 46
    
    'plot line variables
    Dim Line1pix(frequencies) As Byte
    Dim Pixlen As Integer
    Dim Pixlenfirst As Integer
    Dim Pix As Byte
    Dim Pixbetween As Byte
    Dim Pixtodo As Byte
    Dim Pixdir As Bit
    Dim Freqloopcnt As Byte
    Dim Xaxispixrange As Word
    Dim Yaxispixrange As Word
    Dim Xaxisrange As Word
    Dim Yaxisrange As Word
    Dim Arrowon As Bit
    Dim Swrtmp As Single
    Dim Pixperswr As Single
    Dim Swrtopixvalarray(vertpix) As Single
    Dim Zerospan As Bit
    Dim Numfreqtoplot As Word
    
    
    'Subroutine declarations
    
    
    'sub to plot very small font
    Declare Sub Cplcd(byval Charhor As Byte , Byval Charline As Byte , Valstr As String)
    
    'sub to plot axis
    Declare Sub Plaxis
    
    'sub to plot axis labels
    Declare Sub Plaxislabels
    
    'sub to plot welcome screen
    Declare Sub Welcome
    
    'sub to send dds tuning word to dds
    Declare Sub Sendddstuningword(ddstuningword As Long)
    
    'sub to calculate ddstuningword from frequency
    Declare Sub Calcddstuningword(ddsfreq As Long)
    
    'sub to reset dds
    Declare Sub Resetdds
    
    'sub to read tlc1549 adc's
    Declare Sub Readadc
    
    'sub to calculate swr, return-loss, phase and z
    Declare Sub Docalcall
    
    'sub to calc swr only
    Declare Sub Docalcswr
    
    'sub to convert swr etc. to graph pixelvalues
    Declare Sub Calctopix
    
    'sub to update frequency settings
    Declare Sub Updfreq
    
    'sub to read buttons
    Declare Sub Readbuttons
    
    'sub to sound a beeper
    Declare Sub Soundbeeper(byval Beeplength As Word , Byval Beeptone As Byte)
    
    
    
    
    
    '*****< Program Starts >********************************************************
    
    'charseries is not in a data statement because lookdown does not work for
    'strings
    'first char is "?", used for unknown chars
    
    Charseries = "?/^v .-@%&0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    
    'provide pull-up for adc data outputs
    Set Adcphaseinpullup
    Set Adcmagninpullup
    
    'reset dds control lines
    Reset Wclk
    Reset Ddsdata
    Reset Fqud
    
    'disable adc's, adc clock inactive
    Set Adccs
    Set Adcclk
    Buttonpushed = 255
    
    'frequency digit values to add to dds tuning word
    Mhz10 = 238609294
    Mhz1 = 23860929
    Khz100 = 2386093
    Khz10 = 238609
    Khz1 = 23861
    
    'read swrtopixvalarray from datablock
    Restore Swrtopixval
    For Pixval = 1 To Vertpix
      Read Swrtopixvalarray(pixval)
    Next Pixval
    
    'reset dds several times to ensure correct startup
    For Freqloopcnt = 1 To 10
      Call Resetdds
    Next Freqloopcnt
    
    Call Soundbeeper(100 , 1)
    
    Call Welcome
    
    Call Soundbeeper(100 , 1)
    
    Porta = &B11111111                                          ' Enable portA pull-ups
    Waitms 250
    
    'Erase line1pix
    For Pix = 1 To Frequencies
      Line1pix(pix) = 8
    Next Pix
    
    Freqcentre = 14300                                          ' Set default frequencies (kHz)
    Freqspanindex = Fspansdefault
    Reset Zerospan
    Freqspan = Lookup(freqspanindex , Fspans)
    Freqstepindex = Fstepsdefault
    Freqstep = Lookup(freqstepindex , Fsteps)
    Freqstepdisp = Lookupstr(fstepsdefault , Fstepsdisp)
    
    Do
    
    Startsweep:
    
    Call Plaxis
    Call Plaxislabels
    
    Freqtmp = Freqspan / 2
    Freqstart = Freqcentre - Freqtmp
    
    'intv: frequencies-1!
    Freqintv = Freqspan / 114
    If Zerospan = 0 Then
      Ddsfreq = Freqstart
    Else
      Ddsfreq = Freqcentre
    End If
    Freqddstmp = Ddsfreq
    
    Numfreqtoplot = Frequencies
    
    'Do a sweep accross frequencies
    For Freqloopcnt = 1 To Numfreqtoplot
      Call Readbuttons
      If Buttonpushed <> 255 Then
        Call Soundbeeper(100 , 1)
        Call Updfreq
        Buttonpushed = 255
        Goto Startsweep
      End If
      Call Calcddstuningword(ddsfreq)
      Call Sendddstuningword(ddstuningword)
      Call Readadc
      If Freqloopcnt = Midfreq Then
    
        'at centre frequency calculate all parameters
    
        Call Docalcall
        Valstr = "                  "
        Call Cplcd(150 , 30 , Valstr)
    
        Valstr = "SWR"
        Call Cplcd(180 , 30 , Valstr)
    
    
        'check swr limit only for f-centre
        If Swr > 9.99 Then
          Shortstr = " HI "
        Else
          Shortstr = Fusing(swr , "#.##")
        End If
    
        Call Cplcd(150 , 30 , Shortstr)
    
    
        If Returnloss < 0 Then
          Shortstr = Fusing(returnloss , "##.#")
          If Returnloss < -10 Then Shortstr = "" + Shortstr
        Else
          Shortstr = "---.-"
        End If
        Call Cplcd(135 , 40 , Shortstr)
    
        Valstr = "DB  RETURN LOSS"
        Call Cplcd(160 , 40 , Valstr)                           ' Write DB  RETURN LOSS col 165 row 40
    
        Shortstr = Fusing(zimp , "####.#")
        If Zimp < 1000 Then Shortstr = " " + Shortstr
        If Zimp < 100 Then Shortstr = " " + Shortstr
    
        Call Cplcd(140 , 50 , Shortstr)                         ' Write Z0 string
    
        Valstr = "IMPEDANCE"
        Call Cplcd(180 , 50 , Valstr)                           ' Write IMPEDANCE
    
    
        Valstr = "ANTENNA ANALYSER"
        Call Cplcd(145 , 0 , Valstr)
    
        Valstr = "MHZ"
        Call Cplcd(130 , 59 , Valstr)
    
    
      Else
        'at other points only swr is calculated to speed up the sweep
        Call Docalcswr
      End If
    
      Pixcount = Freqloopcnt - 1
      Pixcount = Pixcount + Horpixoffset
    
      'Erase line1pix
      For Pix = 1 To Vertpixerase
        Pixval = Pix + Vertpixoffset
        Pset Pixcount , Pixval , 0
      Next Pixlen
    
      'determine index of swr in swrtopixval datablock, this is the pixel
      'value to use in the graph
      For Pixval = 1 To Vertpix
        If Swr > Swrtopixvalarray(pixval) Then Goto Exitarrayindex
      Next Pixval
    Exitarrayindex:
    
      Pixval = Pixval + Vertpixoffset
      Line1pix(freqloopcnt) = Pixval
      'plot new point of line1
      Pset Pixcount , Line1pix(freqloopcnt) , 1
      If Freqloopcnt > 1 Then
        'Plot Line From Point n-1 To Point n
        Pixlenfirst = Freqloopcnt - 1
        Pixlen = Line1pix(pixlenfirst) - Line1pix(freqloopcnt)
        If Pixlen > 0 Then
          Set Pixdir
        Else
          Reset Pixdir
        End If
        Pixlen = Abs(pixlen)
        If Pixlen > 0 Then
          Pixlenfirst = Pixlen / 2
          Pixlen = Pixlen - Pixlenfirst
          Pixtodo = Pixlenfirst
          Pixlenfirst = Freqloopcnt - 1
          Pixbetween = Line1pix(pixlenfirst)
          Pixcount = Pixcount - 1
          If Pixtodo > 0 Then
            For Pix = 1 To Pixtodo
              If Pixdir = 1 Then
                Pixbetween = Pixbetween - 1
              Else
                Pixbetween = Pixbetween + 1
              End If
              Pset Pixcount , Pixbetween , 1
            Next Pix
          End If
          Pixcount = Pixcount + 1
          Pixtodo = Pixlen
          If Pixtodo > 0 Then
            For Pix = 1 To Pixtodo
              If Pixdir = 1 Then
                Pixbetween = Pixbetween - 1
              Else
                Pixbetween = Pixbetween + 1
              End If
              Pset Pixcount , Pixbetween , 1
            Next Pix
          End If
        End If
      End If
      'next frequency
      If Zerospan = 0 Then
        Freqddstmp = Freqddstmp + Freqintv
        Ddsfreq = Round(freqddstmp)
      End If
    Next Freqloopcnt
    
    Loop
    
    End
    
    
    
    
    
    
    '#####> Subroutines Start Follow <####################################################
    
    Sub Cplcd(byval Charhor As Byte , Byval Charline As Byte , Valstr As String)
      'Place character bits from character set in data block on lcd
      'charhor is horizontal and charline is vertical pixel position
      Local Charcnt As Byte
      Local Slen As Byte
      Local Charinstr As String * 1
      Local Pixcolumn As Byte
      Local Rowindata As Byte
      Local Pixbit As Byte
      Local Bitval As Byte
      Local Charvert As Byte
      Slen = Len(valstr)
      'do for all characters in string
      For Charcnt = 1 To Slen
       'get char from string
        Charinstr = Mid(valstr , Charcnt , 1)
        Pixcolumn = Instr(charseries , Charinstr)
        'if char not in charseries, use ?
        If Pixcolumn = 0 Then Pixcolumn = 1
        Pixcolumn = Pixcolumn - 1
        Rowindata = Pixcolumn * 5
        'for all five pixel columns in character
        For Hpos = 0 To 4
          Pixcolumn = Lookup(rowindata , Chrset)
          Bitval = 16
          'for all five pixel rows in character
          For Vpos = 0 To 4
            Pixbit = Pixcolumn And Bitval
            Charvert = Charline + Vpos
            'place the bit!
            Pset Charhor , Charvert , Pixbit
            Bitval = Bitval / 2
          Next Vpos
          Charhor = Charhor + 1
          Rowindata = Rowindata + 1
        Next Hpos
      Next Charcnt
    End Sub
    
    
    '*****> costruzione rettangolo <************************************************
    
    Sub Plaxis
    
      Line(10 , 2) -(126 , 2) , 255                             ' xy up left corner
      Line(126 , 2) -(126 , 57) , 255
      Line(126 , 57) -(10 , 57) , 255
      Line(10 , 57) -(10 , 2) , 255
    
    'vert. center freq. axes
      Pset 68 , 11 , 1                                          ' up
      Pset 68 , 21 , 1
      Pset 68 , 31 , 1
      Pset 68 , 41 , 1
      Pset 68 , 51 , 1                                          ' dn
    
      'ticks at left y-axis SWR
      Pset 9 , 22 , 1
      Pset 9 , 32 , 1
      Pset 9 , 37 , 1
      Pset 9 , 42 , 1
      Pset 9 , 51 , 1
      Pset 9 , 56 , 1
    
      'ticks at bottom x-axis
      Pset 11 , 58 , 1
      Pset 40 , 58 , 1
      Pset 68 , 58 , 1
      Pset 97 , 58 , 1
      Pset 125 , 58 , 1
    
      'ticks at right y-axis SWR
      Pset 127 , 8 , 1
      Pset 127 , 22 , 1
      Pset 127 , 32 , 1
      Pset 127 , 37 , 1
      Pset 127 , 42 , 1
      Pset 127 , 51 , 1
      Pset 127 , 56 , 1
    
      'ticks at top x-axis
      Pset 11 , 1 , 1
      Pset 40 , 1 , 1
      Pset 68 , 1 , 1
      Pset 97 , 1 , 1
      Pset 125 , 1 , 1
    
    End Sub
    
    
    '******************************************************************************
    
    
    'Show freq dn axes
    
    Sub Plaxislabels
      Freqtmp = Freqspan / 2
      Freqstart = Freqcentre - Freqtmp
      Freqaxisintv = Freqspan / 20
    
      If Zerospan = 0 Then
        Freqstart = Freqstart / 10
        Valstr = Str(freqstart)
        Shortstr = Format(valstr , "00.00")
      Else
        Shortstr = "....."
      End If
      Call Cplcd(10 , 59 , Shortstr)                            ' Write span min freq
    
      If Zerospan = 0 Then
        Freqstart = Freqstart + Freqaxisintv
      Else
        Freqstart = Freqcentre / 10
      End If
      Valstr = Str(freqstart)
      Shortstr = Format(valstr , "00.00")
      Call Cplcd(56 , 59 , Shortstr)                            ' Write central freq
    
      If Zerospan = 0 Then
        Freqstart = Freqstart + Freqaxisintv
        Valstr = Str(freqstart)
        Shortstr = Format(valstr , "00.00")
      Else
        Shortstr = "....."
      End If
      Call Cplcd(102 , 59 , Shortstr)                           ' Write span max freq
    
    
      'Vertical axes sx swr value
    
      Valstr = "&"
      Call Cplcd(3 , 35 , Valstr)
      'narrow 5 (1.5)
      Valstr = "%"
      Call Cplcd(3 , 40 , Valstr)
      'narrow 2 (1.2)
      Valstr = "@"
      Call Cplcd(3 , 49 , Valstr)
      Valstr = "HI"
      Call Cplcd(0 , 6 , Valstr)
      Valstr = "3"
      Call Cplcd(0 , 17 , Valstr)
      Valstr = "2"
      Call Cplcd(0 , 27 , Valstr)
      Valstr = "1"
      Call Cplcd(0 , 53 , Valstr)
    
    
    
      'display frequency step
      Valstr = Freqstepdisp
      Call Cplcd(140 , 20 , Valstr)
    
    '  Valstr = "HZ"                                             ' show "FREQ STEP"
    '  Call Cplcd(160 , 20 , Valstr)
    
      Valstr = "FREQ STEP"                                      ' show "FREQ STEP"
      Call Cplcd(180 , 20 , Valstr)
    
    End Sub
    
    
    '*****> Banner <****************************************************************
    
    Sub Welcome                                                 ' Banner
      Cls
      Wait 1
      Cursor Off
    
      Valstr = "1 TO 65MHZ ANTENNA ANALYSER"
      Call Cplcd(50 , 10 , Valstr)
    
      Valstr = "IW3HEV / PA3CKR / IW0BHB"
      Call Cplcd(50 , 30 , Valstr)
    
      Valstr = "V 0.41"
      Call Cplcd(50 , 50 , Valstr)
    
      Wait 5
      Cls
    End Sub
    
    
    '******************************************************************************
    
    Sub Sendddstuningword(ddstuningword As Long)
      'shift out ddstuningword bits, lsb first on clock high, send to dds
      Shiftout , Ddsdata , Wclk , Ddstuningword , 3
      'shift out fifth byte, lsb first on clock high, only refclk multiplier bit is set
      Twbyte4 = &B00000001
      Shiftout , Ddsdata , Wclk , Twbyte4 , 3
      'toggle fqud to latch data in dds
      Set Fqud
      nop
      Reset Fqud
    End Sub
    
    
    '******************************************************************************
    
    Sub Calcddstuningword(ddsfreq As Long)
      'Scan ddsfreq digits and add digit values to ddstuningword
      Ddstmp = Ddsfreq
      Ddsdiv = 10000
      Ddstuningword = 0
      'calculate dds tuning word
    
      'number of mhz10
      Ddsnum = Ddstmp / Ddsdiv
      For Ddsaddnum = 1 To Ddsnum
        Ddstuningword = Ddstuningword + Mhz10
        Ddstmp = Ddstmp - 10000
      Next Ddsaddnum
      Ddsdiv = 1000
    
      'number of mhz1
      Ddsnum = Ddstmp / Ddsdiv
      For Ddsaddnum = 1 To Ddsnum
        Ddstuningword = Ddstuningword + Mhz1
        Ddstmp = Ddstmp - 1000
      Next Ddsaddnum
      Ddsdiv = 100
    
      'number of khz100
      Ddsnum = Ddstmp / Ddsdiv
      For Ddsaddnum = 1 To Ddsnum
        Ddstuningword = Ddstuningword + Khz100
        Ddstmp = Ddstmp - 100
      Next Ddsaddnum
      Ddsdiv = 10
    
      'number of khz10
      Ddsnum = Ddstmp / Ddsdiv
      For Ddsaddnum = 1 To Ddsnum
        Ddstuningword = Ddstuningword + Khz10
        Ddstmp = Ddstmp - 10
      Next Ddsaddnum
    
      'number of khz1 is remainder of ddstmp
      Ddsnum = Ddstmp
      For Ddsaddnum = 1 To Ddsnum
        Ddstuningword = Ddstuningword + Khz1
      Next Ddsaddnum
    End Sub
    
    
    '******************************************************************************
    
    Sub Resetdds
      Ddstuningword = 0
      Shiftout , Ddsdata , Wclk , Ddstuningword , 3
      Twbyte4 = 0
      Shiftout , Ddsdata , Wclk , Twbyte4 , 3
      'toggle fqud to latch data in dds
      Set Fqud
      nop
      Reset Fqud
    End Sub
    
    
    '******************************************************************************
    
    Sub Readadc
      'read both tlc1549 adc's
      'set adcphase and adcmagnitude to zero
      Adcphase = 0
      Adcmagnitude = 0
      'start with bit 9
      Adcbit = 512
      'enable adc's
      Reset Adccs
      'Waitus 100 'only in breadboard...
      'repeat for adc bits 9 to 0
      While Adcbit > 0
      'For Adccount = 1 To 10
        'adc clock low
        Reset Adcclk
        'Waitus 100 'only in breadboard...
        'read adc's input bit
        If Adcphasein = 1 Then
          Adcphase = Adcphase + Adcbit
        End If
        If Adcmagnin = 1 Then
          Adcmagnitude = Adcmagnitude + Adcbit
        End If
        'set adc clock high
        Set Adcclk
        'Waitus 100 'only in breadboard...
        'shift adcbit right (divide by 2 to get next bit value)
        Shift Adcbit , Right
      Wend
      'Next Adccount
      'disable adc's
      Set Adccs
      'adc clock high
      Set Adcclk
    End Sub
    
    
    '******************************************************************************
    
    Sub Docalcall
      Returnloss = Adcmagnitude * Adcmagres
      Returnloss = Returnloss - 30.0
      Angle = Adcphase * Adcphres
      Tmpsa = Returnloss / 20.0
      Tmpsb = 10.0
      Mag = Power(tmpsb , Tmpsa)
      Mag = 1.0 / Mag
      Tmpsa = 1.0 + Mag
      Tmpsb = 1.0 - Mag
      Tmpsc = Tmpsa / Tmpsb
      Swr = Abs(tmpsc)
    
      Tmpsa = Angle / R2d
      F = Cos(tmpsa)
      G = Sin(tmpsa)
      Rr = F * Mag
      Ss = G * Mag
      Tmpsa = 1.0 - Rr
      Rrsqrtmp = Tmpsa * Tmpsa
      Sssqrtmp = Ss * Ss
      Tmpsa = Rrsqrtmp + Sssqrtmp
      Tmpsb = 2.0 * Ss
      Tmpsc = Tmpsb / Tmpsa
      Tmpsa = Tmpsc * Z0
      Ximp = Abs(tmpsa)
    
      Tmpsa = Rr * Rr
      Tmpsb = 1.0 - Tmpsa
      Tmpsa = Tmpsb - Sssqrtmp
      Tmpsb = Rrsqrtmp + Sssqrtmp
      Tmpsc = Tmpsa / Tmpsb
      Tmpsa = Tmpsc * Z0
      Rimp = Abs(tmpsa)
    
      Tmpsa = Rimp * Rimp
      Tmpsb = Ximp * Ximp
      Tmpsc = Tmpsa + Tmpsb
    '  Zimp = Sqr(tmpsc)
    
      Zimpl = Sqr(tmpsc)
      Zimp = Zimpl - 2.4                                        ' Set calibration of Z0 (2.4 is cal value on 50ohm test load)
    
    End Sub
    
    
    '******************************************************************************
    
    Sub Docalcswr
      Returnloss = Adcmagnitude * Adcmagres
      Returnloss = Returnloss - 30.0
      Angle = Adcphase * Adcphres
      Tmpsa = Returnloss / 20.0
      Tmpsb = 10.0
      Mag = Power(tmpsb , Tmpsa)
      Mag = 1.0 / Mag
      Tmpsa = 1.0 + Mag
      Tmpsb = 1.0 - Mag
      Tmpsc = Tmpsa / Tmpsb
      Swr = Abs(tmpsc)
    End Sub
    
    
    '*****> Keyboard <**************************************************************
    
    Sub Updfreq
    
       'Frequency up button
       If Buttonpushed = 253 Then
         Freqtmp = Freqspan / 2
         Freqtmp = Freqcentre + Freqtmp
         Freqtmp = Freqtmp + Freqstep
         If Freqtmp > Ddsfreqhighlimit Then
           Call Soundbeeper(50 , 2)
         Else
           Freqcentre = Freqcentre + Freqstep
         End If
       End If
    
       'Frequency down button
       If Buttonpushed = 254 Then
         Freqtmp = Freqspan / 2
         Freqtmp = Freqcentre - Freqtmp
         Freqtmp = Freqtmp - Freqstep
         If Freqtmp < Ddsfreqlowlimit Then
           Call Soundbeeper(50 , 2)
         Else
           Freqcentre = Freqcentre - Freqstep
         End If
       End If
    
       'Frequency span up button
       If Buttonpushed = 247 Then
         Reset Zerospan
         If Freqspanindex = Fspansnum Then
           Call Soundbeeper(50 , 2)
         Else
           Freqstspindex = Freqspanindex + 1
           Freqstsptmp = Lookup(freqstspindex , Fspans)
           Freqtmp = Freqstsptmp / 2
           Freqtmp = Freqcentre - Freqtmp
           Freqtmp1 = Freqstsptmp / 2
           Freqtmp1 = Freqcentre + Freqtmp1
           If Freqtmp < Ddsfreqlowlimit Or Freqtmp1 > Ddsfreqhighlimit Then
             Call Soundbeeper(50 , 2)
           Else
             Freqspanindex = Freqstspindex
             Freqspan = Freqstsptmp
           End If
         End If
       End If
    
       'Frequency span down button
       If Buttonpushed = 251 Then
         If Freqspanindex = 0 Then
           Set Zerospan
           'Call Soundbeeper(50 , 2)
         Else
           Freqstspindex = Freqspanindex - 1
           Freqstsptmp = Lookup(freqstspindex , Fspans)
           Freqtmp = Freqstsptmp / 2
           Freqtmp = Freqcentre - Freqtmp
           Freqtmp1 = Freqstsptmp / 2
           Freqtmp1 = Freqcentre + Freqtmp1
           If Freqtmp < Ddsfreqlowlimit Or Freqtmp1 > Ddsfreqhighlimit Then
             Call Soundbeeper(50 , 2)
           Else
             Freqspanindex = Freqstspindex
             Freqspan = Freqstsptmp
           End If
         End If
       End If
    
       'Frequency step up button
       If Buttonpushed = 223 Then
         If Freqstepindex = Fstepsnum Then
           Call Soundbeeper(50 , 2)
         Else
           Freqstepindex = Freqstepindex + 1
           Freqstep = Lookup(freqstepindex , Fsteps)
           Freqstepdisp = Lookupstr(freqstepindex , Fstepsdisp)
         End If
       End If
    
       'Frequency step down button
       If Buttonpushed = 239 Then
         If Freqstepindex = 0 Then
           Call Soundbeeper(50 , 2)
         Else
           Freqstepindex = Freqstepindex - 1
           Freqstep = Lookup(freqstepindex , Fsteps)
           Freqstepdisp = Lookupstr(freqstepindex , Fstepsdisp)
         End If
       End If
    
    End Sub
    
    
    '*****> Keyboard Debounce <*****************************************************
    
    Sub Readbuttons
      'read button state
      Buttonvalue = Buttons
      If Buttonvalue <> 255 Then
        Buttonpushed = Buttonvalue
        'a button is pushed, wait debounce
        Waitms 25
        Buttonvalue = 0
        'wait until button is released
        While Buttonvalue <> 255
          Buttonvalue = Buttons
        Wend
        'wait debounce
        Waitms 25
      End If
    End Sub
    
    
    '*****> Beep <******************************************************************
    
    Sub Soundbeeper(byval Beeplength As Word , Byval Beeptone As Byte)
      For Beepcount = 1 To Beeplength
        Toggle Beeper
        Waitms Beeptone
        Toggle Beeper
        Waitms Beeptone
      Next Beepcount
    End Sub
    
    
    '******************************************************************************
    
    End
    I belive that this sub should contain all math
    Code:
    Sub Docalcall
      Returnloss = Adcmagnitude * Adcmagres
      Returnloss = Returnloss - 30.0
      Angle = Adcphase * Adcphres
      Tmpsa = Returnloss / 20.0
      Tmpsb = 10.0
      Mag = Power(tmpsb , Tmpsa)
      Mag = 1.0 / Mag
      Tmpsa = 1.0 + Mag
      Tmpsb = 1.0 - Mag
      Tmpsc = Tmpsa / Tmpsb
      Swr = Abs(tmpsc)
    
      Tmpsa = Angle / R2d
      F = Cos(tmpsa)
      G = Sin(tmpsa)
      Rr = F * Mag
      Ss = G * Mag
      Tmpsa = 1.0 - Rr
      Rrsqrtmp = Tmpsa * Tmpsa
      Sssqrtmp = Ss * Ss
      Tmpsa = Rrsqrtmp + Sssqrtmp
      Tmpsb = 2.0 * Ss
      Tmpsc = Tmpsb / Tmpsa
      Tmpsa = Tmpsc * Z0
      Ximp = Abs(tmpsa)
    
      Tmpsa = Rr * Rr
      Tmpsb = 1.0 - Tmpsa
      Tmpsa = Tmpsb - Sssqrtmp
      Tmpsb = Rrsqrtmp + Sssqrtmp
      Tmpsc = Tmpsa / Tmpsb
      Tmpsa = Tmpsc * Z0
      Rimp = Abs(tmpsa)
    
      Tmpsa = Rimp * Rimp
      Tmpsb = Ximp * Ximp
      Tmpsc = Tmpsa + Tmpsb
    '  Zimp = Sqr(tmpsc)
    
      Zimpl = Sqr(tmpsc)
      Zimp = Zimpl - 2.4                                        ' Set calibration of Z0 (2.4 is cal value on 50ohm test load)
    
    End Sub
    But I strougle to get it.
    First part is just converting ADC to Phase and return loss, calculating magnitude and SWR.
    Then I'm lost...
    I can't find from where I downloaded that source code, but it wasn't any coment on code...
    Last edited by pedja089; - 27th May 2019 at 12:27.

  7. #7
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    2,914

    Default Re: AD8302 Phase and magnitude to complex impedance

    To make thing more complicated, the antenna under test, should be far away from almost anything. Ground, cables, metals of any kind and sure yourself.

    So, how will you be able to, relatively easy, trim the antenna...

    Nice project, following your progress with great interest.

    Ioannis

  8. #8
    Join Date
    Sep 2009
    Posts
    774

    Default Re: AD8302 Phase and magnitude to complex impedance

    That is usually case. But I want it to be in real working condition(bolted to wall) or on other surface.
    So trimming isn't problem.
    Step 1: Make longer antenna,
    Step 2: Just go to antenna clip 2mm too far, then move away, see that you clip too much,
    Repeat step 1
    Step 3 Then add matching network suggested for other antenna(just to try it).
    See that resonant frequency move up, so go to step 1
    Step 4: Build VNA
    Step 5: Hate math

  9. #9
    Join Date
    Sep 2009
    Posts
    774

    Default Re: AD8302 Phase and magnitude to complex impedance

    Step 6: Realize how stupid you are, and how some things are simple
    Math is actually fairly simple.
    M=Vf/Vr-magnitude signal from AD8302. p- Phase from AD8302, Z0-system impedance

    Zx=Z0*[M*(cos(p)-j sin(p))]/[1-M*(cos(p)-j sin(p))]

    So you get something like this

    Zx=R-j X
    and that is exactly what I need to plot on SimSmith.

  10. #10
    Join Date
    Sep 2009
    Posts
    774

    Default Re: AD8302 Phase and magnitude to complex impedance

    Written in form Zx=R-jX
    Attachment 8927

  11. #11
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    2,914

    Default Re: AD8302 Phase and magnitude to complex impedance

    OK, and you say these are maths a PIC can do, at least easy?

    Ioannis

  12. #12
    Join Date
    Sep 2009
    Posts
    774

    Default Re: AD8302 Phase and magnitude to complex impedance

    First, I now see that I have mistake in formula, all items with "i" should be on right. I used online calc to solve it. Looks like that I need to solve by hand...
    Answer to your question is yes, and using PBP and some assembly.
    If you search forum, you will find post from Melanie, about calculating sin cos to 2 decimals. Solve separate first and second fraction. Then display it in form Z=R+iX.
    Also few years ago I implemented calculating mean kinetic temperature(https://en.wikipedia.org/wiki/Mean_kinetic_temperature second formula) using PBP and ASM look up tables(as they use less space) with maximum error of 0,1C in range from -20 to 50C.

  13. #13
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    2,914

    Default Re: AD8302 Phase and magnitude to complex impedance

    Thanks for the info. Very interesting.

    Staying tuned to see how it evolves.

    Ioannis

Similar Threads

  1. Replies: 5
    Last Post: - 1st November 2013, 05:11
  2. Measuring battery impedance
    By lerameur in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 3rd August 2011, 22:16
  3. Input Pins Low Impedance
    By GraemeJ in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 5th December 2010, 04:00
  4. how large and complex firmware you design using pbp?
    By chrdcv in forum mel PIC BASIC Pro
    Replies: 17
    Last Post: - 22nd December 2008, 00:30
  5. Replies: 6
    Last Post: - 30th October 2006, 03:37

Members who have read this thread : 12

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts