diff --git a/vna_system/core/processors/configs/bscan_config.json b/vna_system/core/processors/configs/bscan_config.json index 986ec3e..143e04f 100644 --- a/vna_system/core/processors/configs/bscan_config.json +++ b/vna_system/core/processors/configs/bscan_config.json @@ -1,14 +1,14 @@ { - "open_air": true, + "open_air": false, "ach_norm_enabled": false, "s11_norm_enabled": false, "subtract_mean_ascan": false, "axis": "abs", - "cut": 0.183, - "max": 2.0, + "cut": 0.0, + "max": 12.0, "gain": 1.5, "start_freq": 1730.0, - "stop_freq": 7320.0, + "stop_freq": 6000.0, "clear_history": false, "sigma": 1.38, "border_border_m": 0.09, diff --git a/vna_system/core/processors/implementations/bscan_processor.py b/vna_system/core/processors/implementations/bscan_processor.py index b3a7077..9e08ba6 100644 --- a/vna_system/core/processors/implementations/bscan_processor.py +++ b/vna_system/core/processors/implementations/bscan_processor.py @@ -16,6 +16,31 @@ from vna_system.core.config import SPEED_OF_LIGHT_M_S logger = get_component_logger(__file__) +# ----------------------------------------------------------------------------- +# Hardcoded notch filter configuration (Hz) +# Keep this list simple for manual on/off by commenting lines. +# If list is empty, filter is bypassed safely. +# ----------------------------------------------------------------------------- +_HARDCODED_NOTCH_BANDS_HZ: list[tuple[float, float]] = [ + (521805341, 559802333), + (565570894, 597568846), + (654160139, 726852100), + (774625224, 866509567), + (923844514, 961841506), + (1710023801, 1762573222), + (1830537144, 1889723898), + (1976018004, 2008015956), + (2095044545, 2133041601), + (2168370432, 2228168766), + (2251665672, 2277664776), + (2308722546, 2346719602), + (2373748986, 2405746938), + (2491168130, 2578479270), + (2647818717, 2698980425), +] +_HARDCODED_NOTCH_TAPER_WIDTH_HZ = 40e6 +_HARDCODED_NOTCH_TAPER_TYPE = "cosine" # "cosine" or "hard" + class BScanProcessor(BaseProcessor): """ @@ -132,7 +157,7 @@ class BScanProcessor(BaseProcessor): label="Макс. глубина (м)", type="slider", value=cfg["max"], - options={"min": 0.1, "max": 5.0, "step": 0.1, "dtype": "float"}, + options={"min": 0.1, "max": 15.0, "step": 0.1, "dtype": "float"}, ), UIParameter( name="gain", @@ -937,6 +962,56 @@ class BScanProcessor(BaseProcessor): self._config["start_freq"] = new_start self._config["stop_freq"] = new_stop + def _apply_hardcoded_notch_filter( + self, + s_complex: NDArray[np.complex128], + freq_hz: NDArray[np.floating], + ) -> tuple[NDArray[np.complex128], NDArray[np.floating]]: + """ + Apply manual hardcoded notch filtering in frequency domain. + + Notes + ----- + - Designed for simple manual editing of frequency bands. + - If `_HARDCODED_NOTCH_BANDS_HZ` is empty, this is a passthrough. + """ + mask = np.ones_like(freq_hz, dtype=float) + bands = _HARDCODED_NOTCH_BANDS_HZ + + if not bands: + return s_complex, mask + + taper_width_hz = float(_HARDCODED_NOTCH_TAPER_WIDTH_HZ) + taper_type = str(_HARDCODED_NOTCH_TAPER_TYPE).lower() + + if taper_width_hz <= 0.0: + taper_type = "hard" + + for f_low, f_high in bands: + trans_low = f_low - taper_width_hz + trans_high = f_high + taper_width_hz + + inside = (freq_hz >= f_low) & (freq_hz <= f_high) + left_edge = (freq_hz >= trans_low) & (freq_hz < f_low) + right_edge = (freq_hz > f_high) & (freq_hz <= trans_high) + + if taper_type == "cosine": + # Left transition: 1 -> 0 + arg_l = np.pi * (freq_hz[left_edge] - trans_low) / taper_width_hz + mask[left_edge] *= 0.5 * (1.0 + np.cos(arg_l)) + + # Right transition: 0 -> 1 + arg_r = np.pi * (freq_hz[right_edge] - f_high) / taper_width_hz + mask[right_edge] *= 0.5 * (1.0 - np.cos(arg_r)) + + mask[inside] = 0.0 + else: + mask[inside] = 0.0 + mask[left_edge] = 0.0 + mask[right_edge] = 0.0 + + return s_complex * mask, mask + def _perform_data_analysis( self, complex_data: NDArray[np.complex128], @@ -963,6 +1038,9 @@ class BScanProcessor(BaseProcessor): # Frequency vector over current data length freq_axis = np.linspace(freq_start, freq_stop, complex_data.size, dtype=float) + # Hardcoded frequency-domain notch filter (manual on/off via comments) + complex_data, _ = self._apply_hardcoded_notch_filter(complex_data, freq_axis) + # print("freq_axis", freq_axis.shape, freq_axis[0], freq_axis[-1]) # Optionally normalize amplitude (phase-only modes)