From 6bad9de6068828e97b5ca3b73f6f69a35a369f44 Mon Sep 17 00:00:00 2001 From: cho45 Date: Wed, 11 Sep 2019 20:47:17 +0900 Subject: [PATCH] change menu name to 'TRANSFORM' --- fft.h | 45 +++++++++++++++++++++++++++++------- main.c | 4 ++-- nanovna.h | 13 +++++++---- ui.c | 69 ++++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 104 insertions(+), 27 deletions(-) diff --git a/fft.h b/fft.h index bf5cb11..1a46515 100644 --- a/fft.h +++ b/fft.h @@ -33,16 +33,38 @@ static uint8_t reverse_bits(uint8_t x, int n) { return result; } +static const float sin_table[] = { + /* + * float has about 7.2 digits of precision + for (uint8_t i = 0; i < 96; i++) { + printf("% .8f,%c", sin(2 * M_PI * i / n), i % 8 == 7 ? '\n' : ' '); + } + */ + 0.00000000, 0.04906767, 0.09801714, 0.14673047, 0.19509032, 0.24298018, 0.29028468, 0.33688985, + 0.38268343, 0.42755509, 0.47139674, 0.51410274, 0.55557023, 0.59569930, 0.63439328, 0.67155895, + 0.70710678, 0.74095113, 0.77301045, 0.80320753, 0.83146961, 0.85772861, 0.88192126, 0.90398929, + 0.92387953, 0.94154407, 0.95694034, 0.97003125, 0.98078528, 0.98917651, 0.99518473, 0.99879546, + 1.00000000, 0.99879546, 0.99518473, 0.98917651, 0.98078528, 0.97003125, 0.95694034, 0.94154407, + 0.92387953, 0.90398929, 0.88192126, 0.85772861, 0.83146961, 0.80320753, 0.77301045, 0.74095113, + 0.70710678, 0.67155895, 0.63439328, 0.59569930, 0.55557023, 0.51410274, 0.47139674, 0.42755509, + 0.38268343, 0.33688985, 0.29028468, 0.24298018, 0.19509032, 0.14673047, 0.09801714, 0.04906767, + 0.00000000, -0.04906767, -0.09801714, -0.14673047, -0.19509032, -0.24298018, -0.29028468, -0.33688985, + -0.38268343, -0.42755509, -0.47139674, -0.51410274, -0.55557023, -0.59569930, -0.63439328, -0.67155895, + -0.70710678, -0.74095113, -0.77301045, -0.80320753, -0.83146961, -0.85772861, -0.88192126, -0.90398929, + -0.92387953, -0.94154407, -0.95694034, -0.97003125, -0.98078528, -0.98917651, -0.99518473, -0.99879546, +}; + /*** * dir = forward: 0, inverse: 1 + * https://www.nayuki.io/res/free-small-fft-in-multiple-languages/fft.c */ -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++; +static void fft128(float array[][2], const uint8_t dir) { + const uint8_t n = 128; + const uint8_t levels = 7; // log2(n) + const float* const cos_table = &sin_table[32]; - uint8_t real = dir & 1; - uint8_t imag = ~real & 1; + const uint8_t real = dir & 1; + const uint8_t imag = ~real & 1; for (uint8_t i = 0; i < n; i++) { uint8_t j = reverse_bits(i, levels); @@ -63,8 +85,8 @@ void fft(float array[][2], uint8_t n, uint8_t dir) { 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); + float tpre = array[l][real] * cos_table[k] + array[l][imag] * sin_table[k]; + float tpim = -array[l][real] * sin_table[k] + array[l][imag] * cos_table[k] ; array[l][real] = array[j][real] - tpre; array[l][imag] = array[j][imag] - tpim; array[j][real] += tpre; @@ -76,3 +98,10 @@ void fft(float array[][2], uint8_t n, uint8_t dir) { } } +static inline void fft128_forward(float array[][2]) { + fft128(array, 0); +} + +static inline void fft128_inverse(float array[][2]) { + fft128(array, 1); +} diff --git a/main.c b/main.c index 0cd5832..5d0a327 100644 --- a/main.c +++ b/main.c @@ -122,13 +122,13 @@ transform_domain(void) tmp[i*2+0] = 0.0; tmp[i*2+1] = 0.0; } - fft((float(*)[2])tmp, 128, 1); + fft128_inverse((float(*)[2])tmp); memcpy(measured[ch], tmp, sizeof(measured[0])); for (int i = 0; i < 101; i++) { measured[ch][i][0] /= 128.0; measured[ch][i][1] /= 128.0; } - if ( (domain_mode & TDR_FUNC_STEP) == TDR_FUNC_STEP ) { + if ( (domain_mode & TDR_FUNC) == TDR_FUNC_LOWPASS_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]; diff --git a/nanovna.h b/nanovna.h index d9e008f..7465d44 100644 --- a/nanovna.h +++ b/nanovna.h @@ -61,9 +61,14 @@ enum { #define DOMAIN_MODE (1<<0) #define DOMAIN_FREQ (0<<0) #define DOMAIN_TIME (1<<0) -#define TDR_FUNC (1<<1) -#define TDR_FUNC_IMPULSE (0<<1) -#define TDR_FUNC_STEP (1<<1) +#define TDR_FUNC (0b11<<1) +#define TDR_FUNC_BANDPASS (0b00<<1) +#define TDR_FUNC_LOWPASS_IMPULSE (0b01<<1) +#define TDR_FUNC_LOWPASS_STEP (0b10<<1) +#define TDR_WINDOW (0b11<<3) +#define TDR_WINDOW_NORMAL (0b00<<3) +#define TDR_WINDOW_MINIMUM (0b01<<3) +#define TDR_WINDOW_MAXIMUM (0b10<<3) void cal_collect(int type); void cal_done(void); @@ -298,7 +303,7 @@ typedef struct { trace_t _trace[TRACES_MAX]; marker_t _markers[4]; int _active_marker; - uint8_t _domain_mode; + uint8_t _domain_mode; /* 0bxxxxxffm : where ff: TDR_FUNC m: DOMAIN_MODE */ uint8_t _velocity_factor; // % int32_t checksum; diff --git a/ui.c b/ui.c index d62a54e..3541156 100644 --- a/ui.c +++ b/ui.c @@ -665,7 +665,27 @@ menu_channel_cb(int item) } static void -menu_tdr_cb(int item) +menu_transform_window_cb(int item) +{ + // TODO + switch (item) { + case 0: + domain_mode = (domain_mode & ~TDR_WINDOW) | TDR_WINDOW_MINIMUM; + ui_mode_normal(); + break; + case 1: + domain_mode = (domain_mode & ~TDR_WINDOW) | TDR_WINDOW_NORMAL; + ui_mode_normal(); + break; + case 2: + domain_mode = (domain_mode & ~TDR_WINDOW) | TDR_WINDOW_MAXIMUM; + ui_mode_normal(); + break; + } +} + +static void +menu_transform_cb(int item) { int status; switch (item) { @@ -678,14 +698,18 @@ menu_tdr_cb(int item) ui_mode_normal(); break; case 1: - domain_mode = (domain_mode & ~TDR_FUNC) | TDR_FUNC_IMPULSE; + domain_mode = (domain_mode & ~TDR_FUNC) | TDR_FUNC_LOWPASS_IMPULSE; ui_mode_normal(); break; case 2: - domain_mode = (domain_mode & ~TDR_FUNC) | TDR_FUNC_STEP; + domain_mode = (domain_mode & ~TDR_FUNC) | TDR_FUNC_LOWPASS_STEP; ui_mode_normal(); break; case 3: + domain_mode = (domain_mode & ~TDR_FUNC) | TDR_FUNC_BANDPASS; + ui_mode_normal(); + break; + case 5: status = btn_wait_release(); if (status & EVT_BUTTON_DOWN_LONG) { ui_mode_numeric(KM_VELOCITY_FACTOR); @@ -908,11 +932,21 @@ 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_CALLBACK, "\2VELOCITY\0FACTOR", menu_tdr_cb }, +const menuitem_t menu_transform_window[] = { + { MT_CALLBACK, "MINIMUM", menu_transform_window_cb }, + { MT_CALLBACK, "NORMAL", menu_transform_window_cb }, + { MT_CALLBACK, "MAXIMUM", menu_transform_window_cb }, + { MT_CANCEL, S_LARROW" BACK", NULL }, + { MT_NONE, NULL, NULL } // sentinel +}; + +const menuitem_t menu_transform[] = { + { MT_CALLBACK, "\2TRANSFORM\0ON", menu_transform_cb }, + { MT_CALLBACK, "\2LOW PASS\0IMPULSE", menu_transform_cb }, + { MT_CALLBACK, "\2LOW PASS\0STEP", menu_transform_cb }, + { MT_CALLBACK, "BANDPASS", menu_transform_cb }, + { MT_SUBMENU, "WINDOW", menu_transform_window }, + { MT_CALLBACK, "\2VELOCITY\0FACTOR", menu_transform_cb }, { MT_CANCEL, S_LARROW" BACK", NULL }, { MT_NONE, NULL, NULL } // sentinel }; @@ -922,7 +956,7 @@ const menuitem_t menu_display[] = { { MT_SUBMENU, "FORMAT", menu_format }, { MT_SUBMENU, "SCALE", menu_scale }, { MT_SUBMENU, "CHANNEL", menu_channel }, - { MT_SUBMENU, "TDR", menu_tdr }, + { MT_SUBMENU, "TRANSFORM", menu_transform }, { MT_CANCEL, S_LARROW" BACK", NULL }, { MT_NONE, NULL, NULL } // sentinel }; @@ -1168,7 +1202,7 @@ const keypads_t * const keypads_mode_tbl[] = { }; const char * const keypad_mode_label[] = { - "START", "STOP", "CENTER", "SPAN", "CW FREQ", "SCALE", "REFPOS", "EDELAY", "VELOCITY" + "START", "STOP", "CENTER", "SPAN", "CW FREQ", "SCALE", "REFPOS", "EDELAY", "VELOCITY%" }; void @@ -1281,10 +1315,19 @@ menu_item_modify_attribute(const menuitem_t *menu, int item, *bg = 0x0000; *fg = 0xffff; } - } else if (menu == menu_tdr) { + } else if (menu == menu_transform) { if ((item == 0 && (domain_mode & DOMAIN_MODE) == DOMAIN_TIME) - || (item == 1 && (domain_mode & TDR_FUNC) == TDR_FUNC_IMPULSE) - || (item == 2 && (domain_mode & TDR_FUNC) == TDR_FUNC_STEP) + || (item == 1 && (domain_mode & TDR_FUNC) == TDR_FUNC_LOWPASS_IMPULSE) + || (item == 2 && (domain_mode & TDR_FUNC) == TDR_FUNC_LOWPASS_STEP) + || (item == 3 && (domain_mode & TDR_FUNC) == TDR_FUNC_BANDPASS) + ) { + *bg = 0x0000; + *fg = 0xffff; + } + } else if (menu == menu_transform_window) { + if ((item == 0 && (domain_mode & TDR_WINDOW) == TDR_WINDOW_MINIMUM) + || (item == 1 && (domain_mode & TDR_WINDOW) == TDR_WINDOW_NORMAL) + || (item == 2 && (domain_mode & TDR_WINDOW) == TDR_WINDOW_MAXIMUM) ) { *bg = 0x0000; *fg = 0xffff;