From eca4c5cbb15645ed44d3e34f0afd6c3d04d12cc6 Mon Sep 17 00:00:00 2001 From: Nixevol Date: Tue, 11 Aug 2026 16:45:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=B6=E5=BC=8F=E6=A0=87=E6=B3=A8?= =?UTF-8?q?=E6=94=B9=E4=B8=BA2.6G/700M/TDD/FDD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- aidocs/project_context.md | 7 +++++++ main.py | 31 ++++++++++++++++++------------- tests/test_pipeline.py | 16 ++++++++++++---- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7d61961..42deb69 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ metric_time,network_type,cgi,cell_name,interference_dbm,prev_interference_dbm,lo All selected workbook rows must belong to the selected natural 15-minute group. Every summary row receives the same normalized `metric_time`; a row outside the group fails the run before database or history output. -`network_type` is derived from the seven source types: both `5G...` sources are `2.6G`, both `700M...` sources are `700M`, and SDR/反开 sources are `4G`. The summary and database keep only high-interference rows: `2.6G >= -107 dBm` and `700M/4G >= -110 dBm`. Converted source CSV files remain full source conversions. +`network_type` is derived from the seven source types: `5G干扰监控` is `2.6G`, `700M干扰监控` is `700M`, `SDR_TDD干扰监控` and `反开RD干扰监控` are `TDD`, and `SDR_FDD干扰监控`, `5G下FDD干扰监控`, and `700M下FDD干扰监控` are `FDD`. The summary and database keep only high-interference rows. Thresholds keep the original directory grouping and are independent of the `network_type` label: the two `5G...` sources use `>= -107 dBm`, and the other five sources use `>= -110 dBm`. Converted source CSV files remain full source conversions. `nearby_count` is the number of other high-interference cells from the same selected time group within 1 km, across all network types. The cell itself is excluded, the 1 km boundary is included, and rows without coordinates use `0`. Candidate cells are found through a 1 km spatial grid index and confirmed with exact Haversine distance. diff --git a/aidocs/project_context.md b/aidocs/project_context.md index d4dede8..66943ae 100644 --- a/aidocs/project_context.md +++ b/aidocs/project_context.md @@ -109,6 +109,13 @@ - The current `2026-08-07 14:00:00` database result was exported directly through the history-only path and replaced in Storage as a verified GBK CSV: 1,082 rows, 150,251 bytes, no UTF-8 BOM, and the expected eleven columns. The temporary UTF-8 backup was deleted after validation. - The newer `2026-08-07 15:00:00` source group currently contains duplicate CGI rows, for example `460-00-122737-22`. Its database transaction rolled back on the existing `(metric_time, cgi)` primary key, so the retained `14:00` database and history result were not replaced. Duplicate-row selection requires a separate business rule. +## 2026-08-11: Network type relabeled to 2.6G/700M/TDD/FDD + +- `network_type` keeps its column name but now labels radio type per source prefix: `5G干扰监控` is `2.6G` (the user treats 2.6G as the unambiguous 5G label because 700M is also 5G), `700M干扰监控` is `700M`, `SDR_TDD干扰监控` and `反开RD干扰监控` are `TDD`, and the three FDD-schema sources (`SDR_FDD干扰监控`, `5G下FDD干扰监控`, `700M下FDD干扰监控`) are `FDD`. The old `2.6G/700M/4G` grouping is gone. +- Real source filenames only carry these keywords in the fixed prefix; the middle text (for example `LWP_每小时_过滤110`) has no usable network keyword. +- High-interference thresholds are unchanged and now keyed per source type through `MIN_INTERFERENCE_BY_SOURCE`: the two 5G-directory sources keep `-107` and the other five keep `-110`, so relabeling `5G下FDD干扰监控` to `FDD` does not change which rows are kept. +- No database migration is needed: the column type stays `VARCHAR(16)` and old-label rows disappear on the next successful replacement run. Twenty-two tests pass locally. + ## 2026-08-07: Duplicate CGI selection - Retained high-interference rows are deduplicated by CGI before nearby counting and database insertion. When duplicates exist, the row with the numerically largest `interference_dbm` is kept; equal values keep the first encountered row. Converted source CSVs remain complete. diff --git a/main.py b/main.py index 67b5df0..38db6f2 100644 --- a/main.py +++ b/main.py @@ -48,19 +48,25 @@ EXPECTED_TYPES = ( ) NETWORK_TYPE_BY_SOURCE = { - "5G下FDD干扰监控": "2.6G", + "5G下FDD干扰监控": "FDD", "5G干扰监控": "2.6G", - "700M下FDD干扰监控": "700M", + "700M下FDD干扰监控": "FDD", "700M干扰监控": "700M", - "SDR_FDD干扰监控": "4G", - "SDR_TDD干扰监控": "4G", - "反开RD干扰监控": "4G", + "SDR_FDD干扰监控": "FDD", + "SDR_TDD干扰监控": "TDD", + "反开RD干扰监控": "TDD", } -MIN_INTERFERENCE_BY_NETWORK_TYPE = { - "2.6G": Decimal("-107"), - "700M": Decimal("-110"), - "4G": Decimal("-110"), +# Thresholds keep the original band grouping (the two 5G-directory sources use +# -107, all others -110); they are independent of the network_type label. +MIN_INTERFERENCE_BY_SOURCE = { + "5G下FDD干扰监控": Decimal("-107"), + "5G干扰监控": Decimal("-107"), + "700M下FDD干扰监控": Decimal("-110"), + "700M干扰监控": Decimal("-110"), + "SDR_FDD干扰监控": Decimal("-110"), + "SDR_TDD干扰监控": Decimal("-110"), + "反开RD干扰监控": Decimal("-110"), } EARTH_RADIUS_KM = 6371.0088 @@ -848,7 +854,7 @@ def process( for row_number, row in enumerate(rows, start=2): record = dict(zip(header, row, strict=True)) summary = summary_record(record, source_type, candidate.path, metric_time, row_number, cell_metadata) - if passes_interference_threshold(summary): + if passes_interference_threshold(summary, source_type): summary_rows.append(summary) else: threshold_filtered_rows += 1 @@ -975,15 +981,14 @@ def summary_record( } -def passes_interference_threshold(record: dict[str, str]) -> bool: - network_type = record["network_type"] +def passes_interference_threshold(record: dict[str, str], source_type: str) -> bool: try: interference = Decimal(record["interference_dbm"]) except InvalidOperation as exc: raise ProcessingError(f"Invalid interference value: {record['interference_dbm']}") from exc if not interference.is_finite(): raise ProcessingError(f"Invalid interference value: {record['interference_dbm']}") - return interference >= MIN_INTERFERENCE_BY_NETWORK_TYPE[network_type] + return interference >= MIN_INTERFERENCE_BY_SOURCE[source_type] def populate_nearby_counts(rows: list[dict[str, str]]) -> None: diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index f89c97b..80e343f 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -62,6 +62,7 @@ class PipelineTest(unittest.TestCase): ) rows_by_cgi = {row["cgi"]: row for row in rows} self.assertEqual(rows_by_cgi["460-00-200-1"]["network_type"], "2.6G") + self.assertEqual(rows_by_cgi["460-00-100-1"]["network_type"], "FDD") self.assertTrue(all(row["metric_time"] == "2026-07-31 10:00:00" for row in rows)) self.assertEqual(rows_by_cgi["460-00-200-1"]["cell_name"], "5G干扰监控-小区") self.assertTrue(all(row["interference_dbm"] == "-100.5" for row in rows)) @@ -97,13 +98,20 @@ class PipelineTest(unittest.TestCase): self.assertEqual(len(archived_rows), 2) def test_interference_thresholds_remove_only_lower_values(self) -> None: - for network_type, threshold in (("2.6G", "-107"), ("700M", "-110"), ("4G", "-110")): + for source_type, threshold in ( + ("5G干扰监控", "-107"), + ("5G下FDD干扰监控", "-107"), + ("700M干扰监控", "-110"), + ("700M下FDD干扰监控", "-110"), + ("SDR_FDD干扰监控", "-110"), + ("SDR_TDD干扰监控", "-110"), + ("反开RD干扰监控", "-110"), + ): row = database_row() - row["network_type"] = network_type row["interference_dbm"] = threshold - self.assertTrue(main.passes_interference_threshold(row)) + self.assertTrue(main.passes_interference_threshold(row, source_type)) row["interference_dbm"] = str(float(threshold) - 0.1) - self.assertFalse(main.passes_interference_threshold(row)) + self.assertFalse(main.passes_interference_threshold(row, source_type)) with tempfile.TemporaryDirectory() as temp: root = Path(temp) / "source"