InterferenceETL

InterferenceETL follows the newest interference KPI time group in Metrix storage. It reads seven ZIP/XLSX source types, converts each Sheet0 to CSV, and creates one merged high-interference summary.

Source file names are identified by one of the seven fixed prefixes plus a final _YYYYMMDDHHMMHHMM.zip; text between the prefix and time is unrestricted. Only the first YYYYMMDDHHMM start time is used for grouping. Start times are rounded down to natural 15-minute boundaries, so 12:00 through 12:14 belong to 12:00. This also works unchanged when all providers switch together to hourly or daily delivery.

Every run follows only the group containing the newest source start time. It never falls back or backfills an older group. If any source type is missing, the script prints status=waiting with the missing types and exits successfully. When one source has multiple files in the group, its latest start time wins.

Output

Each run writes one window directory:

output/20260731100000/
├── converted/
│   ├── 5G下FDD干扰监控_2026073110001100.csv
│   ├── 5G干扰监控_2026073110001100.csv
│   └── ... seven source CSV files
├── interference_summary_20260731100000.csv
└── manifest.json

For every processed group, the script also reads the latest filename-dated XLSX from each configured CellData directory. It builds CellData CGI as 460-00-{eNB/gNB}-{CI} and adds coordinates plus direction angle to matching interference rows. Unmatched rows keep empty coordinates and use 0 for azimuth.

The summary columns are:

metric_time,network_type,cgi,cell_name,interference_dbm,prev_interference_dbm,longitude,latitude,azimuth,nearby_count,prev_nearby_count

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.

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.

prev_interference_dbm and prev_nearby_count come from the previously retained database time, matched by CGI before the current batch replaces old rows. They represent the same cell's previous-period interference value and nearby high-interference count. On the first run, or when a CGI did not exist in the previous period, both fields are empty in CSV/history output and NULL in MySQL.

The script never modifies or deletes source storage files. Before downloading source ZIP files or CellData, it compares the normalized target time with the database. A target already present, or older than the database, is not processed again.

The database table contains normalized metric_time DATETIME, network_type VARCHAR(16), interference_dbm DECIMAL(10,3), nullable prev_interference_dbm DECIMAL(10,3), nullable longitude and latitude, azimuth DECIMAL(6,2) NOT NULL DEFAULT 0, nearby_count INT NOT NULL DEFAULT 0, and nullable prev_nearby_count INT. A successful transaction replaces the target batch and deletes every other database time, so the table retains only the latest processed group. The previous-period values are read before this replacement transaction.

After the database succeeds, the same eleven result columns are uploaded as GBK CSV to:

/网优日常优化数据文档/(勿删)干扰定时小时指标/干扰历史数据/YYYY-MM-DD/干扰数据处理结果_YYYYMMDDHHMMSS.csv

The filename time comes from normalized metric_time, never the server clock. If the database already contains the target time but its history CSV is missing or empty, the script exports that time from the database and repairs the history file without reprocessing source data.

All generated CSV files use GBK without a UTF-8 BOM, including the seven converted source files, the merged summary, and the uploaded history file. Source non-breaking spaces (U+00A0) are normalized to ordinary spaces because GBK cannot encode them; other unsupported characters still fail the run instead of being silently replaced. manifest.json remains UTF-8 JSON.

CGI is generated with fixed rules:

  • NR (5G干扰监控, 700M干扰监控): {gNBplmn}-{gNBId}-{cellId}.
  • 4G (the other five source types): 460-00-{eNodeBID}-{小区ID}, using each source schema's actual equivalent column names.

The Metrix API address, API Token, and database connection ID are constants in runtime_config.py; they are not project environment variables. Copy runtime_config.example.py to runtime_config.py and fill in the actual Token and the conn_id of ShareMySQL. The fixed database is interference_etl, the fixed table is interference_hourly_summary, and the script creates both automatically when they do not exist.

The five CellData directories are fixed in CELL_DATA_DIRECTORIES. In each directory, only XLSX files ending with a valid YYYYMMDD.xlsx date are considered, and the latest date is selected. CellData column 方向角 maps to summary/database column azimuth; an empty source value becomes 0.

Local development

python -m pip install -r requirements.txt
python -m unittest discover -s tests -v
python main.py --source-dir C:\path\to\mock-or-exported-tree --output-dir output --no-database

Use --window 2026073110001100 to select the natural 15-minute group containing that source start time. Without it, the newest observed source start time determines the group. Incomplete groups wait and never fall back.

Metrix Script Management

The target server is offline. Build the dependency image locally, then generate a self-contained Script Management upload ZIP:

docker build -t interference-etl-runtime:1.1 .
python scripts\build_offline_package.py

The generated dist/InterferenceETL-offline-1.1.zip contains main.py, runtime_config.py, a ZIP execution entry point, and a vendor/ directory containing openpyxl and et_xmlfile. The builder verifies imports and ZIP execution using the standard python:3.13.11-slim image, so the uploaded workspace does not need an online pip install or a custom runtime image. The build fails when runtime_config.py is missing.

Create the project, then upload and extract the ZIP in its Script Management workspace. The normal file tree should contain main.py at /workspace/main.py. Use these project settings:

Name: InterferenceETL
Language: python
Base image: python:3.13.11-slim
Network: bridge
Run command: python main.py
Timeout: 1800 seconds

If the server keeps the ZIP as one file instead of extracting it, use python InterferenceETL-offline-1.1.zip as the run command. The ZIP contains __main__.py for this mode.

Configure only run-specific source and output settings in the project environment:

{
  "METRIX_STORAGE_ID": "stg_4d9a910d72",
  "INTERFERENCE_SOURCE_ROOT": "/网优日常优化数据文档/(勿删)干扰定时小时指标",
  "INTERFERENCE_OUTPUT_DIR": "/workspace/output",
  "INTERFERENCE_LOOKBACK_DAYS": "3"
}

Both storage reads and database writes use the Metrix API at http://188.5.127.115:18271. SSH remains the deployment and operational channel for uploading files, starting runs, and reading logs.

CLI options

--source-dir PATH      Read a local directory tree instead of Metrix API
--output-dir PATH      Output root, default output or INTERFERENCE_OUTPUT_DIR
--window WINDOW        Select the natural 15-minute group for a 16-digit source window
--lookback-days N      Number of newest date directories scanned, default 3
--storage-id ID        Metrix storage connection ID
--root PATH            Source directory in Metrix storage
--no-database          Generate CSV files without writing the database
S
Description
No description provided
Readme
132 KiB
Languages
Python 99.8%
Dockerfile 0.2%