mirror of
https://github.com/ttrftech/NanoVNA.git
synced 2025-12-06 03:31:59 +01:00
TDR feature
This commit is contained in:
parent
35dfd691a2
commit
889d675836
78
fft.h
Normal file
78
fft.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* fft.h is Based on
|
||||
* Free FFT and convolution (C)
|
||||
*
|
||||
* Copyright (c) 2019 Project Nayuki. (MIT License)
|
||||
* https://www.nayuki.io/page/free-small-fft-in-multiple-languages
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static uint8_t reverse_bits(uint8_t x, int n) {
|
||||
uint8_t result = 0;
|
||||
for (int i = 0; i < n; i++, x >>= 1)
|
||||
result = (result << 1) | (x & 1U);
|
||||
return result;
|
||||
}
|
||||
|
||||
/***
|
||||
* dir = forward: 0, inverse: 1
|
||||
*/
|
||||
void fft(float array[][2], uint8_t n, uint8_t dir) {
|
||||
int levels = 0; // Compute levels = floor(log2(n))
|
||||
for (uint8_t temp = n; temp > 1U; temp >>= 1)
|
||||
levels++;
|
||||
|
||||
uint8_t real = dir & 1;
|
||||
uint8_t imag = ~real & 1;
|
||||
|
||||
for (uint8_t i = 0; i < n; i++) {
|
||||
uint8_t j = reverse_bits(i, levels);
|
||||
if (j > i) {
|
||||
float temp = array[i][real];
|
||||
array[i][real] = array[j][real];
|
||||
array[j][real] = temp;
|
||||
temp = array[i][imag];
|
||||
array[i][imag] = array[j][imag];
|
||||
array[j][imag] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
// Cooley-Tukey decimation-in-time radix-2 FFT
|
||||
for (uint8_t size = 2; size <= n; size *= 2) {
|
||||
uint8_t halfsize = size / 2;
|
||||
uint8_t tablestep = n / size;
|
||||
for (uint8_t i = 0; i < n; i += size) {
|
||||
for (uint8_t j = i, k = 0; j < i + halfsize; j++, k += tablestep) {
|
||||
uint8_t l = j + halfsize;
|
||||
float tpre = array[l][real] * cos(2 * M_PI * k / n) + array[l][imag] * sin(2 * M_PI * k / n);
|
||||
float tpim = -array[l][real] * sin(2 * M_PI * k / n) + array[l][imag] * cos(2 * M_PI * k / n);
|
||||
array[l][real] = array[j][real] - tpre;
|
||||
array[l][imag] = array[j][imag] - tpim;
|
||||
array[j][real] += tpre;
|
||||
array[j][imag] += tpim;
|
||||
}
|
||||
}
|
||||
if (size == n) // Prevent overflow in 'size *= 2'
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
34
main.c
34
main.c
|
|
@ -23,6 +23,7 @@
|
|||
#include "usbcfg.h"
|
||||
#include "si5351.h"
|
||||
#include "nanovna.h"
|
||||
#include "fft.h"
|
||||
|
||||
#include <chprintf.h>
|
||||
#include <shell.h>
|
||||
|
|
@ -36,6 +37,7 @@
|
|||
static void apply_error_term(void);
|
||||
static void apply_error_term_at(int i);
|
||||
static void cal_interpolate(int s);
|
||||
static void transform_domain(void);
|
||||
|
||||
void sweep(void);
|
||||
|
||||
|
|
@ -54,6 +56,8 @@ int8_t redraw_requested = FALSE;
|
|||
int8_t stop_the_world = FALSE;
|
||||
int16_t vbat = 0;
|
||||
|
||||
uint8_t domain = DOMAIN_TIME;
|
||||
uint8_t tdrfunc = TDR_IMPULSE;
|
||||
static THD_WORKING_AREA(waThread1, 640);
|
||||
static THD_FUNCTION(Thread1, arg)
|
||||
{
|
||||
|
|
@ -82,6 +86,7 @@ static THD_FUNCTION(Thread1, arg)
|
|||
draw_battery_status();
|
||||
}
|
||||
|
||||
transform_domain();
|
||||
/* calculate trace coordinates */
|
||||
plot_into_index(measured);
|
||||
/* plot trace as raster */
|
||||
|
|
@ -107,6 +112,35 @@ toggle_sweep(void)
|
|||
sweep_enabled = !sweep_enabled;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
transform_domain(void)
|
||||
{
|
||||
if (domain != DOMAIN_TIME) return; // nothing to do for freq domain
|
||||
// use spi_buffer as temporary buffer
|
||||
// and calculate ifft for time domain
|
||||
float* tmp = (float*)spi_buffer;
|
||||
for (int ch = 0; ch < 2; ch++) {
|
||||
for (int i = 0; i < 128; i++) {
|
||||
tmp[i*2+0] = 0.0;
|
||||
tmp[i*2+1] = 0.0;
|
||||
}
|
||||
memcpy(spi_buffer, measured[ch], sizeof(measured[0]));
|
||||
fft((float(*)[2])tmp, 128, 1);
|
||||
memcpy(measured[ch], spi_buffer, sizeof(measured[0]));
|
||||
for (int i = 0; i < 101; i++) {
|
||||
measured[ch][i][0] /= 128.0;
|
||||
measured[ch][i][1] /= 128.0;
|
||||
}
|
||||
if (tdrfunc == TDR_STEP) {
|
||||
for (int i = 1; i < 101; i++) {
|
||||
measured[ch][i][0] += measured[ch][i-1][0];
|
||||
measured[ch][i][1] += measured[ch][i-1][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_pause(BaseSequentialStream *chp, int argc, char *argv[])
|
||||
{
|
||||
(void)chp;
|
||||
|
|
|
|||
12
nanovna.h
12
nanovna.h
|
|
@ -22,8 +22,20 @@
|
|||
/*
|
||||
* main.c
|
||||
*/
|
||||
|
||||
extern float measured[2][101][2];
|
||||
|
||||
enum {
|
||||
DOMAIN_FREQ, DOMAIN_TIME
|
||||
};
|
||||
|
||||
enum {
|
||||
TDR_IMPULSE, TDR_STEP
|
||||
};
|
||||
|
||||
extern uint8_t domain;
|
||||
extern uint8_t tdrfunc;
|
||||
|
||||
#define CAL_LOAD 0
|
||||
#define CAL_OPEN 1
|
||||
#define CAL_SHORT 2
|
||||
|
|
|
|||
11
plot.c
11
plot.c
|
|
@ -1367,8 +1367,15 @@ cell_draw_marker_info(int m, int n, int w, int h)
|
|||
chsnprintf(buf, sizeof buf, "%d:", active_marker + 1);
|
||||
cell_drawstring_5x7(w, h, buf, xpos, ypos, 0xffff);
|
||||
xpos += 16;
|
||||
frequency_string(buf, sizeof buf, frequencies[idx]);
|
||||
cell_drawstring_5x7(w, h, buf, xpos, ypos, 0xffff);
|
||||
if (domain == DOMAIN_FREQ) {
|
||||
frequency_string(buf, sizeof buf, frequencies[idx]);
|
||||
cell_drawstring_5x7(w, h, buf, xpos, ypos, 0xffff);
|
||||
} else {
|
||||
#define SPEED_OF_LIGHT 299792458
|
||||
float distance = ((float)idx * (float)SPEED_OF_LIGHT) / ( (float)(frequencies[1] - frequencies[0]) * 128.0 * 2.0);
|
||||
chsnprintf(buf, sizeof buf, "%f m", distance);
|
||||
cell_drawstring_5x7(w, h, buf, xpos, ypos, 0xffff);
|
||||
}
|
||||
|
||||
// draw marker delta
|
||||
if (previous_marker >= 0 && active_marker != previous_marker && markers[previous_marker].enabled) {
|
||||
|
|
|
|||
35
ui.c
35
ui.c
|
|
@ -664,6 +664,24 @@ menu_channel_cb(int item)
|
|||
ui_mode_normal();
|
||||
}
|
||||
|
||||
static void
|
||||
menu_tdr_cb(int item)
|
||||
{
|
||||
switch (item) {
|
||||
case 0:
|
||||
domain = (domain == DOMAIN_FREQ) ? DOMAIN_TIME : DOMAIN_FREQ;
|
||||
break;
|
||||
case 1:
|
||||
tdrfunc = TDR_IMPULSE;
|
||||
break;
|
||||
case 2:
|
||||
tdrfunc = TDR_STEP;
|
||||
break;
|
||||
}
|
||||
|
||||
ui_mode_normal();
|
||||
}
|
||||
|
||||
static void
|
||||
choose_active_marker(void)
|
||||
{
|
||||
|
|
@ -874,11 +892,20 @@ const menuitem_t menu_channel[] = {
|
|||
{ MT_NONE, NULL, NULL } // sentinel
|
||||
};
|
||||
|
||||
const menuitem_t menu_tdr[] = {
|
||||
{ MT_CALLBACK, "TDR MODE", menu_tdr_cb },
|
||||
{ MT_CALLBACK, "IMPULSE", menu_tdr_cb },
|
||||
{ MT_CALLBACK, "STEP", menu_tdr_cb },
|
||||
{ MT_CANCEL, S_LARROW" BACK", NULL },
|
||||
{ MT_NONE, NULL, NULL } // sentinel
|
||||
};
|
||||
|
||||
const menuitem_t menu_display[] = {
|
||||
{ MT_SUBMENU, "TRACE", menu_trace },
|
||||
{ MT_SUBMENU, "FORMAT", menu_format },
|
||||
{ MT_SUBMENU, "SCALE", menu_scale },
|
||||
{ MT_SUBMENU, "CHANNEL", menu_channel },
|
||||
{ MT_SUBMENU, "TDR", menu_tdr },
|
||||
{ MT_CANCEL, S_LARROW" BACK", NULL },
|
||||
{ MT_NONE, NULL, NULL } // sentinel
|
||||
};
|
||||
|
|
@ -1235,6 +1262,14 @@ menu_item_modify_attribute(const menuitem_t *menu, int item,
|
|||
*bg = 0x0000;
|
||||
*fg = 0xffff;
|
||||
}
|
||||
} else if (menu == menu_tdr) {
|
||||
if ((item == 0 && domain == DOMAIN_TIME)
|
||||
|| (item == 1 && tdrfunc == TDR_IMPULSE)
|
||||
|| (item == 2 && tdrfunc == TDR_STEP)
|
||||
) {
|
||||
*bg = 0x0000;
|
||||
*fg = 0xffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue