Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

192 lines
6.3KB

  1. #!/usr/bin/env python3
  2. import multiprocessing
  3. import os
  4. from argparse import ArgumentParser
  5. from datetime import datetime
  6. from math import ceil
  7. from time import sleep
  8. import pandas as pd
  9. import geopandas as gpd
  10. import contextily as cx
  11. import matplotlib.pyplot as plt
  12. def csv_to_dataframe(csv_list, dummy):
  13. global n
  14. global frame_list
  15. transmission_df = None
  16. for csv in csv_list:
  17. tmp_df = pd.read_csv(
  18. "{}{}".format(args.pcap_csv_folder, csv),
  19. dtype=dict(is_retranmission=bool, is_dup_ack=bool),
  20. )
  21. #tmp_df["datetime"] = pd.to_datetime(tmp_df["datetime"]) - pd.Timedelta(hours=1)
  22. tmp_df["datetime"] = pd.to_datetime(tmp_df["datetime"])
  23. tmp_df = tmp_df.set_index("datetime")
  24. tmp_df.index = pd.to_datetime(tmp_df.index)
  25. if transmission_df is None:
  26. transmission_df = tmp_df
  27. else:
  28. transmission_df = pd.concat([transmission_df, tmp_df])
  29. n.value += 1
  30. frame_list.append(transmission_df)
  31. from itertools import islice
  32. def chunk(it, size):
  33. it = iter(it)
  34. return iter(lambda: tuple(islice(it, size)), ())
  35. if __name__ == "__main__":
  36. parser = ArgumentParser()
  37. parser.add_argument("-f", "--gps_file", required=True, help="GPS csv file.")
  38. parser.add_argument("-s", "--serial_file", required=True, help="Serial csv file.")
  39. parser.add_argument("-p", "--pcap_csv_folder", required=True, help="PCAP csv folder.")
  40. parser.add_argument("--save", default=None, help="Location to save pdf file.")
  41. parser.add_argument("--time_offset", default=0, type=int, help="Minutes added to GPS datetime.")
  42. parser.add_argument("--neg_offset", default=False, action="store_true", help="Subtract GPS time offset.")
  43. parser.add_argument("--auto_offset", default=False, action="store_true", help="Calculate GPS time offset.")
  44. parser.add_argument(
  45. "-c",
  46. "--cores",
  47. default=1,
  48. type=int,
  49. help="Number of cores for multiprocessing.",
  50. )
  51. parser.add_argument(
  52. "-i",
  53. "--interval",
  54. default=10,
  55. type=int,
  56. help="Time interval for rolling window.",
  57. )
  58. args = parser.parse_args()
  59. manager = multiprocessing.Manager()
  60. n = manager.Value("i", 0)
  61. frame_list = manager.list()
  62. jobs = []
  63. # load all pcap csv into one dataframe
  64. pcap_csv_list = list()
  65. for filename in os.listdir(args.pcap_csv_folder):
  66. if filename.endswith(".csv") and "tcp" in filename:
  67. pcap_csv_list.append(filename)
  68. parts = chunk(pcap_csv_list, ceil(len(pcap_csv_list) / args.cores))
  69. print("Start processing with {} jobs.".format(args.cores))
  70. for p in parts:
  71. process = multiprocessing.Process(target=csv_to_dataframe, args=(p, "dummy"))
  72. jobs.append(process)
  73. for j in jobs:
  74. j.start()
  75. print("Started all jobs.")
  76. # Ensure all of the processes have finished
  77. finished_job_counter = 0
  78. working = ["|", "/", "-", "\\", "|", "/", "-", "\\"]
  79. w = 0
  80. while len(jobs) != finished_job_counter:
  81. sleep(1)
  82. print(
  83. "\r\t{}{}{}\t Running {} jobs ({} finished). Processed {} out of {} pcap csv files. ({}%) ".format(
  84. working[w],
  85. working[w],
  86. working[w],
  87. len(jobs),
  88. finished_job_counter,
  89. n.value,
  90. len(pcap_csv_list),
  91. round((n.value / len(pcap_csv_list)) * 100, 2),
  92. ),
  93. end="",
  94. )
  95. finished_job_counter = 0
  96. for j in jobs:
  97. if not j.is_alive():
  98. finished_job_counter += 1
  99. if (w + 1) % len(working) == 0:
  100. w = 0
  101. else:
  102. w += 1
  103. print("\r\nSorting table...")
  104. transmission_df = pd.concat(frame_list)
  105. frame_list = None
  106. transmission_df = transmission_df.sort_index()
  107. print("Calculate goodput...")
  108. transmission_df["goodput"] = transmission_df["payload_size"].rolling("{}s".format(args.interval)).sum()
  109. transmission_df["goodput"] = transmission_df["goodput"].apply(
  110. lambda x: ((x * 8) / args.interval) / 10**6
  111. )
  112. # load dataframe an put it into geopandas
  113. df = pd.read_csv(args.gps_file)
  114. df["kmh"] = df["speed (knots)"].apply(lambda x: x * 1.852)
  115. if not args.auto_offset and args.time_offset > 0:
  116. if args.neg_offset:
  117. df["datetime"] = pd.to_datetime(df["datetime"]) - pd.Timedelta(minutes=args.time_offset)
  118. else:
  119. df["datetime"] = pd.to_datetime(df["datetime"]) + pd.Timedelta(minutes=args.time_offset)
  120. elif args.auto_offset:
  121. gps_first = datetime.strptime(df["datetime"].iloc[0], "%Y-%m-%d %H:%M:%S.%f")
  122. pcap_first = datetime.strptime(pd.to_datetime(transmission_df.first_valid_index()), "%Y-%m-%d %H:%M:%S.%f")
  123. calc_offset = gps_first - pcap_first
  124. if gps_first > pcap_first:
  125. time_offset = gps_first - pcap_first
  126. df["datetime"] = pd.to_datetime(df["datetime"]) - time_offset
  127. else:
  128. time_offset = pcap_first - gps_first
  129. df["datetime"] = pd.to_datetime(df["datetime"]) + time_offset
  130. else:
  131. df["datetime"] = pd.to_datetime(df["datetime"])
  132. df = df.set_index("datetime")
  133. df.index = pd.to_datetime(df.index)
  134. gdf = gpd.GeoDataFrame(
  135. df,
  136. geometry=gpd.points_from_xy(df["longitude"], df["latitude"]),
  137. crs="EPSG:4326",
  138. )
  139. gdf = pd.merge_asof(
  140. gdf,
  141. transmission_df,
  142. tolerance=pd.Timedelta("10s"),
  143. right_index=True,
  144. left_index=True,
  145. )
  146. # read serial csv
  147. serial_df = pd.read_csv(args.serial_file)
  148. #serial_df["datetime"] = pd.to_datetime(serial_df["datetime"]) - pd.Timedelta(hours=1)
  149. serial_df["datetime"] = pd.to_datetime(serial_df["datetime"])
  150. serial_df = serial_df.set_index("datetime")
  151. serial_df.index = pd.to_datetime(serial_df.index)
  152. gdf = pd.merge_asof(
  153. gdf,
  154. serial_df,
  155. tolerance=pd.Timedelta("1s"),
  156. right_index=True,
  157. left_index=True,
  158. )
  159. # format to needed format and add basemap as background
  160. df_wm = gdf.to_crs(epsg=3857)
  161. #df_wm.to_csv("debug-data.csv")
  162. # ax2 = df_wm.plot(figsize=(10, 10), alpha=0.5, edgecolor='k')
  163. df_wm.to_csv("{}gps_plot.csv".format(args.save))
  164. print("Saved calculations to: {}gps_plot.csv".format(args.save))