diff --git a/nanovna.h b/nanovna.h index 49ab04d..5841763 100644 --- a/nanovna.h +++ b/nanovna.h @@ -70,6 +70,7 @@ #define __REMOTE_DESKTOP__ // Add remote desktop option #define __LISTEN__ #ifdef TINYSA4 +#define __CHANNEL_POWER__ #define __LIMITS__ #define __HARMONIC__ #else @@ -271,6 +272,8 @@ void set_extra_lna(int t); extern float level_min; extern float level_max; extern float level_range; +extern float channel_power[3]; +extern float channel_power_watt[3]; extern const char * const unit_string[]; #ifdef TINYSA4 @@ -576,6 +579,7 @@ enum unit_type { #define UNIT_IS_LOG(T) ( T >= U_VOLT ? false : true) float value(float); +float index_to_value(const int i); typedef struct trace { uint8_t enabled; @@ -1297,13 +1301,14 @@ void self_test(int); void wait_user(void); void calibrate(void); float to_dBm(float); +float dBm_to_Watt(float); uint32_t calc_min_sweep_time_us(void); pureRSSI_t perform(bool b, int i, freq_t f, int e); void interpolate_maximum(int m); void calibrate_modulation(int modulation, int8_t *correction); enum { - M_OFF, M_IMD, M_OIP3, M_PHASE_NOISE, M_STOP_BAND, M_PASS_BAND, M_LINEARITY, M_AM, M_FM, M_THD + M_OFF, M_IMD, M_OIP3, M_PHASE_NOISE, M_STOP_BAND, M_PASS_BAND, M_LINEARITY, M_AM, M_FM, M_THD, M_CP, }; enum { diff --git a/plot.c b/plot.c index 52c229f..8d0af5f 100644 --- a/plot.c +++ b/plot.c @@ -335,6 +335,12 @@ to_dBm(const float v) return v; // raw data is in logmag*10 format } +float +dBm_to_Watt(const float v) +{ + return logf(v*1000.0)*(10.0/logf(10.0)); +} + static void trace_into_index_x_array(index_x_t *x, uint16_t points){ // Not need update if index calculated for this points count @@ -923,6 +929,13 @@ draw_cell(int m, int n) if (rectangular_grid_x(x + x0)) { for (y = 0; y < h; y++) cell_buffer[y * CELLWIDTH + x] = c; } +#ifdef __CHANNEL_POWER__ + if (setting.measurement == M_CP) { + if (x+x0 == WIDTH/3 || x+x0 == 2*WIDTH/3 ) { + for (y = 0; y < h; y++) cell_buffer[y * CELLWIDTH + x] = LCD_TRIGGER_COLOR; + } + } +#endif } for (y = 0; y < h; y++) { if (rectangular_grid_y(y + y0)) { @@ -1285,6 +1298,22 @@ static void cell_draw_marker_info(int x0, int y0) active++; } } +#ifdef __CHANNEL_POWER__ + if (setting.measurement==M_CP) { + char *p_label[3] = { "Left", "Mid", "Right" }; + for (int c=0; c<3;c++) { + if (c == 1) + plot_printf(buf, sizeof buf, "%s: %4.1fdB %4.1f%%", p_label[c], channel_power[1], 100.0 * (channel_power_watt[1] - channel_power_watt[0] - channel_power_watt[2]) /channel_power_watt[1] ); + else + plot_printf(buf, sizeof buf, "%s: %4.1fdB", p_label[c], channel_power[c]); + int xpos = 10 + (c)*(WIDTH/3) + CELLOFFSETX - x0; + int ypos = 1 - y0; + ili9341_set_foreground(LCD_FG_COLOR); + cell_drawstring_7x13(buf, xpos, ypos); + } + return; + } +#endif if (setting.measurement == M_THD && active >= 1) active = 2; for (int i = 0; i < MARKER_COUNT; i++) { diff --git a/sa_core.c b/sa_core.c index 1955cae..34bf7dd 100644 --- a/sa_core.c +++ b/sa_core.c @@ -71,7 +71,7 @@ static freq_t real_old_freq[4] = { 0, 0, 0, 0}; #endif #ifdef TINYSA4 -const float si_drive_dBm [] = {-41, -30, -21, -17, -12, -11, -10, -8.5, -7.5, -6.5, -5.5, -4.5, -3.5, -3 , -2, -1.5, -1, -0.5, 0}; +const float si_drive_dBm [] = {-41, -30, -21, -17, -14, -11, -10, -8, -7, -6, -5, -4, -3, -2.5 , -2, -1.5, -1, -0.5, 0}; const float adf_drive_dBm[] = {-15,-12,-9,-6}; const uint8_t drive_register[] = {0, 1, 2, 3, 4, 5, 6, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; float *drive_dBm = (float *) adf_drive_dBm; @@ -92,7 +92,7 @@ const int8_t drive_dBm [16] = {-38, -32, -30, -27, -24, -19, -15, -12, -5, -2, 0 #define SL_GENHIGH_LEVEL_MAX drive_dBm[MAX_DRIVE] #define SL_GENLOW_LEVEL_MIN -104 -#define SL_GENLOW_LEVEL_MAX -14 +#define SL_GENLOW_LEVEL_MAX -16 #else @@ -114,6 +114,8 @@ float level_min; float level_max; float level_range; +float channel_power[3]; +float channel_power_watt[3]; //int setting.refer = -1; // Off by default const uint32_t reffer_freq[] = {30000000, 15000000, 10000000, 4000000, 3000000, 2000000, 1000000}; @@ -2276,6 +2278,7 @@ void clock_at_48MHz(void) RCC->CR &= RCC_CR_HSICAL; RCC->CR |= ( (hsical) << 8 ); RCC->CR &= RCC_CR_HSITRIM | RCC_CR_HSION; /* CR Reset value. */ + RCC->CR |= RCC_CR_HSITRIM_4; } } @@ -3704,6 +3707,22 @@ sweep_again: // stay in sweep loop when output mo set_AGC_LNA(); #endif } +#ifdef __CHANNEL_POWER__ + } else if (setting.measurement == M_CP) { // ----------------CHANNEL_POWER measurement + int old_unit = setting.unit; + setting.unit = U_WATT; + for (int c = 0; c < 3 ;c++) { + channel_power_watt[c] = 0.0; + int sp_div3 = sweep_points/3; + for (int i =0; i < sp_div3; i++) { + channel_power_watt[c] += index_to_value(i + c*sp_div3); + } + float rbw_cor = (float)(get_sweep_frequency(ST_SPAN)/3) / ((float)actual_rbw_x10 * 100.0); + channel_power_watt[c] = channel_power_watt[c] * rbw_cor /(float)sp_div3; + channel_power[c] = to_dBm(channel_power_watt[c]); + } + setting.unit = old_unit; +#endif } #endif diff --git a/ui_sa.c b/ui_sa.c index ff84b80..edaeaa4 100644 --- a/ui_sa.c +++ b/ui_sa.c @@ -908,6 +908,8 @@ static UI_FUNCTION_ADV_CALLBACK(menu_measure_acb) switch(data) { case M_OFF: // Off // reset_settings(setting.mode); + markers[0].enabled = M_ENABLED; + markers[0].mtype = M_REFERENCE | M_TRACKING; no_measurement: set_measurement(M_OFF); break; @@ -1069,6 +1071,18 @@ static UI_FUNCTION_ADV_CALLBACK(menu_measure_acb) case M_THD: set_measurement(M_THD); break; +#ifdef __CHANNEL_POWER__ + case M_CP: // channel power + reset_settings(setting.mode); + markers[0].enabled = M_DISABLED; + kp_help_text = "Channel frequency"; + ui_mode_keypad(KM_CENTER); + kp_help_text = "Channel width"; + ui_mode_keypad(KM_SPAN); + set_sweep_frequency(ST_SPAN, uistat.value*3); + set_measurement(M_CP); + break; +#endif } #endif // selection = -1; @@ -2031,7 +2045,10 @@ static const menuitem_t menu_measure2[] = { { MT_ADV_CALLBACK, M_AM, "AM", menu_measure_acb}, { MT_ADV_CALLBACK, M_FM, "FM", menu_measure_acb}, { MT_ADV_CALLBACK, M_THD, "THD", menu_measure_acb}, -#ifdef __LINEARITY__ +#ifdef __CHANNEL_POWER__ + { MT_ADV_CALLBACK, M_CP, "CHANNEL\nPOWER",menu_measure_acb}, +#endif + #ifdef __LINEARITY__ { MT_ADV_CALLBACK | MT_LOW, M_LINEARITY, "LINEAR", menu_measure_acb}, #endif { MT_CANCEL, 0, S_LARROW" BACK", NULL },