diff --git a/main.c b/main.c index f33ac13..1c3ed1e 100644 --- a/main.c +++ b/main.c @@ -902,6 +902,9 @@ config_t config = { .high_out_adf4350 = true, .ext_zero_level = 174, .receive_switch_offset = 0.0, +#ifdef __NOISE_FIGURE__ + .noise_figure = 7.2, +#endif #endif .sweep_voltage = 3.3, .switch_offset = 0.0, @@ -1651,6 +1654,9 @@ static const VNAShellCommand commands[] = #endif {"dac" , cmd_dac , CMD_RUN_IN_LOAD}, {"sweep_voltage",cmd_sweep_voltage,CMD_RUN_IN_LOAD}, +#ifdef __NOISE_FIGURE__ + {"nf", cmd_nf, CMD_RUN_IN_LOAD}, +#endif {"saveconfig" , cmd_saveconfig , CMD_RUN_IN_LOAD}, {"clearconfig" , cmd_clearconfig , CMD_RUN_IN_LOAD}, {"data" , cmd_data , CMD_WAIT_MUTEX}, @@ -1914,7 +1920,7 @@ static const VNAShellCommand *VNAShell_parceLine(char *line){ // Parse and execute line char *lp = line, *ep; shell_nargs = 0; - + shell_args[0] = line; // shell_args[0] is used in error message, must be initialized // DEBUG_LOG(0, lp); // debug console log while (*lp != 0) { // Skipping white space and tabs at string begin. diff --git a/nanovna.h b/nanovna.h index d7f2db8..3709b87 100644 --- a/nanovna.h +++ b/nanovna.h @@ -83,6 +83,7 @@ #define __SD_CARD_LOAD__ // Allow run commands from SD card (config.ini in root) #define __LCD_BRIGHTNESS__ // LCD or hardware allow change brightness, add menu item for this #define __HARMONIC__ +#define __NOISE_FIGURE__ #define __VBW__ #define __SWEEP_RESTART__ #define DB_PER_DEGREE_BELOW 0.056 @@ -633,6 +634,9 @@ typedef struct config { float receive_switch_offset; float harmonic_level_offset; float shift_level_offset; +#endif +#ifdef __NOISE_FIGURE__ + float noise_figure; #endif float correction_value[CORRECTION_SIZE][CORRECTION_POINTS]; freq_t correction_frequency[CORRECTION_SIZE][CORRECTION_POINTS]; @@ -1137,7 +1141,7 @@ typedef struct properties { //sizeof(properties_t) == 0x1200 -#define CONFIG_MAGIC 0x434f4e52 /* 'CONF' */ +#define CONFIG_MAGIC 0x434f4e53 /* 'CONF' */ extern int16_t lastsaveid; //extern properties_t *active_props; @@ -1399,7 +1403,7 @@ void interpolate_maximum(int m); void calibrate_modulation(int modulation, int8_t *correction); enum { - M_OFF, M_IMD, M_OIP3, M_PHASE_NOISE, M_SNR, M_PASS_BAND, M_LINEARITY, M_AM, M_FM, M_THD, M_CP, M_DECONV + M_OFF, M_IMD, M_OIP3, M_PHASE_NOISE, M_SNR, M_PASS_BAND, M_LINEARITY, M_AM, M_FM, M_THD, M_CP, M_NF, M_DECONV }; enum { diff --git a/plot.c b/plot.c index a6b5f72..d60b82e 100644 --- a/plot.c +++ b/plot.c @@ -1587,6 +1587,24 @@ static void cell_draw_marker_info(int x0, int y0) cell_printf(xpos, ypos, FONT_b"#%d THD: %4.1f%%", h_count, thd); break; } +#ifdef __NOISE_FIGURE__ + } else if (i>=2 && setting.measurement == M_NF && markers[0].enabled && setting.external_gain != 0 ) { + float mNF = marker_to_value(0) - logf(actual_rbw_x10*100.0) * (10.0/logf(10.0)) + 174; // measured noise figure at 18C + float mnf = expf(mNF/10 * logf(10)); // measure noise factor + float tnf = expf(config.noise_figure/10 * logf(10)); // tinySA noise factor + float anf = mnf - (tnf - 1.0)/setting.external_gain; + float aNF = 10*logf(anf)/logf(10); + // powf(10,x) = expf(x * logf(10)) + // log10f(x) = logf(x)/logf(10) + + + ili9341_set_foreground(marker_color(markers[0].mtype)); +// j = 1; + int xpos = 1 + (j%2)*(WIDTH/2) + CELLOFFSETX - x0; + int ypos = 1 + (j/2)*(16) - y0; + cell_printf(xpos, ypos, FONT_b"NF: %4.1f", aNF); + break; +#endif } else if (i >= 2 && setting.measurement == M_OIP3 && markers[2].enabled && markers[3].enabled) { float il = marker_to_value(2); diff --git a/sa_cmd.c b/sa_cmd.c index e6f6383..19a8f40 100644 --- a/sa_cmd.c +++ b/sa_cmd.c @@ -370,6 +370,19 @@ VNA_SHELL_FUNCTION(cmd_sweep_voltage) config.sweep_voltage = value; } +#ifdef __NOISE_FIGURE__ +VNA_SHELL_FUNCTION(cmd_nf) +{ + if (argc != 1) { + shell_printf("usage: nr {value}\r\n"\ + "%f\r\n", config.noise_figure); + return; + } + config.noise_figure = my_atof(argv[0]); + dirty = true; +} +#endif + VNA_SHELL_FUNCTION(cmd_rbw) { if (argc != 1) { diff --git a/sa_core.c b/sa_core.c index 7aaf4f1..d3e15d7 100644 --- a/sa_core.c +++ b/sa_core.c @@ -2017,6 +2017,8 @@ case M_GENHIGH: // Direct output from 1 ADF4351_enable_out(true); // Must be enabled to have aux output #endif ADF4351_aux_drive(setting.lo_drive); + enable_extra_lna(false); + enable_ultra(true); // Open low output } else { ADF4351_enable_aux_out(false); ADF4351_enable_out(false); diff --git a/ui_sa.c b/ui_sa.c index b9c11b8..5841c23 100644 --- a/ui_sa.c +++ b/ui_sa.c @@ -431,6 +431,9 @@ enum { KM_MARKER_TIME, // #35 KM_VAR, +#ifdef __NOISE_FIGURE__ + KM_NF, +#endif KM_NONE // always at enum end }; @@ -488,6 +491,7 @@ static const struct { #endif [KM_MARKER_TIME] = {keypads_time , "MARKER\nTIME"}, // KM_MARKER_TIME [KM_VAR] = {keypads_freq , "JOG\nSTEP"}, // jog step +[KM_NF] = {keypads_plusmin , "NOISE\nFIGURE"}, // noise figure of tinySA }; #if 0 // Not used @@ -1170,6 +1174,8 @@ static UI_FUNCTION_ADV_CALLBACK(menu_measure_acb) TRACE_DISABLE(TRACE_STORED_FLAG); } set_average(AV_OFF); + set_external_gain(0.0); + set_extra_lna(false); } switch(data) { case M_OFF: // Off @@ -1332,6 +1338,17 @@ static UI_FUNCTION_ADV_CALLBACK(menu_measure_acb) // set_measurement(M_CP); break; #endif +#ifdef __NOISE_FIGURE__ + case M_NF: // noise figure +// reset_settings(setting.mode); + markers[0].enabled = M_ENABLED; + markers[0].mtype = M_NOISE; + set_extra_lna(true); + kp_help_text = "Amplifier Gain "; + ui_mode_keypad(KM_EXT_GAIN); + set_average(AV_100); + break; +#endif #ifdef __FFT_DECONV__ case M_DECONV: set_average(AV_DECONV); @@ -2482,11 +2499,14 @@ static const menuitem_t menu_settings4[] = { { MT_ADV_CALLBACK, 0, "DEBUG\nFREQ", menu_debug_freq_acb}, { MT_ADV_CALLBACK, 0, "DEBUG\nAVOID", menu_debug_avoid_acb}, -#if 1 // only used during development +#if 0 // only used during development { MT_KEYPAD, KM_COR_AM, "COR\nAM", "Enter AM modulation correction"}, { MT_KEYPAD, KM_COR_WFM, "COR\nWFM", "Enter WFM modulation correction"}, { MT_KEYPAD, KM_COR_NFM, "COR\nNFM", "Enter NFM modulation correction"}, #endif +#ifdef __NOISE_FIGURE__ + { MT_KEYPAD, KM_NF, "NOISE\nFIGURE", "Enter tinySA noise figure"}, +#endif #ifdef __SD_CARD_LOAD__ { MT_CALLBACK, 0 , "LOAD\nCONFIG", menu_load_config_cb}, #endif @@ -2613,6 +2633,9 @@ static const menuitem_t menu_measure2[] = { #ifdef __LINEARITY__ { MT_ADV_CALLBACK | MT_LOW, M_LINEARITY, "LINEAR", menu_measure_acb}, #endif +#ifdef __NOISE_FIGURE__ +{ MT_ADV_CALLBACK | MT_LOW, M_NF, "NOISE\nFIGURE", menu_measure_acb}, +#endif #ifdef __FFT_DECONV__ { MT_ADV_CALLBACK, M_DECONV, "DECONV", menu_measure_acb}, #endif @@ -3024,6 +3047,12 @@ static void fetch_numeric_target(uint8_t mode) uistat.freq_value = setting.frequency_var; plot_printf(uistat.text, sizeof uistat.text, setting.frequency_var ? "%QHz" : " AUTO", setting.frequency_var); break; +#ifdef __NOISE_FIGURE__ + case KM_NF: + uistat.value = config.noise_figure; + plot_printf(uistat.text, sizeof uistat.text, "%.1fdB", uistat.value); + break; +#endif } } @@ -3190,6 +3219,13 @@ set_numeric_value(void) case KM_VAR: setting.frequency_var = uistat.freq_value; break; +#ifdef __NOISE_FIGURE__ + case KM_NF: + config.noise_figure = uistat.value; + config_save(); + dirty = true; + break; +#endif } }