DavMelchi commited on
Commit
d269960
·
1 Parent(s): bcc0fd9

GSM CAPACITY initial commit

Browse files
apps/kpi_analysis/gsm_capacity.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import plotly.express as px
3
+ import streamlit as st
4
+
5
+ from process_kpi.process_gsm_capacity import GsmCapacity, analyze_gsm_data
6
+ from utils.convert_to_excel import ( # Import convert_dfs from the appropriate module
7
+ convert_dfs,
8
+ convert_gsm_dfs,
9
+ )
10
+
11
+ st.title(" 📊 GSM Capacity Analysis")
12
+ doc_col, image_col = st.columns(2)
13
+
14
+ with doc_col:
15
+ st.write(
16
+ """
17
+ The report should be run with a minimum of 3 days of data.
18
+ - Daily Aggregated
19
+ - Site level
20
+ - Exported in CSV format.
21
+ """
22
+ )
23
+
24
+ with image_col:
25
+ st.image("./assets/gsm_capacity.png", width=250)
26
+
27
+ file1, file2, file3 = st.columns(3)
28
+
29
+ with file1:
30
+ uploaded_dump = st.file_uploader("Upload Dump file in xlsb format", type="xlsb")
31
+ with file2:
32
+ uploaded_daily_report = st.file_uploader(
33
+ "Upload Daily Report in CSV format", type="csv"
34
+ )
35
+ with file3:
36
+ uploaded_bh_report = st.file_uploader(
37
+ "Upload Busy Hour Report in CSV format", type="csv"
38
+ )
39
+
40
+
41
+ col1, col2 = st.columns(2)
42
+
43
+ threshold_col1, threshold_col2 = st.columns(2)
44
+ threshold_col3, threshold_col4 = st.columns(2)
45
+
46
+ if (
47
+ uploaded_dump is not None
48
+ and uploaded_daily_report is not None
49
+ and uploaded_bh_report is not None
50
+ ):
51
+ # WbtsCapacity.final_results = None
52
+ with col1:
53
+ number_of_kpi_days = st.number_input(
54
+ "Number of days for analysis",
55
+ min_value=3,
56
+ max_value=30,
57
+ value=7,
58
+ )
59
+ with col2:
60
+ number_of_threshold_days = st.number_input(
61
+ "Number of days for threshold",
62
+ min_value=1,
63
+ max_value=30,
64
+ value=3,
65
+ )
66
+
67
+ with threshold_col1:
68
+ availability_threshold = st.number_input(
69
+ "Availability Threshold", min_value=1, max_value=100, value=95
70
+ )
71
+ with threshold_col2:
72
+ tch_abis_fails_threshold = st.number_input(
73
+ "TCH ABIS Fails Threshold", min_value=0, value=10
74
+ )
75
+ with threshold_col3:
76
+ sddch_blocking_threshold = st.number_input(
77
+ "SDDCH Blocking Threshold", min_value=0.1, value=0.5
78
+ )
79
+ with threshold_col4:
80
+ tch_blocking_threshold = st.number_input(
81
+ "TCH Blocking Threshold", min_value=0.1, value=0.5
82
+ )
83
+
84
+ if st.button("Analyze Data", type="primary"):
85
+ dfs = analyze_gsm_data(
86
+ dump_path=uploaded_dump,
87
+ daily_report_path=uploaded_daily_report,
88
+ bh_report_path=uploaded_bh_report,
89
+ number_of_kpi_days=number_of_kpi_days,
90
+ number_of_threshold_days=number_of_threshold_days,
91
+ availability_threshold=availability_threshold,
92
+ tch_abis_fails_threshold=tch_abis_fails_threshold,
93
+ sddch_blocking_threshold=sddch_blocking_threshold,
94
+ tch_blocking_threshold=tch_blocking_threshold,
95
+ )
96
+
97
+ if dfs is not None:
98
+ gsm_analysis_df = dfs[0]
99
+ bh_kpi_df = dfs[1]
100
+ GsmCapacity.final_results = convert_gsm_dfs(
101
+ [gsm_analysis_df, bh_kpi_df], ["GSM_Analysis", "BH_KPI_Analysis"]
102
+ )
103
+
104
+ # GsmCapacity.final_results = convert_gsm_dfs(
105
+ # [gsm_analysis_df], ["GSM_Analysis"]
106
+ # )
107
+
108
+ if GsmCapacity.final_results is not None:
109
+ st.download_button(
110
+ on_click="ignore",
111
+ type="primary",
112
+ label="Download the Analysis Report",
113
+ data=GsmCapacity.final_results,
114
+ file_name="GSM_Analysis_Report.xlsx",
115
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
116
+ )
117
+
118
+ st.write(gsm_analysis_df)
assets/gsm_capacity.png ADDED
process_kpi/gsm_kpi_requirements.md ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Required Input
2
+
3
+ - BH report
4
+ - Daily Report
5
+ - Dump file (2G dump)
6
+ - Number of last day for the analysis
7
+ - Number of days for blocking
8
+ - Sddch blocking threshold
9
+ - TCH blocking threshold
10
+ - Availability threshold
11
+ - TCH abis fails threshold
12
+
13
+ Analyse
14
+
15
+ DUMP
16
+
17
+ - Check that mandatory sheet exists in the dump
18
+ - Parse 2G databases
19
+ - Get number of TRX,TCH,SDCCH,amrSegLoadDepTchRateLower,amrSegLoadDepTchRateUpper from databases
20
+ - Add "GPRS" colomn equal to (dedicatedGPRScapacity * number_tch_per_cell)/100
21
+ - Get "Coef HF rate" by mapping "amrSegLoadDepTchRateLower" to 2G analysis_utility "hf_rate_coef" dict
22
+ - "TCH Actual HR%" equal to "number of TCH" multiplyed by "Coef HF rate"
23
+ - Get "Offered Traffic" by mapping approximate "TCH Actual HR%" to 2G analysis_utility "erlangB" dict
24
+
25
+ BH DATA
26
+
27
+ - Pivot KPI in BH report
28
+ - Calculate Average and Max of Traffic
29
+ - Average of TCH blocking
30
+ - Average of SDCCH blocking
31
+ - Count number of Days with TCH blocking exceeded TCH blocking threshold
32
+ - Count number of Days with SDCCH blocking exceeded Sddch blocking threshold
33
+ - Count number of Days with Availability below Availability threshold
34
+ - "TCH UTILIZATION (@Max Traffic)" equal to "Max_Trafic" divided by "offered Traffic"
35
+ - Add "ErlabngB_value" =MAX TRAFFIC/(1-(MAX TCH call blocking/200))
36
+ - Get "Target FR CHs" by mapping "ERLANG value" to 2G analysis_utility "erlangB" dict
37
+ - "Target HR CHs" equal to "Target FR CHs" * 2
38
+ - Get "Signal" and "GPRS" value from databases
39
+ - Target TCHs equal to Target HR CHs + Signal + GPRS + SDCCH
40
+ - "Target TRXs" equal to roundup(Target TCHs/8)
41
+ - "# of required TRXs" equal to difference between "Target TRXs" and "number of TRX"
42
+
43
+ Daily DATA
44
+
45
+ - Pivot KPI in Daily Report
46
+ - Count number of Days with Availability below Availability threshold
47
+ - Count number of Days with abis fails exceeded TCH abis fails threshold
process_kpi/process_gsm_capacity.py ADDED
@@ -0,0 +1,408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pandas as pd
3
+
4
+ from queries.process_gsm import combined_gsm_database
5
+ from utils.check_sheet_exist import execute_checks_sheets_exist
6
+ from utils.convert_to_excel import convert_dfs, save_dataframe
7
+ from utils.kpi_analysis_utils import (
8
+ GsmAnalysis,
9
+ create_daily_date,
10
+ create_dfs_per_kpi,
11
+ create_hourly_date,
12
+ kpi_naming_cleaning,
13
+ )
14
+
15
+
16
+ class GsmCapacity:
17
+ final_results = None
18
+
19
+
20
+ GSM_COLUMNS = [
21
+ "ID_BTS",
22
+ "site_name",
23
+ "name",
24
+ "BSC",
25
+ "BCF",
26
+ "BTS",
27
+ "code",
28
+ "Region",
29
+ "adminState",
30
+ "frequencyBandInUse",
31
+ "amrSegLoadDepTchRateLower",
32
+ "amrSegLoadDepTchRateUpper",
33
+ "dedicatedGPRScapacity",
34
+ "defaultGPRScapacity",
35
+ "cellId",
36
+ "band",
37
+ "site_config_band",
38
+ "trxRfPower",
39
+ "BCCH",
40
+ "number_trx_per_cell",
41
+ "number_trx_per_bcf",
42
+ "TRX_TCH",
43
+ "MAL_TCH",
44
+ ]
45
+
46
+ TRX_COLUMNS = [
47
+ "ID_BTS",
48
+ "number_tch_per_cell",
49
+ "number_sd_per_cell",
50
+ "number_bcch_per_cell",
51
+ "number_ccch_per_cell",
52
+ "number_cbc_per_cell",
53
+ "number_total_channels_per_cell",
54
+ "number_signals_per_cell",
55
+ ]
56
+
57
+ KPI_COLUMNS = [
58
+ "date",
59
+ "BTS_name",
60
+ "TCH_availability_ratio",
61
+ "2G_Carried_Traffic",
62
+ "TCH_call_blocking",
63
+ "TCH_ABIS_FAIL_CALL_c001084",
64
+ "SDCCH_real_blocking",
65
+ ]
66
+ BH_COLUMNS_FOR_CAPACITY = [
67
+ "Max_Traffic BH",
68
+ "Avg_Traffic BH",
69
+ "Max_tch_call_blocking BH",
70
+ "Avg_tch_call_blocking BH",
71
+ "number_of_days_with_tch_blocking_exceeded",
72
+ "Max_sdcch_real_blocking BH",
73
+ "Avg_sdcch_real_blocking BH",
74
+ "number_of_days_with_sdcch_blocking_exceeded",
75
+ ]
76
+
77
+
78
+ def bh_tch_call_blocking_analysis(
79
+ df: pd.DataFrame,
80
+ number_of_kpi_days: int,
81
+ tch_blocking_threshold: int,
82
+ number_of_threshold_days: int,
83
+ ) -> pd.DataFrame:
84
+
85
+ result_df = df.copy()
86
+ last_days_df = result_df.iloc[:, -number_of_kpi_days:]
87
+ # last_days_df = last_days_df.fillna(0)
88
+
89
+ result_df["Avg_tch_call_blocking BH"] = last_days_df.mean(axis=1).round(2)
90
+ result_df["Max_tch_call_blocking BH"] = last_days_df.max(axis=1)
91
+ # Count the number of days above threshold
92
+ result_df["number_of_days_with_tch_blocking_exceeded"] = last_days_df.apply(
93
+ lambda row: sum(1 for x in row if x >= tch_blocking_threshold), axis=1
94
+ )
95
+ return result_df
96
+
97
+
98
+ def bh_sdcch_call_blocking_analysis(
99
+ df: pd.DataFrame,
100
+ number_of_kpi_days: int,
101
+ sdcch_blocking_threshold: int,
102
+ number_of_threshold_days: int,
103
+ ) -> pd.DataFrame:
104
+
105
+ result_df = df.copy()
106
+ last_days_df = result_df.iloc[:, -number_of_kpi_days:]
107
+ # last_days_df = last_days_df.fillna(0)
108
+
109
+ result_df["Avg_sdcch_real_blocking BH"] = last_days_df.mean(axis=1).round(2)
110
+ result_df["Max_sdcch_real_blocking BH"] = last_days_df.max(axis=1)
111
+ # Count the number of days above threshold
112
+ result_df["number_of_days_with_sdcch_blocking_exceeded"] = last_days_df.apply(
113
+ lambda row: sum(1 for x in row if x >= sdcch_blocking_threshold), axis=1
114
+ )
115
+ return result_df
116
+
117
+
118
+ def bh_traffic_analysis(
119
+ df: pd.DataFrame,
120
+ number_of_kpi_days: int,
121
+ ) -> pd.DataFrame:
122
+
123
+ result_df = df.copy()
124
+ last_days_df = result_df.iloc[:, -number_of_kpi_days:]
125
+ # last_days_df = last_days_df.fillna(0)
126
+
127
+ result_df["Avg_Traffic BH"] = last_days_df.mean(axis=1).round(2)
128
+ result_df["Max_Traffic BH"] = last_days_df.max(axis=1)
129
+ return result_df
130
+
131
+
132
+ def bh_dfs_per_kpi(
133
+ df: pd.DataFrame,
134
+ number_of_kpi_days: int = 7,
135
+ tch_blocking_threshold: int = 0.50,
136
+ sdcch_blocking_threshold: int = 0.50,
137
+ number_of_threshold_days: int = 3,
138
+ ) -> pd.DataFrame:
139
+ """
140
+ Create pivoted DataFrames for each KPI and perform analysis.
141
+
142
+ Args:
143
+ df: DataFrame containing KPI data
144
+ number_of_kpi_days: Number of days to analyze
145
+ threshold: Utilization threshold percentage for flagging
146
+ number_of_threshold_days: Minimum days above threshold to flag for upgrade
147
+
148
+ Returns:
149
+ DataFrame with combined analysis results
150
+ """
151
+ pivoted_kpi_dfs = {}
152
+
153
+ pivoted_kpi_dfs = create_dfs_per_kpi(
154
+ df=df,
155
+ pivot_date_column="date",
156
+ pivot_name_column="BTS_name",
157
+ kpi_columns_from=2,
158
+ )
159
+
160
+ tch_call_blocking_df: pd.DataFrame = pivoted_kpi_dfs["TCH_call_blocking"]
161
+ sdcch_real_blocking_df: pd.DataFrame = pivoted_kpi_dfs["SDCCH_real_blocking"]
162
+ Carried_Traffic_df: pd.DataFrame = pivoted_kpi_dfs["2G_Carried_Traffic"]
163
+ tch_availability_ratio_df: pd.DataFrame = pivoted_kpi_dfs["TCH_availability_ratio"]
164
+
165
+ # ANALISYS
166
+
167
+ tch_call_blocking_df = bh_tch_call_blocking_analysis(
168
+ df=tch_call_blocking_df,
169
+ number_of_kpi_days=number_of_kpi_days,
170
+ tch_blocking_threshold=tch_blocking_threshold,
171
+ number_of_threshold_days=number_of_threshold_days,
172
+ )
173
+
174
+ sdcch_real_blocking_df = bh_sdcch_call_blocking_analysis(
175
+ df=sdcch_real_blocking_df,
176
+ number_of_kpi_days=number_of_kpi_days,
177
+ sdcch_blocking_threshold=sdcch_blocking_threshold,
178
+ number_of_threshold_days=number_of_threshold_days,
179
+ )
180
+
181
+ Carried_Traffic_df = bh_traffic_analysis(
182
+ df=Carried_Traffic_df,
183
+ number_of_kpi_days=number_of_kpi_days,
184
+ )
185
+
186
+ # Carried_Traffic_df["Max_Traffic BH"] = Carried_Traffic_df.max(axis=1)
187
+ # Carried_Traffic_df["Avg_Traffic BH"] = Carried_Traffic_df.mean(axis=1)
188
+
189
+ bh_kpi_df = pd.concat(
190
+ [
191
+ tch_availability_ratio_df,
192
+ Carried_Traffic_df,
193
+ tch_call_blocking_df,
194
+ sdcch_real_blocking_df,
195
+ ],
196
+ axis=1,
197
+ )
198
+ # print(Carried_Traffic_df)
199
+
200
+ return bh_kpi_df
201
+
202
+
203
+ def analyse_bh_data(
204
+ bh_report_path: str,
205
+ number_of_kpi_days: int,
206
+ tch_blocking_threshold: int,
207
+ sdcch_blocking_threshold: int,
208
+ number_of_threshold_days: int,
209
+ ) -> pd.DataFrame:
210
+ df = pd.read_csv(bh_report_path, delimiter=";")
211
+ df = kpi_naming_cleaning(df)
212
+ df = create_hourly_date(df)
213
+ df = df[KPI_COLUMNS]
214
+ df = bh_dfs_per_kpi(
215
+ df=df,
216
+ number_of_kpi_days=number_of_kpi_days,
217
+ tch_blocking_threshold=tch_blocking_threshold,
218
+ sdcch_blocking_threshold=sdcch_blocking_threshold,
219
+ number_of_threshold_days=number_of_threshold_days,
220
+ )
221
+
222
+ bh_df_for_capacity = df.copy()
223
+ bh_df_for_capacity = bh_df_for_capacity[BH_COLUMNS_FOR_CAPACITY]
224
+ bh_df_for_capacity = bh_df_for_capacity.reset_index()
225
+
226
+ # If columns have multiple levels (MultiIndex), flatten them
227
+ if isinstance(bh_df_for_capacity.columns, pd.MultiIndex):
228
+ bh_df_for_capacity.columns = [
229
+ "_".join([str(el) for el in col if el])
230
+ for col in bh_df_for_capacity.columns.values
231
+ ]
232
+ # bh_df_for_capacity = bh_df_for_capacity.reset_index()
233
+
234
+ # rename Bts_name to name
235
+ bh_df_for_capacity = bh_df_for_capacity.rename(columns={"BTS_name": "name"})
236
+
237
+ return [bh_df_for_capacity, df]
238
+
239
+
240
+ def daily_dfs_per_kpi(
241
+ df: pd.DataFrame,
242
+ number_of_kpi_days: int = 7,
243
+ availability_threshold: int = 95,
244
+ number_of_threshold_days: int = 3,
245
+ tch_abis_fails_threshold: int = 10,
246
+ ) -> pd.DataFrame:
247
+ """
248
+ Create pivoted DataFrames for each KPI and perform analysis.
249
+
250
+ Args:
251
+ df: DataFrame containing KPI data
252
+ number_of_kpi_days: Number of days to analyze
253
+ threshold: Utilization threshold percentage for flagging
254
+ number_of_threshold_days: Minimum days above threshold to flag for upgrade
255
+
256
+ Returns:
257
+ DataFrame with combined analysis results
258
+ """
259
+ pivoted_kpi_dfs = {}
260
+
261
+ pivoted_kpi_dfs = create_dfs_per_kpi(
262
+ df=df,
263
+ pivot_date_column="date",
264
+ pivot_name_column="BTS_name",
265
+ kpi_columns_from=2,
266
+ )
267
+
268
+ tch_call_blocking_df: pd.DataFrame = pivoted_kpi_dfs["TCH_call_blocking"]
269
+ sdcch_real_blocking_df: pd.DataFrame = pivoted_kpi_dfs["SDCCH_real_blocking"]
270
+ Carried_Traffic_df: pd.DataFrame = pivoted_kpi_dfs["2G_Carried_Traffic"]
271
+ tch_availability_ratio_df: pd.DataFrame = pivoted_kpi_dfs["TCH_availability_ratio"]
272
+ tch_abis_fails_df: pd.DataFrame = pivoted_kpi_dfs["TCH_ABIS_FAIL_CALL_c001084"]
273
+
274
+
275
+ def analyse_daily_data(
276
+ daily_report_path: str,
277
+ number_of_kpi_days: int,
278
+ tch_abis_fails_threshold: int,
279
+ availability_threshold: int,
280
+ number_of_threshold_days: int,
281
+ ) -> pd.DataFrame:
282
+ df = pd.read_csv(daily_report_path, delimiter=";")
283
+ df = kpi_naming_cleaning(df)
284
+ df = create_daily_date(df)
285
+ df = df[KPI_COLUMNS]
286
+ df = daily_dfs_per_kpi(
287
+ df=df,
288
+ number_of_kpi_days=number_of_kpi_days,
289
+ availability_threshold=availability_threshold,
290
+ tch_abis_fails_threshold=tch_abis_fails_threshold,
291
+ number_of_threshold_days=number_of_threshold_days,
292
+ )
293
+ # print(df)
294
+
295
+
296
+ def get_gsm_databases(dump_path: str) -> pd.DataFrame:
297
+
298
+ dfs = combined_gsm_database(dump_path)
299
+ bts_df: pd.DataFrame = dfs[0]
300
+ trx_df: pd.DataFrame = dfs[2]
301
+
302
+ # Clean GSM df
303
+ bts_df = bts_df[GSM_COLUMNS]
304
+ trx_df = trx_df[TRX_COLUMNS]
305
+
306
+ # Remove duplicate in TRX df
307
+ trx_df = trx_df.drop_duplicates(subset=["ID_BTS"])
308
+
309
+ gsm_df = pd.merge(bts_df, trx_df, on="ID_BTS", how="left")
310
+
311
+ # add hf_rate_coef
312
+ gsm_df["hf_rate_coef"] = gsm_df["amrSegLoadDepTchRateLower"].map(
313
+ GsmAnalysis.hf_rate_coef
314
+ )
315
+ # Add "GPRS" colomn equal to (dedicatedGPRScapacity * number_tch_per_cell)/100
316
+ gsm_df["GPRS"] = (
317
+ gsm_df["dedicatedGPRScapacity"] * gsm_df["number_tch_per_cell"]
318
+ ) / 100
319
+
320
+ # "TCH Actual HR%" equal to "number of TCH" multiplyed by "Coef HF rate"
321
+ gsm_df["TCH Actual HR%"] = gsm_df["number_tch_per_cell"] * gsm_df["hf_rate_coef"]
322
+
323
+ # Remove empty rows
324
+ gsm_df = gsm_df.dropna(subset=["TCH Actual HR%"])
325
+
326
+ # Get "Offered Traffic BH" by mapping approximate "TCH Actual HR%" to 2G analysis_utility "erlangB" dict
327
+ gsm_df["Offered Traffic BH"] = gsm_df["TCH Actual HR%"].apply(
328
+ lambda x: GsmAnalysis.erlangB_table.get(int(x), 0)
329
+ )
330
+
331
+ # save_dataframe(gsm_df, "GSM")
332
+ return gsm_df
333
+
334
+
335
+ def analyze_gsm_data(
336
+ dump_path: str,
337
+ daily_report_path: str,
338
+ bh_report_path: str,
339
+ number_of_kpi_days: int,
340
+ number_of_threshold_days: int,
341
+ availability_threshold: int,
342
+ tch_abis_fails_threshold: int,
343
+ sddch_blocking_threshold: float,
344
+ tch_blocking_threshold: float,
345
+ ):
346
+ # print("Analyzing data...")
347
+ # print(f"Number of days: {number_of_kpi_days}")
348
+ # print(f"availability_threshold: {availability_threshold}")
349
+
350
+ analyse_daily_data(
351
+ daily_report_path=daily_report_path,
352
+ number_of_kpi_days=number_of_kpi_days,
353
+ availability_threshold=availability_threshold,
354
+ tch_abis_fails_threshold=tch_abis_fails_threshold,
355
+ number_of_threshold_days=number_of_threshold_days,
356
+ )
357
+
358
+ gsm_database_df: pd.DataFrame = get_gsm_databases(dump_path)
359
+
360
+ bh_kpi_dfs = analyse_bh_data(
361
+ bh_report_path=bh_report_path,
362
+ number_of_kpi_days=number_of_kpi_days,
363
+ tch_blocking_threshold=tch_blocking_threshold,
364
+ sdcch_blocking_threshold=sddch_blocking_threshold,
365
+ number_of_threshold_days=number_of_threshold_days,
366
+ )
367
+
368
+ bh_kpi_df = bh_kpi_dfs[0]
369
+ bh_kpi_full_df = bh_kpi_dfs[1]
370
+
371
+ gsm_analysis_df = gsm_database_df.merge(bh_kpi_df, on="name", how="left")
372
+
373
+ # "TCH UTILIZATION (@Max Traffic)" equal to "(Max_Trafic" divided by "Offered Traffic BH)*100"
374
+ gsm_analysis_df["TCH UTILIZATION (@Max Traffic)"] = (
375
+ gsm_analysis_df["Max_Traffic BH"] / gsm_analysis_df["Offered Traffic BH"]
376
+ ) * 100
377
+
378
+ # Add "ERLANGB value" =MAX TRAFFIC/(1-(MAX TCH call blocking/200))
379
+ gsm_analysis_df["ErlabngB_value"] = gsm_analysis_df["Max_Traffic BH"] / (
380
+ 1 - (gsm_analysis_df["Max_tch_call_blocking BH"] / 200)
381
+ )
382
+
383
+ # - Get "Target FR CHs" by mapping "ERLANG value" to 2G analysis_utility "erlangB" dict
384
+ gsm_analysis_df["Target FR CHs"] = gsm_analysis_df["ErlabngB_value"].apply(
385
+ lambda x: GsmAnalysis.erlangB_table.get(int(x) if pd.notnull(x) else 0, 0)
386
+ )
387
+
388
+ # "Target HR CHs" equal to "Target FR CHs" * 2
389
+ gsm_analysis_df["Target HR CHs"] = gsm_analysis_df["Target FR CHs"] * 2
390
+
391
+ # - Target TCHs equal to Target HR CHs + Signal + GPRS + SDCCH
392
+ gsm_analysis_df["Target TCHs"] = (
393
+ gsm_analysis_df["Target HR CHs"]
394
+ + gsm_analysis_df["number_signals_per_cell"]
395
+ + gsm_analysis_df["GPRS"]
396
+ + gsm_analysis_df["number_sd_per_cell"]
397
+ )
398
+ # "Target TRXs" equal to roundup(Target TCHs/8)
399
+ gsm_analysis_df["Target TRXs"] = np.ceil(
400
+ gsm_analysis_df["Target TCHs"] / 8
401
+ ) # df["Target TCHs"] / 8
402
+
403
+ # "Numberof required TRXs" equal to difference between "Target TRXs" and "number_trx_per_cell"
404
+ gsm_analysis_df["Numberof required TRXs"] = (
405
+ gsm_analysis_df["Target TRXs"] - gsm_analysis_df["number_trx_per_cell"]
406
+ )
407
+
408
+ return [gsm_analysis_df, bh_kpi_full_df]