diff --git a/CellData.sql b/CellData.sql index 793f6ea..b826dc2 100644 --- a/CellData.sql +++ b/CellData.sql @@ -1,3 +1,105 @@ -UPDATE cellinfo SET `带宽` = IF(`带宽` IS NULL OR `带宽` = '', '0M', CONCAT(REPLACE(UPPER(`带宽`),'M',''), 'M')); - -# 后续实现通过cellinfo表处理为扇区表,支撑扇区容量分析 \ No newline at end of file +-- ============================================================================= +-- CellData 数据处理脚本(在 celldata 库执行) +-- 1) 规范化 cellinfo.带宽 +-- 2) 重建频段特征库 sector_band_ref(频点/PLMN -> 制式/频段 对应表) +-- 3) 由 cellinfo 逆推 sector(扇区/物理站/制式/频段/带宽/站型/网络) +-- —— 不清空 sector,仅补充缺失 CGI,已有行(含人工修正)保留不覆盖 +-- 逆推规则与准确率见 docs/sector_inference_research.md +-- ============================================================================= + +-- 1. 带宽规范化:空值补 0M,统一大写并以 M 结尾(如 20M) +UPDATE cellinfo SET `带宽` = IF(`带宽` IS NULL OR `带宽` = '', '0M', CONCAT(REPLACE(UPPER(`带宽`),'M',''), 'M')); + +-- 2. 频段特征库:网络 + 频点区间(+PLMN) -> 制式/频段 +-- 700M 与 广电 同频点 763.25,由 PLMN 区分(460-00=移动700M,460-15=中国广电) +-- D频 与 3DMM 同频点同 PLMN 同带宽,cellinfo 无法区分,统一判 D频(3DMM 为天线属性) +DROP TABLE IF EXISTS sector_band_ref; +CREATE TABLE sector_band_ref ( + `网络` varchar(8), + f_lo decimal(10,2), + f_hi decimal(10,2), + plmn varchar(16) NULL, + `制式` varchar(20), + `频段` varchar(20) +); +INSERT INTO sector_band_ref (`网络`,f_lo,f_hi,plmn,`制式`,`频段`) VALUES +('5G',4000,99999,NULL,'4.9G','4.9G'), +('5G',700,800,'460-00','700M','700M'), +('5G',700,800,'460-15','广电','广电'), +('5G',2000,3000,NULL,'2.6G','2.6G'), +('4G',900,1000,NULL,'FDD','FDD900'), +('4G',1000,1880,NULL,'FDD','FDD1800'), +('4G',1880,1920,NULL,'TDD','F频'), +('4G',1920,2110,NULL,'TDD','A频'), +('4G',2300,2400,NULL,'TDD','E频'), +('4G',2400,2700,NULL,'TDD','D频'); + +-- 3. 逆推暂存表:预处理小区名称(全角括号->半角、【】->()、去空格/制表符) +DROP TABLE IF EXISTS _sector_infer; +CREATE TABLE _sector_infer AS +SELECT + c.CGI, c.`网络`, c.`带宽`, c.PLMN, c.`频点`, c.`制式` AS ci_zs, + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + c.`小区名称`,' ',''),CHAR(9),''),' ',''),'(','('),')',')'),'【','('),'】',')') AS name1 +FROM cellinfo c; + +ALTER TABLE _sector_infer + ADD COLUMN `制式` varchar(20), + ADD COLUMN `频段` varchar(20), + ADD COLUMN `站型` varchar(10), + ADD COLUMN numstr varchar(20), + ADD COLUMN base varchar(220), + ADD COLUMN `物理站` varchar(200), + ADD COLUMN `扇区` varchar(210); + +-- 3.1 设备码([频率前缀]-Z[xx]-[扇区号])剥离得到 base;尾部数字串;站型判定 +-- 站型:设备码尾字母 W=室分;名称含"微小"=微站;其余=宏站 +UPDATE _sector_infer SET + base = REGEXP_REPLACE(name1,'[A-Z0-9]+-Z[A-Z0-9]{2}-[0-9]+$',''), + numstr = REGEXP_SUBSTR(name1,'[0-9]+$'), + `站型` = CASE + WHEN name1 REGEXP 'Z[A-Z]W-[0-9]+$' THEN '室分' + WHEN name1 LIKE '%微小%' THEN '微站' + ELSE '宏站' END; + +-- 3.2 制式/频段:按特征库匹配;未命中回落 cellinfo 原制式 +UPDATE _sector_infer t +JOIN sector_band_ref r + ON r.`网络` = t.`网络` + AND CAST(NULLIF(t.`频点`,'') AS DECIMAL(10,2)) >= r.f_lo + AND CAST(NULLIF(t.`频点`,'') AS DECIMAL(10,2)) < r.f_hi + AND (r.plmn IS NULL OR r.plmn = t.PLMN) +SET t.`制式` = r.`制式`, t.`频段` = r.`频段`; +UPDATE _sector_infer SET `制式` = ci_zs, `频段` = ci_zs WHERE `制式` IS NULL; + +-- 3.3 物理站(非 700M/广电):去码后删全部括号注记,保留(微小X)并回贴; +-- 再去掉不闭合的悬空开括号与孤立右括号 +UPDATE _sector_infer SET `物理站` = CONCAT( + TRIM(REGEXP_REPLACE(REGEXP_REPLACE(REGEXP_REPLACE(REGEXP_REPLACE(REGEXP_REPLACE(REGEXP_REPLACE( + base,'\\([^()]*\\)',''),'\\([^()]*\\)',''),'\\([^()]*\\)',''),'\\([^()]*$',''),'[)]+$',''),'^[)]+','')), + IFNULL(REGEXP_SUBSTR(name1,'[(]微小[A-Z]?[)]'),'')) +WHERE `制式` IS NULL OR `制式` NOT IN ('700M','广电'); + +-- 3.4 物理站(700M/广电):取以"(江门"开头的括号内容为真实站址; +-- 无则取外层(去 CBN- 前缀与注记)。括号内容以"共"开头属共建标注,归外层 +UPDATE _sector_infer SET `物理站` = + CASE WHEN REGEXP_SUBSTR(base,'\\(江门[^()]*') <> '' + THEN TRIM(SUBSTRING(REGEXP_SUBSTR(base,'\\(江门[^()]*'),2)) + ELSE TRIM(REGEXP_REPLACE(REGEXP_REPLACE(base,'\\(.*$',''),'^CBN-?','')) END +WHERE `制式` IN ('700M','广电'); + +-- 3.5 扇区 = 物理站 + 扇区号(700M/广电取末位数字;其余取数字串 % 100) +UPDATE _sector_infer SET `扇区` = CONCAT(`物理站`, + CASE WHEN numstr IS NULL OR numstr = '' THEN '' + WHEN `制式` IN ('700M','广电') THEN RIGHT(numstr,1) + ELSE CAST(CAST(numstr AS UNSIGNED) % 100 AS CHAR) END); + +-- 4. 补缺写回 sector:仅插入 sector 中尚不存在的 CGI(区域留空,不参与逆推) +-- 已存在的 CGI 一律保留,避免人工修正(如 3DMM、人工纠正的物理站/带宽)被覆盖 +INSERT INTO sector (CGI,`扇区`,`物理站`,`区域`,`制式`,`频段`,`带宽`,`站型`,`网络`) +SELECT i.CGI, i.`扇区`, i.`物理站`, NULL, i.`制式`, i.`频段`, i.`带宽`, i.`站型`, i.`网络` +FROM _sector_infer i +LEFT JOIN sector s ON s.CGI = i.CGI +WHERE s.CGI IS NULL; + +DROP TABLE _sector_infer; diff --git a/docs/project_context.md b/docs/project_context.md index bfbd6e8..2575a3a 100644 --- a/docs/project_context.md +++ b/docs/project_context.md @@ -972,6 +972,15 @@ CellData 处理日志细化(`app/services/cell_data.py`): - 同扇区同运营商小区每项加详情图标按钮(`OpenOutline`),点击 `openDetail(sib.id)` 在抽屉内切换到该小区详情;`.cap-sib-item` 改 flex 行(`.cap-sib-body` 占主 + 右侧 `.cap-icon-btn`)。新增通用 `.cap-icon-btn` 样式(复制/详情共用)。 - 验证:`frontend` `vue-tsc --noEmit` 通过。 +## 2026-06-26:CellData.sql 新增 cellinfo→sector 逆推(特征库 + 补缺不覆盖) + +- 背景:`celldata.cellinfo`(自动处理、有数据源)→ `celldata.sector`(原人工整理)。新脚本自动逆推 sector 的 扇区/物理站/制式/频段/带宽/站型/网络(区域留空,最终不用)。 +- 特征库 `sector_band_ref`(频点区间+PLMN→制式/频段,10 条):700M/广电同频 763.25 用 PLMN 区分(460-00/460-15);4.9G 用频点≥4000;4G FDD900/1800、TDD F/A/E/D 频按频点分档。**D频与3DMM 同频同PLMN同带宽不可区分**,统一判 D频(3DMM 为天线属性)。 +- 逆推 staging `_sector_infer`:预处理小区名(全角括号→半角、【】→()、去空格/制表符)→ 剥设备码正则 `[A-Z0-9]+-Z[A-Z0-9]{2}-[0-9]+$` 得 base;站型(码尾 W=室分 / 名称含"微小"=微站 / 否则宏站);制式频段经特征表 JOIN(未命中回落 cellinfo 制式);物理站(非700M 删全部成对括号+清悬空+回贴(微小X);700M 取"(江门"括号内容否则外层去CBN-);扇区=物理站+扇区号(700M 末位/其余 %100)。 +- 落库:`INSERT` 仅补 sector 中缺失 CGI(**不清空、不覆盖**已有行,保人工修正如 3DMM/15M/纠正物理站),末尾 DROP staging;`sector_band_ref` 作为持久特征库保留。 +- 准确率(MCP 实测,重叠 66001):网络 100%、制式 97.88%(排除 3DMM 即 100%)、频段 97.6%、带宽 99.75%、站型 99.94%、**物理站 99.59%、扇区 99.20%**;残差为不可还原的人工差异(室分多载波编号、700M 个别人工编号、源数据制表符等)。详见 `docs/sector_inference_research.md`。 +- 关键坑:MySQL 字符串字面量会吞掉未知转义的反斜杠,正则字面量需写 `\\(`(.sql 文件)/ JSON 调用需 `\\\\(`;ICU 正则字符类内的 `[ ]` 易误判,统一把名称中的 `[]` 转 `()` 后只处理圆括号。 + ## 2026-06-26:离线可用性全面审计(运行期零外网) 结论:**运行期已完全离线就绪,无需改运行时代码**;外网仅「构建期」需要。审计证据: diff --git a/docs/sector_inference_research.md b/docs/sector_inference_research.md new file mode 100644 index 0000000..c7a78db --- /dev/null +++ b/docs/sector_inference_research.md @@ -0,0 +1,139 @@ +# cellinfo → sector 逆推调研笔记 + +> 目标:用 `celldata.cellinfo`(自动处理、有数据源)逆推出 `celldata.sector`(人工据 cellinfo 整理)。 +> 现有 sector 作为基准/参考。逆推时**不清空** sector:仅补充缺失 CGI,已有的保留(避免人工纠正被自动运行冲掉)。 +> 脚本与特征库写入 `CellData.sql`。本文件记录字段映射、规则、每轮测试的优化点与准确率。 + +## 一、两表结构(celldata) + +cellinfo(数据源,66778 行):`CGI, eNodeBID, CellID, PLMN, 基站名称, 小区名称, 频点, 带宽, 制式, 功率, 网络` +sector(目标,66969 行):`CGI, 扇区, 物理站, 区域, 制式, 频段, 带宽, 站型, 网络` + +连接键:`CGI`。sector 比 cellinfo 多 ~191 行(历史/其他来源),逆推以 cellinfo 为准。 + +## 二、字段来源结论 + +| sector 字段 | 来源 | 说明 | +|---|---|---| +| CGI | 复制 cellinfo.CGI | 连接键 | +| 网络 | 复制 cellinfo.网络 | 4G / 5G | +| 带宽 | 复制 cellinfo.带宽 | cellinfo 已规范化为如 `20M` | +| 区域 | **留空(不推理)** | 用户确认最终不使用该字段 | +| 制式 + 频段 | 频点 + PLMN 推导(特征表) | 见三 | +| 站型 | 名称关键字 + 设备码推导 | 见四 | +| 物理站 | 小区名称解析 | 见五 | +| 扇区 | 物理站 + 扇区号 | 扇区号见五 | + +## 三、频点 → 制式 / 频段(特征库核心) + +cellinfo.制式 已给出粗类(FDD/TDD/700M/2.6G),频段再按频点细分;个别需 PLMN 区分: + +| 网络 | 频点范围 | PLMN | 制式 | 频段 | 实测样本 | +|---|---|---|---|---|---| +| 5G | ≥4000 | 任意 | 4.9G | 4.9G | 4827.36、4919.52 | +| 5G | 700–800 | 460-00 | 700M | 700M | 763.25(移动)9808 | +| 5G | 700–800 | 460-15 | 广电 | 广电 | 763.25(广电)9802 | +| 5G | 2000–3000 | 任意 | 2.6G | 2.6G | 2524.95 等 | +| 4G | 900–1000 | 任意 | FDD | FDD900 | 939.0 | +| 4G | 1000–1880 | 任意 | FDD | FDD1800 | 1810–1827 | +| 4G | 1880–1920 | 任意 | TDD | F频 | 1895.0、1909.4 | +| 4G | 1920–2110 | 任意 | TDD | A频 | 2017.5 | +| 4G | 2300–2400 | 任意 | TDD | E频 | 2330、2349.8、2364.6 | +| 4G | 2400–2700 | 任意 | TDD | D频 | 2624.6 等 | + +**关键歧义** +1. **700M vs 广电**:同频点 763.25,由 **PLMN** 区分(460-00=移动 700M,460-15=中国广电)。✅ 可完美区分。 +2. **D频 vs 3DMM**:同频点(2624.6 等)、同 PLMN(460-00)、同带宽(20M)、功率也重叠(18.2 两类都有)。**cellinfo 无法可靠区分**——3DMM 是 3D-MIMO 天线属性,非频点/名称可还原。逆推统一归 `TDD/D频`;现有 sector 中的 3DMM 因「不覆盖已有行」而保留,新增行只能判 D频(已知局限)。 + +## 四、站型规则(实测覆盖度) + +| 站型 | 规则 | 命中 | 总数 | 备注 | +|---|---|---|---|---| +| 室分 | 小区名设备码尾 `Z[A-Z]W`(如 ZLW/ZRW/ZFW,末字母 W) | 10146 | 10168 | 99.8% | +| 微站 | 小区名含「微小」(如 (微小M)/(微小I)) | 1086 | 1086 | 100% | +| 宏站 | 其余(设备码尾 H,如 Z5H/ZLH/ZFH,且无微小) | — | 54747 | 仅 18 行宏站名含微小(误差≈0.03%) | + +判定顺序:室分(W 码) → 微站(微小) → 宏站。W 码与微小在数据中互斥。 + +## 五、物理站 / 扇区解析 + +预处理(仅为解析可靠):全角 `()【】`→半角 `()[]`、去空格。 + +**设备码**(位于小区名尾部):`<频率前缀>-Z<尾字母>-<扇区号>`,正则 `[A-Z0-9]+-Z[A-Z0-9]{2}-[0-9]+$`。 +- 频率前缀:U / E / D / F / DC / RD / RDC 等;尾字母 H=室外(宏/微)、W=室分。 +- 例:`U-Z5H-0711`、`E-ZLW-8`、`D-ZRH-103`、`F-ZLH-3`、`RDC-ZFH-2`。 + +**扇区号**(取小区名尾部数字串): +- 700M/广电(Z5H 码):取**末位数字**。`0711`→1、`0712`→2、`0713`→3、`30712`→2。 +- 其余:取数字串 **% 100**。`-3`→3、`-103`→3、`-113`→13、`-203`→3、`-16`→16。 + +**物理站**: +- **非 700M**:= 小区名去设备码后,删除所有括号/方括号内容,但**保留 `(微小X)`**。 + - 例 `江门台山河东家禽(从…搬迁)(微小M)(共…F-ZLH)F-ZLH-2` → `江门台山河东家禽(微小M)`。 + - 例 `江门鹤山坚美园52至53栋(共…E-ZLW)E-ZLW-8` → `江门鹤山坚美园52至53栋`。 +- **700M/广电**:名称结构 `CBN-<枢纽>(<真实站址>)<码>` 或 `CBN-<站址><码>`。 + - 去码后取**最后一个括号内容**作为物理站;若该内容**以「共」开头**(共建标注,如 `(共…E-ZLW)`)则改取**括号前的外层**(去 `CBN-` 前缀);无括号则取外层去 `CBN-`。 + - 取到的内容再删除其内部子括号(如 `(搬迁)(重建)`)。 + - 注意:`共和` 等地名(括号内容以「江门」开头、共字在中间)**不算共建**,仍取内层。 + - 例 `CBN-江门新会圭阳路(江门新会雍翠峰(搬迁))U-Z5H-0712` → `江门新会雍翠峰`。 + - 例 `CBN-江门台山通济公园U-Z5H-0713` → `江门台山通济公园`。 + - 例 `CBN-江门鹤山铸德(江门鹤山共和鸿江工业区)U-Z5H-0712` → `江门鹤山共和鸿江工业区`。 + +**扇区** = 物理站 + 扇区号(如 `江门新会五和农村二` + `1` = `江门新会五和农村二1`)。 + +> 括号宽度:现有 sector 的 `(微小X)` 用全角 `()`。逆推统一转半角输出;对比准确率时两侧都做括号归一化,衡量语义正确性而非宽度。 + +## 六、测试与准确率(逐轮更新) + +测试方法:在 celldata 建 `sector_band_ref` 特征表 + `_sector_infer` 暂存表逐字段推导, +JOIN 现有 `sector`(重叠 CGI **n=66001**)逐字段比对;物理站/扇区比对时两侧做括号+空白归一化。 + +### Round 1(基础规则) +| 字段 | 准确率 | +|---|---| +| 网络 | 100%(66001)| +| 带宽 | 99.75%(65838)| +| 制式 | 97.88%(64601)| +| 频段 | 97.60%(64417)| +| 站型 | 99.94%(65963)| +| 物理站 | 99.12%(65419)| +| 扇区 | 98.72%(65159)| + +失配定位: +- 制式失配 **100% 是 TDD↔3DMM**(1400)——同频/同 PLMN/同带宽/功率重叠,不可还原。 +- 频段失配 = 3DMM(1400) + F频↔A频(162,1895/1909 同频人工分档) + E频↔D频(22)。 +- 带宽失配主要 cellinfo=20M 而人工=15M(155,源数据人工修正)。 +- 站型失配 38:20 个室分码为 `Z[A-Z]R`(如 E-ZLR,高铁 SM 站)未被 W 规则覆盖;18 个宏站名含"微小"被误判微站。 +- 物理站/扇区失配:700M 多括号/不闭合、非 700M 共建/拉远不闭合括号。 + +### Round 2(物理站 v2/v3:按关键字保留限定括号)——失败回退 +尝试只删"共/从/拉远/搬迁…"备注括号、保留 `(龙山路)(红线内)(1)`,物理站反降到 ~98.2%。 +原因:① 末尾 `[)]+$` 误删了 `(微小M)` 等合法括号的右括号;② 大量无备注关键字的别名括号本应删除却被保留,净损失。结论:**"删全部括号+回贴微小"才是最优主策略**。 + +### Round 3(v4:删全部括号 + 悬空清理 + 700M 取"(江门"内容)——定稿 +- 非 700M:去码 → 删全部成对括号(3 轮) → 删悬空开括号 `\([^()]*$` → 删孤立 `)` → 回贴 `(微小X)`。 +- 700M/广电:取 `(江门…` 括号内容;无则取外层去 `CBN-`("共"开头自然落外层)。 +- 扇区号:700M 末位;其余 %100。 + +| 字段 | 准确率 | 说明 | +|---|---|---| +| 网络 | 100% | 复制 | +| 制式 | 97.88%(排除 3DMM 即 **100%**)| 仅差不可还原的 3DMM | +| 频段 | 97.60% | 差额=3DMM+同频 F/A、E/D 人工分档 | +| 带宽 | 99.75% | 差额为人工把 20M 改 15M | +| 站型 | 99.94% | | +| 物理站 | **99.59%**(65728)| | +| 扇区 | **99.20%**(65470)| | + +剩余残差为**不可还原的人工差异**,不再继续拟合(避免过拟合): +- 室分多载波编号不一致:`E-ZLW-12→2`、`-111→1`、`-115→5`(末位)与 `-16→16`(%100)并存;脚本按用户既定 %100。 +- 700M 个别人工编号:`0713→1`、`0712→4`、`0712→空`,与名义 071N→N 规则冲突。 +- 物理站个别含区域前缀(`柏怡酒店`↔`江海柏怡酒店`)、保留 `(龙山路)/(1)` 等;真实数据存在尾随制表符。 +- 因"不覆盖已有行",上述人工值在自动运行中均被保留,不受影响。 + +### 落库策略 +仅 `INSERT` sector 中缺失的 CGI(本次快照 **921 条**),已有 CGI 一律保留。区域留空。 + +### 复现实测命令(celldata) +按 `CellData.sql` 顺序执行即可;准确率核验 SQL: +`SELECT 物理站/扇区 归一化后 = sector 对应值 的占比 FROM _sector_infer JOIN sector USING(CGI)`。