Skip to content

Commit

Permalink
Add L/C match functional (based on OneOfEleven code)
Browse files Browse the repository at this point in the history
  • Loading branch information
DiSlord committed Sep 19, 2020
1 parent 34d04fa commit d802f6a
Show file tree
Hide file tree
Showing 5 changed files with 329 additions and 6 deletions.
273 changes: 273 additions & 0 deletions lc_matching.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
/*
* (c) Yury Kuchura
* [email protected]
*
* This code can be used on terms of WTFPL Version 2 (http://www.wtfpl.net/).
*
* Heavily messed about with by OneOfEleven July 2020
* DiSlord adaptation to use on NanoVNA
*/

// calculate physical component values to match an impendace to 'ref_impedance' (ie 50R)

#ifdef __USE_LC_MATCHING__

typedef struct
{
float xps; // Reactance parallel to source (can be NAN if not applicable)
float xs; // Serial reactance (can be 0.0 if not applicable)
float xpl; // Reactance parallel to load (can be NAN if not applicable)
} t_lc_match;

typedef struct
{
uint32_t Hz;
float R0;
float RL;
float XL;
float VSWR;
// L-Network solution structure
t_lc_match matches[4];
int16_t num_matches;
uint16_t sweep_n;
} t_lc_match_array;

static t_lc_match_array lc_match_array;

static void lc_match_quadratic_equation(float a, float b, float c, float *x)
{
const float d = (b * b) - (4.0f * a * c);
if (d < 0){
x[0] = 0.0f;
x[1] = 0.0f;
}
else{
const float sd = sqrtf(d);
const float a2 = 2.0f * a;
x[0] = (-b + sd) / a2;
x[1] = (-b - sd) / a2;
}
}

// Calculate two solutions for ZL where (R + X * X / R) > R0
static void lc_match_calc_hi(float R0, float RL, float XL, t_lc_match *matches)
{
float xs[2];
float xp[2];

const float a = R0 - RL;
const float b = 2.0f * XL * R0;
const float c = R0 * ((XL * XL) + (RL * RL));
lc_match_quadratic_equation(a, b, c, xp);

// found two impedances parallel to load
//
// now calculate serial impedances
const float RL1 = -XL * xp[0];
const float XL1 = RL * xp[0];
const float RL2 = RL + 0.0f;
const float XL2 = XL + xp[0];
xs[0] = -((RL2 * XL1) - (RL1 * XL2)) / ((RL2 * RL2) + (XL2 * XL2));

const float RL3 = -XL * xp[1];
const float XL3 = RL * xp[1];
const float RL4 = RL + 0.0f;
const float XL4 = XL + xp[1];
xs[1] = -((RL4 * XL3) - (RL3 * XL4)) / ((RL4 * RL4) + (XL4 * XL4));

matches[0].xs = xs[0];
matches[0].xps = 0.0f;
matches[0].xpl = xp[0];

matches[1].xs = xs[1];
matches[1].xps = 0.0f;
matches[1].xpl = xp[1];
}

// Calculate two solutions for ZL where R < R0
static void lc_match_calc_lo(float R0, float RL, float XL, t_lc_match *matches)
{
float xs[2];
float xp[2];

// Calculate Xs

const float a = 1.0f;
const float b = 2.0f * XL;
const float c = (RL * RL) + (XL * XL) - (R0 * RL);
lc_match_quadratic_equation(a, b, c, xs);

// got two serial impedances that change ZL to the Y.real = 1/R0
//
// now calculate impedances parallel to source

const float RL1 = RL + 0.0f;
const float XL1 = XL + xs[0];
const float RL3 = RL1 * R0;
const float XL3 = XL1 * R0;
const float RL5 = RL1 - R0;
const float XL5 = XL1 - 0.0f;
xp[0] = ((RL5 * XL3) - (RL3 * XL5)) / ((RL5 * RL5) + (XL5 * XL5));

const float RL2 = RL + 0.0f;
const float XL2 = XL + xs[1];
const float RL4 = RL2 * R0;
const float XL4 = XL2 * R0;
const float RL6 = RL2 - R0;
const float XL6 = XL2 - 0.0f;
xp[1] = ((RL6 * XL4) - (RL4 * XL6)) / ((RL6 * RL6) + (XL6 * XL6));

matches[0].xs = xs[0];
matches[0].xps = xp[0];
matches[0].xpl = 0.0f;

matches[1].xs = xs[1];
matches[1].xps = xp[1];
matches[1].xpl = 0.0f;
}

