feat: 制式标注改为2.6G/700M/TDD/FDD
This commit is contained in:
@@ -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.
|
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.
|
`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.
|
||||||
|
|
||||||
|
|||||||
@@ -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 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.
|
- 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
|
## 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.
|
- 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.
|
||||||
|
|||||||
@@ -48,19 +48,25 @@ EXPECTED_TYPES = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
NETWORK_TYPE_BY_SOURCE = {
|
NETWORK_TYPE_BY_SOURCE = {
|
||||||
"5G下FDD干扰监控": "2.6G",
|
"5G下FDD干扰监控": "FDD",
|
||||||
"5G干扰监控": "2.6G",
|
"5G干扰监控": "2.6G",
|
||||||
"700M下FDD干扰监控": "700M",
|
"700M下FDD干扰监控": "FDD",
|
||||||
"700M干扰监控": "700M",
|
"700M干扰监控": "700M",
|
||||||
"SDR_FDD干扰监控": "4G",
|
"SDR_FDD干扰监控": "FDD",
|
||||||
"SDR_TDD干扰监控": "4G",
|
"SDR_TDD干扰监控": "TDD",
|
||||||
"反开RD干扰监控": "4G",
|
"反开RD干扰监控": "TDD",
|
||||||
}
|
}
|
||||||
|
|
||||||
MIN_INTERFERENCE_BY_NETWORK_TYPE = {
|
# Thresholds keep the original band grouping (the two 5G-directory sources use
|
||||||
"2.6G": Decimal("-107"),
|
# -107, all others -110); they are independent of the network_type label.
|
||||||
"700M": Decimal("-110"),
|
MIN_INTERFERENCE_BY_SOURCE = {
|
||||||
"4G": Decimal("-110"),
|
"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
|
EARTH_RADIUS_KM = 6371.0088
|
||||||
@@ -848,7 +854,7 @@ def process(
|
|||||||
for row_number, row in enumerate(rows, start=2):
|
for row_number, row in enumerate(rows, start=2):
|
||||||
record = dict(zip(header, row, strict=True))
|
record = dict(zip(header, row, strict=True))
|
||||||
summary = summary_record(record, source_type, candidate.path, metric_time, row_number, cell_metadata)
|
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)
|
summary_rows.append(summary)
|
||||||
else:
|
else:
|
||||||
threshold_filtered_rows += 1
|
threshold_filtered_rows += 1
|
||||||
@@ -975,15 +981,14 @@ def summary_record(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def passes_interference_threshold(record: dict[str, str]) -> bool:
|
def passes_interference_threshold(record: dict[str, str], source_type: str) -> bool:
|
||||||
network_type = record["network_type"]
|
|
||||||
try:
|
try:
|
||||||
interference = Decimal(record["interference_dbm"])
|
interference = Decimal(record["interference_dbm"])
|
||||||
except InvalidOperation as exc:
|
except InvalidOperation as exc:
|
||||||
raise ProcessingError(f"Invalid interference value: {record['interference_dbm']}") from exc
|
raise ProcessingError(f"Invalid interference value: {record['interference_dbm']}") from exc
|
||||||
if not interference.is_finite():
|
if not interference.is_finite():
|
||||||
raise ProcessingError(f"Invalid interference value: {record['interference_dbm']}")
|
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:
|
def populate_nearby_counts(rows: list[dict[str, str]]) -> None:
|
||||||
|
|||||||
+12
-4
@@ -62,6 +62,7 @@ class PipelineTest(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
rows_by_cgi = {row["cgi"]: row for row in rows}
|
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-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.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.assertEqual(rows_by_cgi["460-00-200-1"]["cell_name"], "5G干扰监控-小区")
|
||||||
self.assertTrue(all(row["interference_dbm"] == "-100.5" for row in rows))
|
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)
|
self.assertEqual(len(archived_rows), 2)
|
||||||
|
|
||||||
def test_interference_thresholds_remove_only_lower_values(self) -> None:
|
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 = database_row()
|
||||||
row["network_type"] = network_type
|
|
||||||
row["interference_dbm"] = threshold
|
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)
|
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:
|
with tempfile.TemporaryDirectory() as temp:
|
||||||
root = Path(temp) / "source"
|
root = Path(temp) / "source"
|
||||||
|
|||||||
Reference in New Issue
Block a user