# Thread: AD8302 Phase and magnitude to complex impedance

1. ## 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

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

2. ## 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).  Reply With Quote

3. ## 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
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  Reply With Quote

4. ## 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.  Reply With Quote

5. ## 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  Reply With Quote

6. ## 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 Rtotal (RmeasAdd + Rmeas + Rload)
#define DSP_Z0 50.0f

#define NSAMPLES 512

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;
DMA_DeInit(DMA1_Channel1);
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;
int i;

// PCLK2 is the APB2 clock
// ADCCLK = PCLK2/6 = 72/6 = 12MHz

//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_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

Sleep(10);

//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)
{
}
REMEASURE:
for (i = 0; i < NMEAS; i++)
{
ConfigDMA();
while(!DMA_GetFlagStatus(DMA1_FLAG_TC1)); //Blocks until measurement is finished
DMA_ClearFlag(DMA1_FLAG_TC1);

//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

Config Portc.0 = Output

Config Portc.1 = Input

Config Portc.2 = Input

'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

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 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

'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

'reset dds control lines
Reset Wclk
Reset Ddsdata
Reset Fqud

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
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
If Buttonpushed <> 255 Then
Call Soundbeeper(100 , 1)
Call Updfreq
Buttonpushed = 255
Goto Startsweep
End If
Call Calcddstuningword(ddsfreq)
Call Sendddstuningword(ddstuningword)
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
Ddsdiv = 1000

'number of mhz1
Ddsnum = Ddstmp / Ddsdiv
For Ddsaddnum = 1 To Ddsnum
Ddstuningword = Ddstuningword + Mhz1
Ddstmp = Ddstmp - 1000
Ddsdiv = 100

'number of khz100
Ddsnum = Ddstmp / Ddsdiv
For Ddsaddnum = 1 To Ddsnum
Ddstuningword = Ddstuningword + Khz100
Ddstmp = Ddstmp - 100
Ddsdiv = 10

'number of khz10
Ddsnum = Ddstmp / Ddsdiv
For Ddsaddnum = 1 To Ddsnum
Ddstuningword = Ddstuningword + Khz10
Ddstmp = Ddstmp - 10

'number of khz1 is remainder of ddstmp
Ddsnum = Ddstmp
For Ddsaddnum = 1 To Ddsnum
Ddstuningword = Ddstuningword + Khz1
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

'******************************************************************************

'Waitus 100 'only in breadboard...
'repeat for adc bits 9 to 0
While Adcbit > 0
'For Adccount = 1 To 10
'Waitus 100 'only in breadboard...
If Adcphasein = 1 Then
End If
If Adcmagnin = 1 Then
End If
'set adc clock high
'Waitus 100 'only in breadboard...
'shift adcbit right (divide by 2 to get next bit value)
Shift Adcbit , Right
Wend
End Sub

'******************************************************************************

Sub Docalcall
Returnloss = Returnloss - 30.0
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 = Returnloss - 30.0
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 <*****************************************************

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 = Returnloss - 30.0
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.  Reply With Quote

7. ## 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  Reply With Quote

8. ## 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   Reply With Quote

9. ## 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.  Reply With Quote

10. ## Re: AD8302 Phase and magnitude to complex impedance

Written in form Zx=R-jX
Attachment 8927  Reply With Quote

11. ## Re: AD8302 Phase and magnitude to complex impedance

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

Ioannis  Reply With Quote

12. ## 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,1°C in range from -20 to 50°C.  Reply With Quote

13. ## Re: AD8302 Phase and magnitude to complex impedance

Thanks for the info. Very interesting.

Staying tuned to see how it evolves.

Ioannis  Reply With Quote

#### 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