static int lc_match_calc(void)
{
const float R0 = lc_match_array.R0;
const float RL = lc_match_array.RL;
const float XL = lc_match_array.XL;
const float vswr = lc_match_array.VSWR;
t_lc_match *matches = lc_match_array.matches;
if (RL <= 0.5f)
return -1;
const float q_factor = XL / RL;
// no need for any matching
if (vswr <= 1.1f || q_factor >= 100.0f)
return 0;

// only one solution is enough: just a serial reactance
// this gives SWR < 1.1 if R is within the range 0.91 .. 1.1 of R0
if (RL > (R0 / 1.1f) && RL < (R0 * 1.1f)){
matches[0].xpl = 0.0f;
matches[0].xps = 0.0f;
matches[0].xs = -XL;
return 1;
}

if (RL >= R0)
{ // two Hi-Z solutions
lc_match_calc_hi(R0, RL, XL, &matches[0]);
return 2;
}

// compute Lo-Z solutions
lc_match_calc_lo(R0, RL, XL, &matches[0]);
if ((RL + (XL * q_factor)) <= R0)
return 2;

// two more Hi-Z solutions exist
lc_match_calc_hi(R0, RL, XL, &matches[2]);
return 4;
}

static void lc_match_process(void)
{
const int am = active_marker;
if (am < 0 || am >=MARKERS_MAX || current_props._markers[am].enabled == false)
return;

const int index = current_props._markers[am].index;
if (index < 0 || index >= sweep_points)
return;

lc_match_array.R0 = 50.0f;
lc_match_array.Hz = frequencies[index];

if (lc_match_array.Hz == 0)
return;

if (lc_match_array.sweep_n == sweep_count && lc_match_array.Hz == frequencies[index])
return;

lc_match_array.sweep_n = sweep_count;

const float *coeff = measured[0][index];
// compute the impedance at the chosen frequency
lc_match_array.RL = resistance(coeff);
lc_match_array.XL = reactance(coeff);
lc_match_array.VSWR = swr(coeff);
// compute the possible LC matches
lc_match_array.num_matches = lc_match_calc();
}

//
static void lc_match_x_str(uint32_t FHz, float X, int xp, int yp)
{
if (isnan(X) || 0.0f == X || -0.0f == X)
return;

char type;
char str[12];
#if 0
float val;
if (X < 0.0f) {val = 1.0f / (2.0f * VNA_PI * FHz * -X); type = 'F';}
else {val = X / (2.0f * VNA_PI * FHz); type = 'H';}
#else
if (X < 0.0f) {X = -1.0 / X; type = 'F';}
else { type = 'H';}
float val = X / (2.0f * VNA_PI * FHz);
#endif
plot_printf(str, sizeof(str), "%4.2F%c", val, type);
cell_drawstring(str, xp, yp);
}

// Render L/C match tet to cell
static void cell_draw_lc_match(int x0, int y0)
{
char s[32];
lc_match_process();

int xp = STR_LC_MATH_X - x0;
int yp = STR_LC_MATH_Y - y0;

ili9341_set_background(LCD_BG_COLOR);
ili9341_set_foreground(LCD_FG_COLOR);

if (yp > -FONT_GET_HEIGHT && yp < CELLHEIGHT)
{
plot_printf(s, sizeof(s), "L/C match for source Z0 = %0.1f"S_OHM, lc_match_array.R0);
cell_drawstring(s, xp, yp);
}
#if 0
yp += STR_LC_MATH_HEIGHT;
if (yp > -FONT_GET_HEIGHT && yp < CELLHEIGHT)
{
plot_printf(s, sizeof(s), "%qHz %0.1f %c j%0.1f"S_OHM, match_array->Hz, match_array->RL, (match_array->XL >= 0) ? '+' : '-', fabsf(match_array->XL));
cell_drawstring(s, xp, yp);
}
#endif

yp += STR_LC_MATH_HEIGHT;
if (yp >= CELLHEIGHT) return;
if (lc_match_array.num_matches < 0)
cell_drawstring("No LC match for this lo", xp, yp);
else if (lc_match_array.num_matches == 0)
cell_drawstring("No need for LC match", xp, yp);
else {
cell_drawstring("Src shunt", xp , yp);
cell_drawstring("Series" , xp + STR_LC_MATH_WIDTH, yp);
cell_drawstring("Load" , xp + 2*STR_LC_MATH_WIDTH, yp);
for (int i = 0; i < lc_match_array.num_matches; i++){
yp += STR_LC_MATH_HEIGHT;
if (yp >= CELLHEIGHT) return;
if (yp > -FONT_GET_HEIGHT){
lc_match_x_str(lc_match_array.Hz, lc_match_array.matches[i].xps, xp , yp);
lc_match_x_str(lc_match_array.Hz, lc_match_array.matches[i].xs , xp + STR_LC_MATH_WIDTH, yp);
lc_match_x_str(lc_match_array.Hz, lc_match_array.matches[i].xpl, xp + 2*STR_LC_MATH_WIDTH, yp);
}
}
}
}

// Mark to redraw area under L/C match text
static void lc_match_mark_area(void){
// Update area
invalidate_rect(STR_LC_MATH_X , STR_LC_MATH_Y,
STR_LC_MATH_X + 3 * STR_LC_MATH_WIDTH, STR_LC_MATH_Y + (lc_match_array.num_matches + 2)*STR_LC_MATH_HEIGHT);
}
#endif
6 changes: 3 additions & 3 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ float measured[2][POINTS_COUNT][2];
uint32_t frequencies[POINTS_COUNT];

#undef VERSION
#define VERSION "1.0.36"
#define VERSION "1.0.38"

