feat: 邻近高干扰小区数按制式拆分统计
This commit is contained in:
@@ -72,6 +72,13 @@ MIN_INTERFERENCE_BY_SOURCE = {
|
||||
EARTH_RADIUS_KM = 6371.0088
|
||||
NEARBY_RADIUS_KM = 1.0
|
||||
|
||||
NEARBY_COLUMN_BY_NETWORK_TYPE = {
|
||||
"2.6G": "nearby_26g",
|
||||
"700M": "nearby_700m",
|
||||
"TDD": "nearby_tdd",
|
||||
"FDD": "nearby_fdd",
|
||||
}
|
||||
|
||||
DEFAULT_STORAGE_ID = "stg_4d9a910d72"
|
||||
DEFAULT_ROOT = "/网优日常优化数据文档/(勿删)干扰定时小时指标"
|
||||
CELL_DATA_DIRECTORIES = (
|
||||
@@ -192,7 +199,15 @@ SUMMARY_HEADER = (
|
||||
"latitude",
|
||||
"azimuth",
|
||||
"nearby_count",
|
||||
"nearby_26g",
|
||||
"nearby_700m",
|
||||
"nearby_tdd",
|
||||
"nearby_fdd",
|
||||
"prev_nearby_count",
|
||||
"prev_nearby_26g",
|
||||
"prev_nearby_700m",
|
||||
"prev_nearby_tdd",
|
||||
"prev_nearby_fdd",
|
||||
)
|
||||
|
||||
class ProcessingError(RuntimeError):
|
||||
@@ -358,7 +373,7 @@ class ApiSummaryStore:
|
||||
START TRANSACTION;
|
||||
DELETE FROM `{self.table}` WHERE metric_time = {metric_literal};
|
||||
INSERT INTO `{self.table}`
|
||||
(metric_time, network_type, cgi, cell_name, interference_dbm, prev_interference_dbm, longitude, latitude, azimuth, nearby_count, prev_nearby_count)
|
||||
(metric_time, network_type, cgi, cell_name, interference_dbm, prev_interference_dbm, longitude, latitude, azimuth, nearby_count, nearby_26g, nearby_700m, nearby_tdd, nearby_fdd, prev_nearby_count, prev_nearby_26g, prev_nearby_700m, prev_nearby_tdd, prev_nearby_fdd)
|
||||
VALUES
|
||||
{values};
|
||||
DELETE FROM `{self.table}` WHERE metric_time <> {metric_literal};
|
||||
@@ -392,8 +407,7 @@ class ApiSummaryStore:
|
||||
self._ensure_schema()
|
||||
metric_literal = f"'{metric_time:%Y-%m-%d %H:%M:%S}'"
|
||||
sql = (
|
||||
"SELECT metric_time, network_type, cgi, cell_name, interference_dbm, "
|
||||
"prev_interference_dbm, longitude, latitude, azimuth, nearby_count, prev_nearby_count "
|
||||
f"SELECT {', '.join(SUMMARY_HEADER)} "
|
||||
f"FROM `{self.table}` "
|
||||
f"WHERE metric_time = {metric_literal} ORDER BY cgi, cell_name"
|
||||
)
|
||||
@@ -431,7 +445,15 @@ class ApiSummaryStore:
|
||||
latitude DECIMAL(10,6) NULL,
|
||||
azimuth DECIMAL(6,2) NOT NULL DEFAULT 0,
|
||||
nearby_count INT NOT NULL DEFAULT 0,
|
||||
nearby_26g INT NOT NULL DEFAULT 0,
|
||||
nearby_700m INT NOT NULL DEFAULT 0,
|
||||
nearby_tdd INT NOT NULL DEFAULT 0,
|
||||
nearby_fdd INT NOT NULL DEFAULT 0,
|
||||
prev_nearby_count INT NULL,
|
||||
prev_nearby_26g INT NULL,
|
||||
prev_nearby_700m INT NULL,
|
||||
prev_nearby_tdd INT NULL,
|
||||
prev_nearby_fdd INT NULL,
|
||||
PRIMARY KEY (metric_time, cgi)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
""",
|
||||
@@ -451,7 +473,15 @@ class ApiSummaryStore:
|
||||
"latitude": "DECIMAL(10,6) NULL",
|
||||
"azimuth": "DECIMAL(6,2) NOT NULL DEFAULT 0",
|
||||
"nearby_count": "INT NOT NULL DEFAULT 0",
|
||||
"nearby_26g": "INT NOT NULL DEFAULT 0",
|
||||
"nearby_700m": "INT NOT NULL DEFAULT 0",
|
||||
"nearby_tdd": "INT NOT NULL DEFAULT 0",
|
||||
"nearby_fdd": "INT NOT NULL DEFAULT 0",
|
||||
"prev_nearby_count": "INT NULL",
|
||||
"prev_nearby_26g": "INT NULL",
|
||||
"prev_nearby_700m": "INT NULL",
|
||||
"prev_nearby_tdd": "INT NULL",
|
||||
"prev_nearby_fdd": "INT NULL",
|
||||
}
|
||||
for column, definition in migrations.items():
|
||||
if column not in existing_columns:
|
||||
@@ -487,7 +517,15 @@ class ApiSummaryStore:
|
||||
sql_decimal_literal(row["latitude"], "latitude", nullable=True),
|
||||
sql_decimal_literal(row["azimuth"], "azimuth"),
|
||||
str(int(row["nearby_count"])),
|
||||
str(int(row["nearby_26g"])),
|
||||
str(int(row["nearby_700m"])),
|
||||
str(int(row["nearby_tdd"])),
|
||||
str(int(row["nearby_fdd"])),
|
||||
sql_decimal_literal(row["prev_nearby_count"], "prev_nearby_count", nullable=True),
|
||||
sql_decimal_literal(row["prev_nearby_26g"], "prev_nearby_26g", nullable=True),
|
||||
sql_decimal_literal(row["prev_nearby_700m"], "prev_nearby_700m", nullable=True),
|
||||
sql_decimal_literal(row["prev_nearby_tdd"], "prev_nearby_tdd", nullable=True),
|
||||
sql_decimal_literal(row["prev_nearby_fdd"], "prev_nearby_fdd", nullable=True),
|
||||
)
|
||||
) + ")"
|
||||
|
||||
@@ -966,7 +1004,7 @@ def summary_record(
|
||||
interference = required(record, "载波平均噪声干扰(dBm)", source_path, row_number)
|
||||
|
||||
longitude, latitude, azimuth = (cell_metadata or {}).get(cgi, ("", "", "0"))
|
||||
return {
|
||||
record_out = {
|
||||
"metric_time": metric_time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"network_type": NETWORK_TYPE_BY_SOURCE[source_type],
|
||||
"cgi": cgi,
|
||||
@@ -979,6 +1017,10 @@ def summary_record(
|
||||
"nearby_count": "0",
|
||||
"prev_nearby_count": "",
|
||||
}
|
||||
for column in NEARBY_COLUMN_BY_NETWORK_TYPE.values():
|
||||
record_out[column] = "0"
|
||||
record_out[f"prev_{column}"] = ""
|
||||
return record_out
|
||||
|
||||
|
||||
def passes_interference_threshold(record: dict[str, str], source_type: str) -> bool:
|
||||
@@ -992,10 +1034,9 @@ def passes_interference_threshold(record: dict[str, str], source_type: str) -> b
|
||||
|
||||
|
||||
def populate_nearby_counts(rows: list[dict[str, str]]) -> None:
|
||||
counts = [0] * len(rows)
|
||||
type_counts = [dict.fromkeys(NEARBY_COLUMN_BY_NETWORK_TYPE.values(), 0) for _ in rows]
|
||||
spatial_index: dict[tuple[int, int, int], list[tuple[int, float, float]]] = {}
|
||||
for index, row in enumerate(rows):
|
||||
row["nearby_count"] = "0"
|
||||
if not row["longitude"] or not row["latitude"]:
|
||||
continue
|
||||
try:
|
||||
@@ -1006,6 +1047,7 @@ def populate_nearby_counts(rows: list[dict[str, str]]) -> None:
|
||||
if not math.isfinite(longitude) or not math.isfinite(latitude) or not -180 <= longitude <= 180 or not -90 <= latitude <= 90:
|
||||
raise ProcessingError(f"Invalid coordinates for CGI {row['cgi']}")
|
||||
|
||||
column = NEARBY_COLUMN_BY_NETWORK_TYPE[row["network_type"]]
|
||||
bucket = spatial_bucket(longitude, latitude)
|
||||
for x_offset in (-1, 0, 1):
|
||||
for y_offset in (-1, 0, 1):
|
||||
@@ -1013,12 +1055,14 @@ def populate_nearby_counts(rows: list[dict[str, str]]) -> None:
|
||||
nearby_bucket = (bucket[0] + x_offset, bucket[1] + y_offset, bucket[2] + z_offset)
|
||||
for other_index, other_longitude, other_latitude in spatial_index.get(nearby_bucket, ()):
|
||||
if haversine_distance_km(longitude, latitude, other_longitude, other_latitude) <= NEARBY_RADIUS_KM:
|
||||
counts[index] += 1
|
||||
counts[other_index] += 1
|
||||
type_counts[index][NEARBY_COLUMN_BY_NETWORK_TYPE[rows[other_index]["network_type"]]] += 1
|
||||
type_counts[other_index][column] += 1
|
||||
spatial_index.setdefault(bucket, []).append((index, longitude, latitude))
|
||||
|
||||
for index, count in enumerate(counts):
|
||||
rows[index]["nearby_count"] = str(count)
|
||||
for row, counts in zip(rows, type_counts, strict=True):
|
||||
for column, count in counts.items():
|
||||
row[column] = str(count)
|
||||
row["nearby_count"] = str(sum(counts.values()))
|
||||
|
||||
|
||||
def deduplicate_by_cgi(rows: list[dict[str, str]]) -> int:
|
||||
@@ -1038,14 +1082,11 @@ def deduplicate_by_cgi(rows: list[dict[str, str]]) -> int:
|
||||
|
||||
def populate_previous_values(rows: list[dict[str, str]], previous_rows: list[dict[str, str]]) -> None:
|
||||
previous_by_cgi = {row["cgi"]: row for row in previous_rows}
|
||||
copied_columns = ("interference_dbm", "nearby_count", *NEARBY_COLUMN_BY_NETWORK_TYPE.values())
|
||||
for row in rows:
|
||||
previous = previous_by_cgi.get(row["cgi"])
|
||||
if previous is None:
|
||||
row["prev_interference_dbm"] = ""
|
||||
row["prev_nearby_count"] = ""
|
||||
continue
|
||||
row["prev_interference_dbm"] = previous["interference_dbm"]
|
||||
row["prev_nearby_count"] = previous["nearby_count"]
|
||||
for column in copied_columns:
|
||||
row[f"prev_{column}"] = previous[column] if previous is not None else ""
|
||||
|
||||
|
||||
def spatial_bucket(longitude: float, latitude: float) -> tuple[int, int, int]:
|
||||
|
||||
Reference in New Issue
Block a user