A Discrete-Event Network Simulator
QKDNetSim v2.0 (NS-3 v3.41) @ (+)
API
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
two-ray-to-three-gpp-ch-calibration.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 """
4 Companion TwoRaySpectrumPropagationLossModel calibration script
5 
6 Copyright (c) 2022 SIGNET Lab, Department of Information Engineering,
7 University of Padova
8 
9 This program is free software: you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free Software
11 Foundation, either version 3 of the License, or (at your option) any later
12 version.
13 
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License along with
19 this program. If not, see <http://www.gnu.org/licenses/>.
20 """
21 
22 import argparse as argp
23 import contextlib
24 from itertools import product
25 from pathlib import Path
26 
27 import joblib
28 import numpy as np
29 import pandas as pd
30 import seaborn as sns
31 from matplotlib import pyplot as plt
32 from tqdm import tqdm
33 
34 # Command line arguments
35 parser = argp.ArgumentParser(formatter_class=argp.ArgumentDefaultsHelpFormatter)
36 parser.add_argument(
37  "--num_search_grid_params",
38  default=30,
39  help="Number of values for each parameter of the search grids",
40 )
41 parser.add_argument(
42  "--num_refinements", default=1, help="Number of refinement local search runs to be carried out"
43 )
44 parser.add_argument(
45  "--ref_data_fname",
46  default="two-ray-to-three-gpp-splm-calibration.csv",
47  help="Filename of the fit reference data, obtained from ns-3",
48 )
49 parser.add_argument(
50  "--fit_out_fname", default="two-ray-splm-fitted-params.txt", help="Filename of the fit results"
51 )
52 parser.add_argument(
53  "--c_plus_plus_out_fname",
54  default="two-ray-cplusplus-fitted-params.txt",
55  help="Filename of the fit results, encoded as a C++ data structure to be imported in ns-3",
56 )
57 parser.add_argument(
58  "--figs_folder",
59  default="FiguresTwoRayThreeGppChCalibration/",
60  help="Output folder for the fit results figures",
61 )
62 parser.add_argument("--epsilon", default=1e-7, help="Tolerance value for the preliminary tests")
63 parser.add_argument(
64  "--preliminary_fit_test",
65  default=True,
66  help="Whether to run preliminary tests which check the correctness of the script functions",
67 )
68 parser.add_argument(
69  "--fit_ftr_to_threegpp",
70  default=True,
71  help="Whether to run the calibration with respect to the 3GPP reference channel gains",
72 )
73 parser.add_argument(
74  "--output_ns3_table",
75  default=True,
76  help="Whether to output the code for importing the calibration results in ns-3",
77 )
78 parser.add_argument(
79  "--plot_fit_results",
80  default=False,
81  help="Whether to plot a comparison of the reference data ECDFs vs the fitted FTR distributions",
82 )
83 
84 args = parser.parse_args()
85 # Number of values for each parameter of the search grids
86 num_search_grid_params = int(args.num_search_grid_params)
87 # Number of refinement local search runs to be carried out
88 num_refinements = int(args.num_refinements)
89 # Filename of the fit reference data, obtained from ns-3
90 ref_data_fname = args.ref_data_fname
91 # Filename of the fit results
92 fit_out_fname = args.fit_out_fname
93 # Filename of the fit results, encoded as a C++ data structure to be imported in ns-3
94 c_plus_plus_out_fname = args.c_plus_plus_out_fname
95 # Output folder for the fit results figures
96 figs_folder = args.figs_folder
97 # Tolerance value for the preliminary tests
98 epsilon = float(args.epsilon)
99 # Whether to run preliminary tests which check the correctness of the script functions
100 preliminary_fit_test = bool(args.preliminary_fit_test)
101 # Whether to run the calibration with respect to the 3GPP reference channel gains
102 fit_ftr_to_threegpp = bool(args.fit_ftr_to_threegpp)
103 # Whether to output the code for importing the calibration results in ns-3
104 output_ns3_table = bool(args.output_ns3_table)
105 # Whether to plot a comparison of the reference data ECDFs vs the fitted FTR distributions
106 plot_fit_results = bool(args.plot_fit_results)
107 
108 
109 @contextlib.contextmanager
110 def tqdm_joblib(tqdm_object):
111  """
112  Context manager to patch joblib to report into tqdm progress bar given as argument.
113  Taken from: https://stackoverflow.com/questions/24983493/tracking-progress-of-joblib-parallel-execution
114 
115  """
116 
117  class TqdmBatchCompletionCallback(joblib.parallel.BatchCompletionCallBack):
118  def __call__(self, *args, **kwargs):
119  tqdm_object.update(n=self.batch_size)
120  return super().__call__(*args, **kwargs)
121 
122  old_batch_callback = joblib.parallel.BatchCompletionCallBack
123  joblib.parallel.BatchCompletionCallBack = TqdmBatchCompletionCallback
124  try:
125  yield tqdm_object
126  finally:
127  joblib.parallel.BatchCompletionCallBack = old_batch_callback
128  tqdm_object.close()
129 
130 
131 
132 class FtrParams:
133 
141 
142  def __init__(self, m: float, sigma: float, k: float, delta: float):
143  """! The initializer.
144  @param self: the object pointer
145  @param m: Parameter m for the Gamma variable. Used both as the shape and rate parameters.
146  @param sigma: Parameter sigma. Used as the variance of the amplitudes of the normal diffuse components.
147  @param k: Parameter K. Expresses ratio between dominant specular components and diffuse components.
148  @param delta: Parameter delta [0, 1]. Expresses how similar the amplitudes of the two dominant specular components are.
149  """
150 
151  self.mm = m
152  self.sigmasigma = sigma
153  self.kk = k
154  self.deltadelta = delta
155 
156  def __init__(self):
157  """! The initializer with default values.
158  @param self: the object pointer
159  """
160 
161  self.mm = 1
162  self.sigmasigma = 1.0
163  self.kk = 0.0
164  self.deltadelta = 0.0
165 
166  def __str__(self):
167  """! The initializer with default values.
168  @param self: the object pointer
169  @returns A string reporting the value of each of the FTR fading model parameters
170  """
171 
172  return f"m: {self.m}, sigma: {self.sigma}, k: {self.k}, delta: {self.delta}"
173 
174 
175 def get_ftr_ecdf(params: FtrParams, n_samples: int, db=False):
176  """! Returns the ECDF for the FTR fading model, for a given parameter grid.
177  @param params: The FTR parameters grid.
178  @param n_samples: The number of samples of the output ECDF
179  @param db: Whether to return the ECDF with the gain expressed in dB
180  @returns The ECDF for the FTR fading model
181  """
182 
183  assert params.delta >= 0 and params.delta <= 1.0
184 
185  # Compute the specular components amplitudes from the FTR parameters
186  cmn_sqrt_term = np.sqrt(1 - params.delta**2)
187  v1 = np.sqrt(params.sigma) * np.sqrt(params.k * (1 - cmn_sqrt_term))
188  v2 = np.sqrt(params.sigma) * np.sqrt(params.k * (1 + cmn_sqrt_term))
189 
190  assert abs((v1**2 + v2**2) / (2 * params.sigma) - params.k) < 1e-5
191  if params.k > 0:
192  assert abs((2 * v1 * v2) / (v1**2 + v2**2) - params.delta) < 1e-4
193  else:
194  assert v1 == v2 == params.k
195 
196  sqrt_gamma = np.sqrt(np.random.gamma(shape=params.m, scale=1 / params.m, size=n_samples))
197 
198  # Sample the random phases of the specular components, which are uniformly distributed in [0, 2*PI]
199  phi1 = np.random.uniform(low=0, high=1.0, size=n_samples)
200  phi2 = np.random.uniform(low=0, high=1.0, size=n_samples)
201 
202  # Sample the normal-distributed real and imaginary parts of the diffuse components
203  x = np.random.normal(scale=np.sqrt(params.sigma), size=n_samples)
204  y = np.random.normal(scale=np.sqrt(params.sigma), size=n_samples)
205 
206  # Compute the channel response by combining the above terms
207  compl_phi1 = np.vectorize(complex)(np.cos(phi1), np.sin(phi1))
208  compl_phi2 = np.vectorize(complex)(np.cos(phi2), np.sin(phi2))
209  compl_xy = np.vectorize(complex)(x, y)
210  h = (
211  np.multiply(sqrt_gamma, compl_phi1) * v1
212  + np.multiply(sqrt_gamma, compl_phi2) * v2
213  + compl_xy
214  )
215 
216  # Compute the squared norms
217  power = np.square(np.absolute(h))
218 
219  if db:
220  power = 10 * np.log10(power)
221 
222  return np.sort(power)
223 
224 
225 def compute_ftr_mean(params: FtrParams):
226  """! Computes the mean of the FTR fading model, given a specific set of parameters.
227  @param params: The FTR fading model parameters.
228  """
229 
230  cmn_sqrt_term = np.sqrt(1 - params.delta**2)
231  v1 = np.sqrt(params.sigma) * np.sqrt(params.k * (1 - cmn_sqrt_term))
232  v2 = np.sqrt(params.sigma) * np.sqrt(params.k * (1 + cmn_sqrt_term))
233 
234  mean = v1**2 + v2**2 + 2 * params.sigma
235 
236  return mean
237 
238 
239 def compute_ftr_th_mean(params: FtrParams):
240  """! Computes the mean of the FTR fading model using the formula reported in the corresponding paper,
241  given a specific set of parameters.
242  @param params: The FTR fading model parameters.
243  """
244 
245  return 2 * params.sigma * (1 + params.k)
246 
247 
248 def compute_anderson_darling_measure(ref_ecdf: list, target_ecdf: list) -> float:
249  """! Computes the Anderson-Darling measure for the specified reference and targets distributions.
250  In particular, the Anderson-Darling measure is defined as:
251  \f$A^2 = -N -S\f$, where \f$S = \sum_{i=1}^N \frac{2i - 1}{N} \left[ ln F(Y_i) + ln F(Y_{N + 1 - i}) \right]\f$.
252 
253  See https://www.itl.nist.gov/div898/handbook/eda/section3/eda35e.htm for further details.
254 
255  @param ref_ecdf: The reference ECDF.
256  @param target_ecdf: The target ECDF we wish to match the reference distribution to.
257  @returns The Anderson-Darling measure for the specified reference and targets distributions.
258  """
259 
260  assert len(ref_ecdf) == len(target_ecdf)
261 
262  n = len(ref_ecdf)
263  mult_factors = np.linspace(start=1, stop=n, num=n) * 2 + 1
264  ecdf_values = compute_ecdf_value(ref_ecdf, target_ecdf)
265 
266  # First and last elements of the ECDF may lead to NaNs
267  with np.errstate(divide="ignore"):
268  log_a_plus_b = np.log(ecdf_values) + np.log(1 - np.flip(ecdf_values))
269 
270  valid_idxs = np.isfinite(log_a_plus_b)
271  A_sq = -np.dot(mult_factors[valid_idxs], log_a_plus_b[valid_idxs])
272 
273  return A_sq
274 
275 
276 def compute_ecdf_value(ecdf: list, data_points: float) -> np.ndarray:
277  """! Given an ECDF and data points belonging to its domain, returns their associated EDCF value.
278  @param ecdf: The ECDF, represented as a sorted list of samples.
279  @param data_points: A list of data points belonging to the same domain as the samples.
280  @returns The ECDF value of the domain points of the specified ECDF
281  """
282 
283  ecdf_values = []
284  for point in data_points:
285  idx = np.searchsorted(ecdf, point) / len(ecdf)
286  ecdf_values.append(idx)
287 
288  return np.asarray(ecdf_values)
289 
290 
291 def get_sigma_from_k(k: float) -> float:
292  """! Computes the value for the FTR parameter sigma, given k, yielding a unit-mean fading process.
293  @param k: The K parameter of the FTR fading model, which represents the ratio of the average power
294  of the dominant components to the power of the remaining diffuse multipath.
295  @returns The value for the FTR parameter sigma, given k, yielding a unit-mean fading process.
296  """
297 
298  return 1 / (2 + 2 * k)
299 
300 
302  ref_data: pd.DataFrame, ref_params_combo: tuple, num_params: int, num_refinements: int
303 ) -> str:
304  """! Estimate the FTR parameters yielding the closest ECDF to the reference one.
305 
306  Uses a global search to estimate the FTR parameters yielding the best fit to the reference ECDF.
307  Then, the search is refined by repeating the procedure in the neighborhood of the parameters
308  identified with the global search. Such a neighborhood is determined as the interval whose center
309  is the previous iteration best value, and the lower and upper bounds are the first lower and upper
310  values which were previously considered, respectively.
311 
312  @param ref_data: The reference data, represented as a DataFrame of samples.
313  @param ref_params_combo: The specific combination of simulation parameters corresponding
314  to the reference ECDF
315  @param num_params: The number of values of each parameter in the global and local search grids.
316  @param num_refinements: The number of local refinement search to be carried out after the global search.
317 
318  @returns An estimate of the FTR parameters yielding the closest ECDF to the reference one.
319  """
320 
321  # Retrieve the reference ECDF
322  ref_ecdf = ref_data.query(
323  "scen == @ref_params_combo[0] and cond == @ref_params_combo[1] and fc == @ref_params_combo[2]"
324  )
325 
326  # Perform the fit
327  n_samples = len(ref_ecdf)
328  best_params = FtrParams()
329  best_ad = np.inf
330 
331  # The m and K parameters can range in ]0, +inf[
332  m_and_k_ub = 4
333  m_and_k_lb = 0.001
334  m_and_k_step = (m_and_k_ub - m_and_k_lb) / n_samples
335 
336  # The delta parameter can range in [0, 1]
337  delta_step = 1 / n_samples
338 
339  # Define the coarse grid
340  coarse_search_grid = {
341  # m must be in [0, +inf]
342  "m": np.power(
343  np.ones(num_params) * 10,
344  np.linspace(start=m_and_k_lb, stop=m_and_k_ub, endpoint=True, num=num_params),
345  ),
346  # k must be in [0, +inf]
347  "k": np.power(
348  np.ones(num_params) * 10,
349  np.linspace(start=m_and_k_lb, stop=m_and_k_ub, endpoint=True, num=num_params),
350  ),
351  # delta must be in [0, 1]
352  "delta": np.linspace(start=0.0, stop=1.0, endpoint=True, num=num_params),
353  # sigma determined from k, due to the unit-mean constraint
354  }
355 
356  for element in product(*coarse_search_grid.values()):
357  # Create FTR params object
358  params = FtrParams()
359  params.m = element[0]
360  params.k = element[1]
361  params.delta = element[2]
362  params.sigma = get_sigma_from_k(params.k)
363 
364  # Retrieve the corresponding FTR ECDF
365  ftr_ecdf = get_ftr_ecdf(params, n_samples, db=True)
366  ad_meas = compute_anderson_darling_measure(ref_ecdf, ftr_ecdf)
367 
368  if ad_meas < best_ad:
369  best_params = params
370  best_ad = ad_meas
371 
372  for _ in range(num_refinements):
373  # Refine search in the neighborhood of the previously identified params
374  finer_search_grid = {
375  "m": np.power(
376  np.ones(num_params) * 10,
377  np.linspace(
378  start=max(0, np.log10(best_params.m) - m_and_k_step),
379  stop=np.log10(best_params.m) + m_and_k_step,
380  endpoint=True,
381  num=num_params,
382  ),
383  ),
384  "k": np.power(
385  np.ones(num_params) * 10,
386  np.linspace(
387  start=max(0, np.log10(best_params.k) - m_and_k_step),
388  stop=np.log10(best_params.k) + m_and_k_step,
389  endpoint=True,
390  num=num_params,
391  ),
392  ),
393  "delta": np.linspace(
394  start=max(0, best_params.delta - delta_step),
395  stop=min(1, best_params.delta + delta_step),
396  endpoint=True,
397  num=num_params,
398  ),
399  # sigma determined from k, due to the unit-mean constraint
400  }
401 
402  m_and_k_step = (
403  np.log10(best_params.m) + m_and_k_step - max(0, np.log10(best_params.m) - m_and_k_step)
404  ) / n_samples
405  delta_step = (
406  min(1, best_params.delta + 1 / num_params) - max(0, best_params.delta - 1 / num_params)
407  ) / n_samples
408 
409  for element in product(*finer_search_grid.values()):
410  # Create FTR params object
411  params = FtrParams()
412  params.m = element[0]
413  params.k = element[1]
414  params.delta = element[2]
415  params.sigma = get_sigma_from_k(params.k)
416 
417  # Retrieve the corresponding FTR ECDF
418  ftr_ecdf = get_ftr_ecdf(params, n_samples, db=True)
419  ad_meas = compute_anderson_darling_measure(ref_ecdf, ftr_ecdf)
420 
421  if ad_meas < best_ad:
422  best_params = params
423  best_ad = ad_meas
424 
425  out_str = (
426  f"{ref_params_combo[0]}\t{ref_params_combo[1]}\t{ref_params_combo[2]}"
427  + f" \t{best_params.sigma}\t{best_params.k}\t{best_params.delta}\t{best_params.m}\n"
428  )
429 
430  return out_str
431 
432 
433 def append_ftr_params_to_cpp_string(text: str, params: FtrParams) -> str:
434  text += f"TwoRaySpectrumPropagationLossModel::FtrParams({np.format_float_scientific(params.m)}, {np.format_float_scientific(params.sigma)}, \
435  {np.format_float_scientific(params.k)}, {np.format_float_scientific(params.delta)})"
436 
437  return text
438 
439 
440 def print_cplusplus_map_from_fit_results(fit: pd.DataFrame, out_fname: str):
441  """
442  Prints to a file the results of the FTR fit, as C++ code.
443 
444  Args:
445  fit (pd.DataFrame): A Pandas Dataframe holding the results of the FTR fit.
446  out_fname (str): The name of the file to print the C++ code to.
447  """
448 
449  out_str = "{"
450 
451  for scen in set(fit["scen"]):
452  out_str += f'{{"{scen}",\n{{'
453 
454  for cond in set(fit["cond"]):
455  out_str += f"{{ChannelCondition::LosConditionValue::{cond}, \n"
456 
457  # Print vector of carrier frequencies
458  freqs = np.sort(list(set(fit["fc"])))
459  out_str += "{{"
460  for fc in freqs:
461  out_str += f"{float(fc)}, "
462  out_str = out_str[0:-2]
463  out_str += "},\n{"
464 
465  # Load corresponding fit results
466  for fc in freqs:
467  fit_line = fit.query("scen == @scen and cond == @cond and fc == @fc")
468  assert fit_line.reset_index().shape[0] == 1
469 
470  params = FtrParams()
471  params.m = fit_line.iloc[0]["m"]
472  params.k = fit_line.iloc[0]["k"]
473  params.delta = fit_line.iloc[0]["delta"]
474  params.sigma = fit_line.iloc[0]["sigma"]
475 
476  # Print vector of corresponding FTR parameters
477  out_str = append_ftr_params_to_cpp_string(out_str, params)
478  out_str += ", "
479 
480  out_str = out_str[0:-2]
481  out_str += "}"
482  out_str += "}},\n"
483 
484  out_str = out_str[0:-2]
485  out_str += "}},\n"
486 
487  out_str = out_str[0:-2]
488  out_str += "}\n"
489 
490  with open(out_fname, "w", encoding="utf-8") as f:
491  f.write(out_str)
492 
493 
494 if __name__ == "__main__":
495 
498 
499  # Load reference data obtained from the ns-3 TR 38.901 implementation
500  df = pd.read_csv(ref_data_fname, sep="\t")
501  # Linear gain --> gain in dB
502  df["gain"] = 10 * np.log10(df["gain"])
503 
504  # Retrieve the possible parameters configurations
505  scenarios = set(df["scen"])
506  is_los = set(df["cond"])
507  frequencies = np.sort(list(set(df["fc"])))
508 
509 
512 
513  if preliminary_fit_test:
514  params = FtrParams()
515  get_ftr_ecdf(params, 100)
516 
517  # Make sure the mean is indeed independent from the delta parameter
518  mean_list = []
519  params = FtrParams()
520  for delta in np.linspace(start=0, stop=1, num=100):
521  params.delta = delta
522  mean_list.append(compute_ftr_mean(params))
523 
524  avg_mean = np.mean(mean_list)
525  assert np.all(np.abs(mean_list - avg_mean) < epsilon)
526 
527  # Make sure that we are indeed generating parameters yielding unit-mean
528  mean_list.clear()
529  mean_th_list = []
530  params = FtrParams()
531  for k in np.linspace(start=1, stop=500, num=50):
532  sigma = get_sigma_from_k(k)
533  params.sigma = sigma
534  params.k = k
535  mean_list.append(compute_ftr_mean(params))
536  mean_th_list.append(compute_ftr_th_mean(params))
537 
538  assert np.all(np.abs(mean_list - np.float64(1.0)) < epsilon)
539  assert np.all(np.abs(mean_th_list - np.float64(1.0)) < epsilon)
540 
541  if fit_ftr_to_threegpp:
542  # Parallel search for the different simulation parameters combination
543  with tqdm_joblib(
544  tqdm(
545  desc="Fitting FTR to the 3GPP fading model",
546  total=(len(scenarios) * len(is_los) * len(frequencies)),
547  )
548  ) as progress_bar:
549  res = joblib.Parallel(n_jobs=10)(
550  joblib.delayed(fit_ftr_to_reference)(
551  df, params_comb, num_search_grid_params, num_refinements
552  )
553  for params_comb in product(scenarios, is_los, frequencies)
554  )
555 
556  with open(fit_out_fname, "w", encoding="utf-8") as f:
557  f.write("scen\tcond\tfc\tsigma\tk\tdelta\tm\n")
558  for line in res:
559  f.write(line)
560 
561  if output_ns3_table:
562  # Load the fit results
563  fit = pd.read_csv(fit_out_fname, delimiter="\t")
564 
565  # Output the C++ data structure
566  print_cplusplus_map_from_fit_results(fit, c_plus_plus_out_fname)
567 
568  if plot_fit_results:
569  # Set Seaborn defaults and setup output folder
570  sns.set(rc={"figure.figsize": (7, 5)})
571  sns.set_theme()
572  sns.set_style("darkgrid")
573 
574  fit = pd.read_csv(fit_out_fname, delimiter="\t")
575  # Create folder if it does not exist
576  Path(figs_folder).mkdir(parents=True, exist_ok=True)
577  ad_measures = []
578 
579  for params_comb in product(scenarios, is_los, frequencies):
580  data_query = (
581  "scen == @params_comb[0] and cond == @params_comb[1] and fc == @params_comb[2]"
582  )
583 
584  # Load corresponding reference data
585  ref_data = df.query(data_query)
586 
587  # Create FTR params object
588  fit_line = fit.query(data_query)
589  assert fit_line.reset_index().shape[0] == 1
590  params = FtrParams()
591  params.m = fit_line.iloc[0]["m"]
592  params.k = fit_line.iloc[0]["k"]
593  params.delta = fit_line.iloc[0]["delta"]
594  params.sigma = fit_line.iloc[0]["sigma"]
595 
596  # Retrieve the corresponding FTR ECDF
597  ftr_ecdf = get_ftr_ecdf(params, len(ref_data), db=True)
598 
599  # Compute the AD measure
600  ad_meas = compute_anderson_darling_measure(np.sort(ref_data["gain"]), ftr_ecdf)
601  ad_measures.append(np.sqrt(ad_meas))
602 
603  sns.ecdfplot(data=ref_data, x="gain", label="38.901 reference model")
604  sns.ecdfplot(ftr_ecdf, label=f"Fitted FTR, sqrt(AD)={round(np.sqrt(ad_meas), 2)}")
605  plt.xlabel("End-to-end channel gain due to small scale fading [dB]")
606  plt.legend()
607  plt.savefig(
608  f"{figs_folder}{params_comb[0]}_{params_comb[1]}_{params_comb[2]/1e9}GHz_fit.png",
609  dpi=500,
610  bbox_inches="tight",
611  )
612  plt.clf()
613 
614  # Plot ECDF of the scaled and normalized AD measures
615  sns.ecdfplot(ad_measures, label="AD measures")
616  plt.xlabel("Anderson-Darling goodness-of-fit")
617  plt.legend()
618  plt.savefig(f"{figs_folder}AD_measures.png", dpi=500, bbox_inches="tight")
619  plt.clf()
#define min(a, b)
Definition: 80211b.c:41
#define max(a, b)
Definition: 80211b.c:42
def __str__(self)
The initializer with default values.
def __init__(self, float m, float sigma, float k, float delta)
The initializer.
str append_ftr_params_to_cpp_string(str text, FtrParams params)
float compute_anderson_darling_measure(list ref_ecdf, list target_ecdf)
Computes the Anderson-Darling measure for the specified reference and targets distributions.
def compute_ftr_th_mean(FtrParams params)
Computes the mean of the FTR fading model using the formula reported in the corresponding paper,...
str fit_ftr_to_reference(pd.DataFrame ref_data, tuple ref_params_combo, int num_params, int num_refinements)
Estimate the FTR parameters yielding the closest ECDF to the reference one.
def get_ftr_ecdf(FtrParams params, int n_samples, db=False)
Returns the ECDF for the FTR fading model, for a given parameter grid.
def print_cplusplus_map_from_fit_results(pd.DataFrame fit, str out_fname)
float get_sigma_from_k(float k)
Computes the value for the FTR parameter sigma, given k, yielding a unit-mean fading process.
def compute_ftr_mean(FtrParams params)
Computes the mean of the FTR fading model, given a specific set of parameters.
np.ndarray compute_ecdf_value(list ecdf, float data_points)
Given an ECDF and data points belonging to its domain, returns their associated EDCF value.
#define list