// Version text, displayed in Config->Version menu, also send by info command
const char *info_about[]={
Expand Down Expand Up @@ -763,8 +763,8 @@ config_t config = {
.dac_value = 1922,
.lcd_palette = LCD_DEFAULT_PALETTE,
// .touch_cal = { 693, 605, 124, 171 }, // 2.4 inch LCD panel
// .touch_cal = { 358, 544, 162, 198 }, // 2.8 inch LCD panel
.touch_cal = { 272, 521, 114, 153 }, //4.0" LCD
.touch_cal = { 358, 544, 162, 198 }, // 2.8 inch LCD panel
// .touch_cal = { 272, 521, 114, 153 }, //4.0" LCD
._mode = VNA_MODE_START_STOP,
.harmonic_freq_threshold = FREQUENCY_THRESHOLD,
._serial_speed = SERIAL_DEFAULT_BITRATE,
Expand Down
15 changes: 15 additions & 0 deletions nanovna.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#define __USE_SD_CARD__
// If enabled serial in halconf.h, possible enable serial console control
#define __USE_SERIAL_CONSOLE__
// Add LC match function
#define __USE_LC_MATCHING__

/*
* main.c
Expand Down Expand Up @@ -178,6 +180,8 @@ extern uint32_t frequencies[POINTS_COUNT];
#define TD_WINDOW_NORMAL (0b00<<3)
#define TD_WINDOW_MINIMUM (0b01<<3)
#define TD_WINDOW_MAXIMUM (0b10<<3)
// L/C match enable option
#define TD_LC_MATH (1<<5)

#if POINTS_COUNT <= 256
#define FFT_SIZE 256
Expand Down Expand Up @@ -404,6 +408,17 @@ extern int16_t area_height;
#define KP_GET_Y(posy) ((posy)*KP_HEIGHT + 12 )
#endif

#ifdef __USE_LC_MATCHING__
// X and Y offset to L/C match text
#define STR_LC_MATH_X (OFFSETX + 0)
// Better be aligned by cell
#define STR_LC_MATH_Y (OFFSETY + 32)
// 1/3 Width of text (need 3 column for data)
#define STR_LC_MATH_WIDTH (FONT_WIDTH * 10)
// String Height (need 2 + 0..4 string)
#define STR_LC_MATH_HEIGHT (FONT_STR_HEIGHT + 2)
#endif

// Additional chars in fonts
#define S_DELTA "\027" // hex 0x17
#define S_SARROW "\030" // hex 0x18
Expand Down
24 changes: 21 additions & 3 deletions plot.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ static int16_t grid_width;
int16_t area_width = AREA_WIDTH_NORMAL;
int16_t area_height = AREA_HEIGHT_NORMAL;

// Counter for sweep
uint16_t sweep_count = 0;

// Cell render use spi buffer
static pixel_t *cell_buffer;
// Check buffer size
Expand All @@ -54,8 +57,8 @@ typedef uint16_t map_t;
typedef uint32_t map_t;
#endif

map_t markmap[2][MAX_MARKMAP_Y];
uint8_t current_mappage = 0;
static map_t markmap[2][MAX_MARKMAP_Y];
static uint8_t current_mappage = 0;

// Trace data cache, for faster redraw cells
// CELL_X[16:31] x position
Expand Down Expand Up @@ -951,6 +954,11 @@ cell_drawstring(char *str, int x, int y)
}
}

// Include L/C match functions
#ifdef __USE_LC_MATCHING__
#include "lc_matching.c"
#endif

#define REFERENCE_WIDTH 6
#define REFERENCE_HEIGHT 5
#define REFERENCE_X_OFFSET 5
Expand Down Expand Up @@ -1123,6 +1131,11 @@ markmap_marker(int marker)
int y = CELL_Y(index) - Y_MARKER_OFFSET;
invalidate_rect(x, y, x+MARKER_WIDTH-1, y+MARKER_HEIGHT-1);
}
// Update L/C match area for redraw
#ifdef __USE_LC_MATCHING__
if ((domain_mode & TD_LC_MATH) && marker == active_marker)
lc_match_mark_area();
#endif
}

static void
Expand Down Expand Up @@ -1273,7 +1286,7 @@ plot_into_index(float measured[2][POINTS_COUNT][2])
if (trace[t].enabled && trace[t].polar)
quicksort(trace_index[t], 0, sweep_points);
#endif

sweep_count++;
mark_cells_from_index();
markmap_all_markers();
}
Expand Down Expand Up @@ -1449,6 +1462,11 @@ draw_cell(int m, int n)
if (n <= (3*FONT_STR_HEIGHT)/CELLHEIGHT)
cell_draw_marker_info(x0, y0);
#endif
// L/C match data output
#ifdef __USE_LC_MATCHING__
if (domain_mode & TD_LC_MATH)
cell_draw_lc_match(x0, y0);
#endif
// PULSE;
// Draw reference position (<10 system ticks for all screen calls)
for (t = 0; t < TRACES_MAX; t++) {
Expand Down
Loading

0 comments on commit d802f6a

Please sign in to comment.