flightanalysis 0.2.13__tar.gz → 0.2.14__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/PKG-INFO +3 -3
  2. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/scoring/f3a_criteria_maker.py +12 -12
  3. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/analysis/el_analysis.py +2 -2
  4. flightanalysis-0.2.14/flightanalysis/analysis/manoeuvre_analysis/__init__.py +14 -0
  5. flightanalysis-0.2.14/flightanalysis/analysis/manoeuvre_analysis/alignment.py +97 -0
  6. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/analysis/manoeuvre_analysis/analysis.py +8 -8
  7. flightanalysis-0.2.14/flightanalysis/analysis/manoeuvre_analysis/basic.py +131 -0
  8. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/analysis/manoeuvre_analysis/complete.py +9 -12
  9. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/analysis/manoeuvre_analysis/scored.py +21 -3
  10. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/analysis/sch_analysis.py +3 -5
  11. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/__init__.py +1 -1
  12. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/mandef.py +3 -0
  13. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/manparm.py +2 -2
  14. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/scheddef.py +2 -2
  15. flightanalysis-0.2.14/flightanalysis/definition/scheduleinfo.py +72 -0
  16. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/elements/element.py +6 -6
  17. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/exponential.py +8 -6
  18. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/f3a_criteria.py +13 -12
  19. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/inter/combination.py +1 -1
  20. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/inter/comparison.py +1 -1
  21. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/intra/bounded.py +3 -3
  22. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/intra/continuous.py +3 -3
  23. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/intra/single.py +4 -5
  24. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/downgrade.py +7 -12
  25. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/measurement.py +3 -3
  26. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/results.py +16 -15
  27. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scripts/collect_scores.py +3 -3
  28. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis.egg-info/PKG-INFO +3 -3
  29. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis.egg-info/SOURCES.txt +2 -4
  30. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis.egg-info/requires.txt +2 -2
  31. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/requirements-dev.txt +1 -1
  32. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/requirements.txt +1 -1
  33. flightanalysis-0.2.13/examples/scoring/temp.py +0 -24
  34. flightanalysis-0.2.13/flightanalysis/analysis/manoeuvre_analysis/__init__.py +0 -8
  35. flightanalysis-0.2.13/flightanalysis/analysis/manoeuvre_analysis/alignment.py +0 -81
  36. flightanalysis-0.2.13/flightanalysis/analysis/manoeuvre_analysis/basic.py +0 -86
  37. flightanalysis-0.2.13/flightanalysis/definition/scheduleinfo.py +0 -45
  38. flightanalysis-0.2.13/tests/test_schedule/test_element/test_split_optimiser.py +0 -15
  39. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/.github/workflows/publish_pypi.yml +0 -0
  40. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/.gitignore +0 -0
  41. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/LICENSE +0 -0
  42. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/MANIFEST.in +0 -0
  43. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/README.md +0 -0
  44. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/__init__.py +0 -0
  45. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/data/__init__.py +0 -0
  46. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/data/manual_F3A_F23_22_04_28_00000231.json +0 -0
  47. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/data/manual_F3A_P23_22_05_31_00000350.json +0 -0
  48. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/data/manual_F3A_P23_23_08_11_00000094.json +0 -0
  49. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/scoring/__init__.py +0 -0
  50. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/scoring/judging.py +0 -0
  51. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/scoring/manoeuvres/__init__.py +0 -0
  52. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/scoring/manoeuvres/inter_analysis.py +0 -0
  53. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/scoring/manoeuvres/intra_analysis.py +0 -0
  54. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/scoring/manoeuvres/mans/__init__.py +0 -0
  55. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/scoring/manoeuvres/mans/extract_mans.py +0 -0
  56. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/scoring/manoeuvres/mans/tHat.json +0 -0
  57. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/examples/scoring/manoeuvres/positioning_analysis.py +0 -0
  58. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/__init__.py +0 -0
  59. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/analysis/__init__.py +0 -0
  60. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/data/IMAC_Unlimited2024_schedule.json +0 -0
  61. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/data/__init__.py +0 -0
  62. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/data/f3a_a25_schedule.json +0 -0
  63. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/data/f3a_f25_schedule.json +0 -0
  64. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/data/f3a_p23_schedule.json +0 -0
  65. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/data/f3a_p25_schedule.json +0 -0
  66. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/data/f3auk_clubman_schedule.json +0 -0
  67. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/data/f3auk_inter_schedule.json +0 -0
  68. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/builders/__init__.py +0 -0
  69. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/builders/elbuilders.py +0 -0
  70. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/builders/lines.py +0 -0
  71. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/builders/manbuilder.py +0 -0
  72. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/collectors.py +0 -0
  73. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/eldef.py +0 -0
  74. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/maninfo.py +0 -0
  75. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/manoption.py +0 -0
  76. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/operations/__init__.py +0 -0
  77. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/operations/funopp.py +0 -0
  78. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/operations/itemopp.py +0 -0
  79. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/operations/mathopp.py +0 -0
  80. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/definition/operations/operation.py +0 -0
  81. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/elements/__init__.py +0 -0
  82. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/elements/autorotation.py +0 -0
  83. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/elements/line.py +0 -0
  84. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/elements/loop.py +0 -0
  85. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/elements/nose_drop.py +0 -0
  86. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/elements/pitch_break.py +0 -0
  87. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/elements/recovery.py +0 -0
  88. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/elements/stall_turn.py +0 -0
  89. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/manoeuvre.py +0 -0
  90. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/schedule.py +0 -0
  91. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/__init__.py +0 -0
  92. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/__init__.py +0 -0
  93. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/criteria.py +0 -0
  94. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/inter/__init__.py +0 -0
  95. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scoring/criteria/intra/__init__.py +0 -0
  96. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scripts/batch_analyse.py +0 -0
  97. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis/scripts/plot_scores.py +0 -0
  98. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis.egg-info/dependency_links.txt +0 -0
  99. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis.egg-info/entry_points.txt +0 -0
  100. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/flightanalysis.egg-info/top_level.txt +0 -0
  101. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/pyproject.toml +0 -0
  102. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/AMA_Intermediate2024.py +0 -0
  103. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/__init__.py +0 -0
  104. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/create_all.py +0 -0
  105. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/f3a_a25.py +0 -0
  106. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/f3a_f25.py +0 -0
  107. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/f3a_p23.py +0 -0
  108. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/f3a_p25.py +0 -0
  109. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/f3auk_clubman.py +0 -0
  110. /flightanalysis-0.2.13/scripts/f3auk_Intermediate.py → /flightanalysis-0.2.14/scripts/f3auk_intermediate.py +0 -0
  111. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/imac_sport2024.py +0 -0
  112. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/imac_unlim2024.py +0 -0
  113. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/make_manoeuvre.py +0 -0
  114. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/scripts/nsrca_inter2024.py +0 -0
  115. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/setup.cfg +0 -0
  116. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/EmailedBox.f3a +0 -0
  117. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/__init__.py +0 -0
  118. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/conftest.py +0 -0
  119. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/data/manual_F3A_P23.json +0 -0
  120. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/data/p23.BIN +0 -0
  121. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/data/p23_box.f3a +0 -0
  122. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/data/p23_fc.json +0 -0
  123. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/data/p23_flight.json +0 -0
  124. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_criiteria.py +0 -0
  125. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_data.py +0 -0
  126. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/__init__.py +0 -0
  127. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_definition/__init__.py +0 -0
  128. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_definition/test_definition_eldef.py +0 -0
  129. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_definition/test_definition_manparm.py +0 -0
  130. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_definition/test_definition_mpopp.py +0 -0
  131. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_definition/test_schedule_definition.py +0 -0
  132. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_definition/test_schedule_definition_maninfo.py +0 -0
  133. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/__init__.py +0 -0
  134. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/loop_analysis.json +0 -0
  135. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/p23_th_e0.csv +0 -0
  136. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/p23_th_e0.json +0 -0
  137. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/p23_th_e0_template.csv +0 -0
  138. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/test_schedule_element.py +0 -0
  139. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/test_schedule_element_line.py +0 -0
  140. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/test_schedule_element_loop.py +0 -0
  141. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/test_schedule_element_nose_drop.py +0 -0
  142. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/test_schedule_element_pitch_break.py +0 -0
  143. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/test_schedule_element_recovery.py +0 -0
  144. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_element/test_schedule_element_stallturn.py +0 -0
  145. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_measurement.py +0 -0
  146. {flightanalysis-0.2.13 → flightanalysis-0.2.14}/tests/test_schedule/test_schedule_manoeuvre.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flightanalysis
3
- Version: 0.2.13
3
+ Version: 0.2.14
4
4
  Summary: A package for analysing flight data
5
5
  Author-email: Thomas David <thomasdavid0@gmail.com>
6
6
  License: GNU GPL v3
@@ -16,7 +16,7 @@ Requires-Dist: simplejson
16
16
  Requires-Dist: loguru
17
17
  Requires-Dist: joblib
18
18
  Requires-Dist: pfc-geometry>=0.2.6
19
- Requires-Dist: flightdata>=0.2.11
19
+ Requires-Dist: flightdata>=0.2.13
20
20
  Provides-Extra: dev
21
21
  Requires-Dist: numpy; extra == "dev"
22
22
  Requires-Dist: pandas; extra == "dev"
@@ -26,7 +26,7 @@ Requires-Dist: simplejson; extra == "dev"
26
26
  Requires-Dist: loguru; extra == "dev"
27
27
  Requires-Dist: joblib; extra == "dev"
28
28
  Requires-Dist: pfc-geometry>=0.2.6; extra == "dev"
29
- Requires-Dist: flightdata>=0.2.11; extra == "dev"
29
+ Requires-Dist: flightdata>=0.2.13; extra == "dev"
30
30
  Requires-Dist: ardupilot_log_reader>=0.3.1; extra == "dev"
31
31
  Requires-Dist: pymavlink; extra == "dev"
32
32
 
@@ -1,20 +1,20 @@
1
1
  from flightanalysis.scoring.criteria import Single, Exponential, ContAbs, ContRat, InsideBound, MaxBound, Comparison, free, OutsideBound
2
2
  import numpy as np
3
- from itertools import chain
3
+
4
4
 
5
5
  f3a=dict(
6
6
  single=dict(
7
- track=Single(Exponential.fit_points(np.radians([30, 90]), [2, 6], 100)),
8
- roll=Single(Exponential.fit_points(np.radians([30, 90]), [1, 6], 100)),
9
- angle=Single(Exponential.fit_points(np.radians([30, 90]), [2, 6], 100)),
7
+ track=Single(Exponential.fit_points(np.radians([30, 90]), [2, 6], 6)),
8
+ roll=Single(Exponential.fit_points(np.radians([30, 90]), [1, 6], 6)),
9
+ angle=Single(Exponential.fit_points(np.radians([30, 90]), [2, 6], 6)),
10
10
  # distance = Single(Exponential.fit_points([20, 40], [0.5, 1]))
11
11
  ),
12
12
  intra=dict(
13
- track=ContAbs(Exponential.fit_points(np.radians([30, 90]), [2, 6])),
14
- roll=ContAbs(Exponential.fit_points(np.radians([30, 90]), [1.5, 6])),
15
- radius=ContRat(Exponential.fit_points([1,5], [0.5, 4], 2)),
13
+ track=ContAbs(Exponential.fit_points(np.radians([30, 90]), [2, 6], 6)),
14
+ roll=ContAbs(Exponential.fit_points(np.radians([30, 90]), [1.5, 6], 6)),
15
+ radius=ContRat(Exponential.fit_points([1,5], [0.5, 4], 3)),
16
16
  speed=ContRat(Exponential.fit_points([1,5], [0.15, 0.75], 1)),
17
- roll_rate=ContRat(Exponential.fit_points([1,5], [0.15, 0.75], 1)),
17
+ roll_rate=ContRat(Exponential.fit_points([1,5], [0.15, 0.75], 2)),
18
18
  stallturn_speed=InsideBound(Exponential.fit_points([2, 5], [0.3,1.5]), [-2,2]),
19
19
  stallturn_width=InsideBound(Exponential.fit_points([2, 5], [0.5,2.5]), [-2,2]),
20
20
  spin_entry_length=InsideBound(Exponential.fit_points([2, 5], [0.3,1.5]), [-5,5]),
@@ -25,10 +25,10 @@ f3a=dict(
25
25
  depth=MaxBound(Exponential.fit_points([20, 40], [0.5, 1]), 170)
26
26
  ),
27
27
  inter=dict(
28
- radius=Comparison(Exponential.fit_points([1,2], [1.5, 3])),
29
- speed=Comparison(Exponential.fit_points([1,5], [0.25, 1.0])),
30
- roll_rate=Comparison(Exponential.fit_points([1,5], [0.25, 1.5])),
31
- length=Comparison(Exponential.fit_points([1,2], [1.5, 3])),
28
+ radius=Comparison(Exponential.fit_points([1,2], [1, 2], 2)),
29
+ speed=Comparison(Exponential.fit_points([1,2], [0.25, 0.5], 1)),
30
+ roll_rate=Comparison(Exponential.fit_points([1,2], [0.25, 0.5], 1)),
31
+ length=Comparison(Exponential.fit_points([1,2], [1, 2], 2)),
32
32
  free=Comparison(free),
33
33
  )
34
34
  )
@@ -16,9 +16,9 @@ class ElementAnalysis:
16
16
  tp: State
17
17
  ref_frame: g.Transformation
18
18
 
19
- def plot_3d(self, origin=False, **kwargs):
19
+ def plot_3d(self, **kwargs):
20
20
  from flightplotting import plotsec
21
- return plotsec([self.fl, self.tp], 2, 5, origin=origin, **kwargs)
21
+ return plotsec([self.fl, self.tp], **kwargs)
22
22
 
23
23
  def to_dict(self):
24
24
  return {k: v.to_dict() for k, v in self.__dict__.items()}
@@ -0,0 +1,14 @@
1
+ from .analysis import Analysis
2
+ from .basic import Basic
3
+ from .alignment import Alignment
4
+ from .complete import Complete, Scored
5
+
6
+
7
+ def parse_dict(data: dict) -> Analysis:
8
+ return Scored.from_dict(data)
9
+
10
+ def parse(data: dict) -> Basic | Alignment | Complete | Scored:
11
+ if 'parameters' in data:
12
+ return Basic.from_mindict(data).proceed()
13
+ else:
14
+ return parse_dict(data).proceed()
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+ from flightdata import State
4
+ from flightanalysis.manoeuvre import Manoeuvre
5
+ from loguru import logger
6
+ from .basic import Basic
7
+ from flightanalysis.definition import ManDef, ScheduleInfo
8
+ from ..el_analysis import ElementAnalysis
9
+
10
+ @dataclass
11
+ class Alignment(Basic):
12
+ manoeuvre: Manoeuvre | None
13
+ template: State | None
14
+
15
+ def __getattr__(self, name) -> ElementAnalysis:
16
+ return ElementAnalysis(
17
+ self.mdef.data[name],
18
+ self.mdef.mps,
19
+ self.manoeuvre.elements.data[name],
20
+ self.flown.get_element(name),
21
+ self.template.get_element(name),
22
+ self.template.get_element(name)[0].transform
23
+ )
24
+
25
+ def run_all(self, optimise_aligment=True, force=False) -> Alignment | Complete | Scored:
26
+ if self.__class__.__name__ == 'Scored' and force:
27
+ self = self.downgrade()
28
+ new = self
29
+ while self.__class__.__name__ != 'Scored':
30
+ new = self.run(optimise_aligment) if isinstance(self, Complete) else self.run()
31
+ if new.__class__.__name__ == self.__class__.__name__:
32
+ break
33
+ self = new
34
+ return new
35
+
36
+ @staticmethod
37
+ def from_dict(data: dict, fallback=True):
38
+ ia = Basic.from_dict(data)
39
+ try:
40
+ ia = Alignment(
41
+ manoeuvre=Manoeuvre.from_dict(data['manoeuvre']),
42
+ template=State.from_dict(data['template']),
43
+ **ia.__dict__
44
+ )
45
+ except Exception as e:
46
+ if fallback:
47
+ logger.debug(f'Failed to parse Alignment {repr(e)}')
48
+ else:
49
+ raise e
50
+ return ia
51
+
52
+ def run(self) -> Alignment | Complete:
53
+ if 'element' not in self.flown.data.columns:
54
+ try:
55
+ self = self._run(True)[1]
56
+ except Exception as e:
57
+ logger.error(f'Failed to run alignment stage 1: {repr(e)}')
58
+ return self
59
+ try:
60
+ return self._run(False)[1].proceed()
61
+ except Exception as e:
62
+ logger.error(f'Failed to run alignment stage 2: {repr(e)}')
63
+ return self
64
+
65
+ def _run(self, mirror=False, radius=10) -> Alignment:
66
+ dist, aligned = State.align(self.flown, self.template, radius, mirror)
67
+ return dist, self.update(aligned)
68
+
69
+ def update(self, aligned: State) -> Alignment:
70
+ man, tp = self.manoeuvre.match_intention(self.template[0], aligned)
71
+ mdef = ManDef(self.mdef.info, self.mdef.mps.update_defaults(man), self.mdef.eds)
72
+ return Alignment(self.id, mdef, aligned, self.direction, man, tp)
73
+
74
+ def _proceed(self) -> Complete:
75
+ if 'element' in self.flown.data.columns:
76
+ correction = self.mdef.create(self.template[0].transform)
77
+ return Complete(
78
+ self.id, self.mdef, self.flown, self.direction,
79
+ self.manoeuvre, self.template, correction,
80
+ correction.create_template(self.template[0], self.flown)
81
+ )
82
+ else:
83
+ return self
84
+
85
+ def to_mindict(self, sinfo: ScheduleInfo=None, full=False):
86
+ data = dict(
87
+ els = self.flown.label_ranges('element').to_dict('records')
88
+ )
89
+ if full:
90
+ data = dict(
91
+ **super().to_mindict(sinfo),
92
+ **data
93
+ )
94
+ return data
95
+
96
+ from .complete import Complete # noqa: E402
97
+ from .scored import Scored # noqa: E402
@@ -1,16 +1,16 @@
1
1
  from __future__ import annotations
2
2
  from dataclasses import dataclass
3
-
4
- class AlinmentStage:
5
- SETUP=0
6
- PRELIM=1
7
- SECONDARY=2
8
- OPTIMISED=3
9
-
3
+ from flightanalysis.definition import ScheduleInfo
10
4
 
11
5
  @dataclass
12
6
  class Analysis:
7
+ id: int
8
+
13
9
  def to_dict(self):
14
10
  return {k: (v.to_dict() if hasattr(v, 'to_dict') else v) for k, v in self.__dict__.items()}
15
11
 
16
-
12
+ def to_mindict(self, sinfo: ScheduleInfo):
13
+ return {
14
+ "sinfo": sinfo.__dict__,
15
+ }
16
+
@@ -0,0 +1,131 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+ from flightdata import State, Flight, Origin
4
+ from flightanalysis.definition import ManDef, SchedDef, ManOption
5
+ import geometry as g
6
+ from json import load
7
+ from .analysis import Analysis
8
+ from flightanalysis.definition.scheduleinfo import ScheduleInfo
9
+ import numpy as np
10
+ import pandas as pd
11
+
12
+
13
+ @dataclass
14
+ class Basic(Analysis):
15
+ mdef: ManDef | ManOption
16
+ flown: State
17
+ direction: int
18
+
19
+ @property
20
+ def name(self):
21
+ return self.mdef.uid
22
+
23
+ def run_all(self, optimise_aligment=True, force=False) -> Scored:
24
+ """Run the analysis to the final stage, for the case where the elements have not been labelled"""
25
+ drs = [r._run(True) for r in self.run()]
26
+
27
+ dr = drs[np.argmin([dr[0] for dr in drs])]
28
+
29
+ return dr[1].run_all(optimise_aligment, force)
30
+
31
+ def proceed(self) -> Complete:
32
+ """Proceed the analysis to the final stage for the case where the elements have already been labelled"""
33
+ if 'element' not in self.flown.data.columns:
34
+ return self
35
+ mopt = ManOption([self.mdef]) if isinstance(self.mdef, ManDef) else self.mdef
36
+ elnames = self.flown.data.element.unique()
37
+ for md in mopt:
38
+ if np.all(elnames[1:-1] == list( md.eds.data.keys())):
39
+ mdef = md
40
+ break
41
+ else:
42
+ raise ValueError(f"{self.mdef.info.short_name} element sequence doesn't agree with {self.flown.data.element.unique()}")
43
+
44
+ itrans = self.create_itrans()
45
+ man, tp = mdef.create(itrans).add_lines().match_intention(
46
+ State.from_transform(itrans),
47
+ self.flown
48
+ )
49
+ mdef = ManDef(mdef.info, mdef.mps.update_defaults(man), mdef.eds)
50
+ corr = mdef.create(itrans).add_lines()
51
+ return Complete(
52
+ self.id, mdef, self.flown, self.direction,
53
+ man, tp, corr, corr.create_template(itrans, self.flown)
54
+ )
55
+
56
+ @classmethod
57
+ def from_dict(Cls, data:dict) -> Basic:
58
+ return Basic(
59
+ -1,
60
+ ManDef.from_dict(data["mdef"]),
61
+ State.from_dict(data["flown"]),
62
+ data['direction']
63
+ )
64
+
65
+ def create_itrans(self) -> g.Transformation:
66
+ return g.Transformation(
67
+ self.flown[0].pos,
68
+ self.mdef.info.start.initial_rotation(self.direction)
69
+ )
70
+
71
+ @staticmethod
72
+ def from_fcj(file: str, mid: int):
73
+ with open(file, 'r') as f:
74
+ data = load(f)
75
+ flight = Flight.from_fc_json(data)
76
+ box = Origin.from_fcjson_parmameters(data["parameters"])
77
+
78
+ sdef = SchedDef.load(data["parameters"]["schedule"][1])
79
+
80
+ state = State.from_flight(flight, box).splitter_labels(
81
+ data["mans"],
82
+ [m.info.short_name for m in sdef]
83
+ )
84
+ mdef= sdef[mid]
85
+ return Basic(mid, mdef, state.get_manoeuvre(mdef.uid))
86
+
87
+ def run(self) -> list[Alignment]:
88
+ itrans = self.create_itrans()
89
+ mopt = ManOption([self.mdef]) if isinstance(self.mdef, ManDef) else self.mdef
90
+
91
+ als = []
92
+ for mdef in mopt:
93
+ man = mdef.create(itrans).add_lines()
94
+ als.append(Alignment(
95
+ self.id, mdef, self.flown, self.direction,
96
+ man, man.create_template(itrans)
97
+ ))
98
+ return als
99
+
100
+ def to_mindict(self, sinfo: ScheduleInfo):
101
+ data = dict(
102
+ **super().to_mindict(sinfo),
103
+ name=self.name,
104
+ id=self.id,
105
+ data=self.flown._create_json_data().to_dict('records'),
106
+ direction=self.direction,
107
+ )
108
+ return data
109
+
110
+ @staticmethod
111
+ def from_mindict(data: dict):
112
+ info = ScheduleInfo.from_str(data["parameters"]["schedule"][1])
113
+
114
+ st = State.from_flight(
115
+ Flight.from_fc_json(data),
116
+ Origin.from_fcjson_parmameters(data["parameters"])
117
+ )
118
+
119
+ mdef = SchedDef.load(info)[data['id']]
120
+
121
+ if 'els' in data:
122
+ df = pd.DataFrame(data['els'])
123
+ df.columns = ['name', 'start', 'stop', 'length']
124
+ st = st.splitter_labels(df.to_dict('records'), target_col='element').label(manoeuvre=data['name'])
125
+
126
+ return Basic(data['id'], mdef, st, data['direction'])
127
+
128
+
129
+ from .alignment import Alignment # noqa: E402
130
+ from .complete import Complete # noqa: E402
131
+ from .scored import Scored # noqa: E402
@@ -2,13 +2,13 @@ from __future__ import annotations
2
2
  from dataclasses import dataclass
3
3
  from ..el_analysis import ElementAnalysis
4
4
  from flightdata import State
5
- from flightanalysis.definition import ManDef
5
+ from flightanalysis.definition import ManDef, ScheduleInfo
6
6
  from flightanalysis.manoeuvre import Manoeuvre
7
7
  from flightanalysis.scoring import Results, ManoeuvreResults, Measurement
8
8
  from flightanalysis.scoring.criteria.f3a_criteria import F3A
9
9
  from flightanalysis.definition.maninfo import Position
10
10
  import numpy as np
11
- from .alignment import Alignment, AlinmentStage
11
+ from .alignment import Alignment
12
12
  from loguru import logger
13
13
 
14
14
 
@@ -34,7 +34,7 @@ class Complete(Alignment):
34
34
  return pa
35
35
 
36
36
  def run(self, optimise_aligment=True) -> Scored:
37
- if self.stage < AlinmentStage.OPTIMISED and optimise_aligment:
37
+ if optimise_aligment:
38
38
  self = self.optimise_alignment()
39
39
  self = self.update_templates()
40
40
  return Scored(**self.__dict__,
@@ -63,6 +63,7 @@ class Complete(Alignment):
63
63
  tp = el.get_data(self.template).relocate(st.pos[0])
64
64
  return ElementAnalysis(edef, self.mdef.mps, el, st, tp, el.ref_frame(tp))
65
65
 
66
+
66
67
  def update_templates(self):
67
68
  if not np.all(self.flown.element == self.template.element):
68
69
  manoeuvre, template = self.manoeuvre.match_intention(self.template[0], self.flown)
@@ -70,8 +71,9 @@ class Complete(Alignment):
70
71
  correction = mdef.create(self.template[0].transform).add_lines()
71
72
 
72
73
  return Complete(
73
- mdef, self.flown, self.direction, AlinmentStage.OPTIMISED, self.dist,
74
- manoeuvre, template, correction, correction.create_template(template[0])
74
+ self.id, mdef, self.flown, self.direction,
75
+ manoeuvre, template, correction,
76
+ correction.create_template(template[0])
75
77
  )
76
78
  else:
77
79
  return self
@@ -127,13 +129,6 @@ class Complete(Alignment):
127
129
  Measurement.depth(self.flown)
128
130
  )
129
131
 
130
- # val = self.flown.pos.y.mean()
131
- # id = np.abs(self.flown.pos.y - val).argmin()
132
- # m = Measurement.depth(self.flown[id])
133
- # error = np.maximum(m.value, 170) - 170
134
- # dist_dg = F3A.single.distance.lookup(error) * m.visibility
135
- # return Result("distance", m, m.value, error, dist_dg, [id])
136
-
137
132
  def intra(self):
138
133
  return self.manoeuvre.analyse(self.flown, self.template)
139
134
 
@@ -160,4 +155,6 @@ class Complete(Alignment):
160
155
  fig = plotdtw(self.flown, self.flown.data.element.unique())
161
156
  return plotsec(self.flown, color="blue", nmodels=20, fig=fig, **kwargs)
162
157
 
158
+
159
+
163
160
  from .scored import Scored # noqa: E402
@@ -1,6 +1,7 @@
1
1
  from dataclasses import dataclass
2
2
  from .complete import Complete
3
3
  from flightanalysis.scoring import ManoeuvreResults
4
+ from flightanalysis.definition.scheduleinfo import ScheduleInfo
4
5
  from loguru import logger
5
6
 
6
7
 
@@ -8,6 +9,13 @@ from loguru import logger
8
9
  class Scored(Complete):
9
10
  scores: ManoeuvreResults
10
11
 
12
+ def downgrade(self) -> Complete:
13
+ return Complete(
14
+ self.id, self.mdef, self.flown, self.direction,
15
+ self.manoeuvre, self.template, self.corrected,
16
+ self.corrected_template
17
+ )
18
+
11
19
  @staticmethod
12
20
  def from_dict(data:dict, fallback=True):
13
21
  ca = Complete.from_dict(data, fallback)
@@ -22,6 +30,16 @@ class Scored(Complete):
22
30
  else:
23
31
  raise e
24
32
  return ca
25
-
26
- def run(self, optimise_alignment=True):
27
- return self
33
+
34
+ def to_mindict(self, sinfo: ScheduleInfo=None, full=False):
35
+ data = dict(
36
+ **super().to_mindict(sinfo, full),
37
+ scores=dict(
38
+ **self.scores.summary(),
39
+ total=self.scores.score(),
40
+ k=self.mdef.info.k
41
+ )
42
+ )
43
+
44
+ return data
45
+
@@ -41,16 +41,15 @@ class ScheduleAnalysis(Collection):
41
41
 
42
42
  return ScheduleAnalysis(
43
43
  [analysis.Basic(
44
+ i,
44
45
  mdef,
45
46
  state.get_manoeuvre(mdef.uid),
46
- direction,
47
- analysis.AlinmentStage.SETUP
48
- ) for mdef in sdef],
47
+ direction
48
+ ) for i, mdef in enumerate(sdef)],
49
49
  info
50
50
  )
51
51
 
52
52
  def run_all(self) -> Self:
53
-
54
53
  def parse_analyse_serialise(pad):
55
54
  res = analysis.Basic.from_dict(pad).run_all()
56
55
  logger.info(f'Completed {res.name}')
@@ -67,7 +66,6 @@ class ScheduleAnalysis(Collection):
67
66
 
68
67
  def parse_analyse_serialise(mad):
69
68
  an = analysis.Complete.from_dict(mad)
70
- an.stage = analysis.AlinmentStage.SECONDARY
71
69
  return an.run_all().to_dict()
72
70
 
73
71
  logger.info(f'Starting {os.cpu_count()} alinment optimisation processes')
@@ -12,6 +12,6 @@ from .manparm import ManParm, ManParms, DummyMPs
12
12
  from .eldef import ElDef, ElDefs
13
13
  from .mandef import ManDef
14
14
  from .manoption import ManOption
15
- from .scheduleinfo import ScheduleInfo, fcj_schedule_names, schedule_library
15
+ from .scheduleinfo import ScheduleInfo, schedule_library
16
16
  from .scheddef import SchedDef
17
17
  from .builders.manbuilder import ManBuilder, f3amb, MBTags, centred, imacmb, r, c45, dp
@@ -34,6 +34,9 @@ class ManDef:
34
34
  self.mps: ManParms = ManParms.create_defaults_f3a() if mps is None else mps
35
35
  self.eds: ElDefs = ElDefs() if eds is None else eds
36
36
 
37
+ def __repr__(self):
38
+ return f"ManDef({self.info.name})"
39
+
37
40
  @property
38
41
  def uid(self):
39
42
  return self.info.short_name
@@ -25,7 +25,7 @@ class ManParm(Opp):
25
25
 
26
26
  """
27
27
  criteria: Criteria
28
- defaul:Any=None
28
+ defaul:Number=None
29
29
  collectors:Collectors=field(default_factory=lambda : Collectors())
30
30
 
31
31
 
@@ -78,7 +78,7 @@ class ManParm(Opp):
78
78
  [c(els) for c in self.collectors],
79
79
  self.defaul,
80
80
  direction,
81
- [vis[0]] + [max(va, vb) for va, vb in zip(vis[:-1], vis[1:])],
81
+ np.array([vis[0]] + [max(va, vb) for va, vb in zip(vis[:-1], vis[1:])]),
82
82
  [str(c) for c in self.collectors]
83
83
  )
84
84
 
@@ -1,4 +1,4 @@
1
- from . import ManDef, ManInfo, ManOption, ScheduleInfo, fcj_schedule_names
1
+ from . import ManDef, ManInfo, ManOption, ScheduleInfo
2
2
  from flightdata import State
3
3
  from typing import Tuple, Union, Self
4
4
  from geometry import Transformation
@@ -95,7 +95,7 @@ class SchedDef(Collection):
95
95
  fcj = self.label_exit_lines(template).create_fc_json(
96
96
  [0] + [man.info.k for man in self] + [0],
97
97
  sname,
98
- fcj_schedule_names[kind.lower()][-1]
98
+ kind.lower()
99
99
  )
100
100
 
101
101
  with open(path, 'w') as f:
@@ -0,0 +1,72 @@
1
+ from dataclasses import dataclass
2
+ from flightanalysis.data import list_resources
3
+
4
+
5
+ fcj_categories = {
6
+ 'F3A FAI':'f3a',
7
+ 'F3A':'f3a',
8
+ 'US AMA':'nsrca',
9
+ 'F3A UK':'f3auk',
10
+ 'F3A US':'nsrca',
11
+ 'IMAC':'imac',
12
+ }
13
+
14
+ fcj_schedules = {
15
+ 'P23': 'p23',
16
+ 'F23': 'f23',
17
+ 'P25': 'p25',
18
+ 'F25': 'f25',
19
+ }
20
+
21
+
22
+
23
+ @dataclass
24
+ class ScheduleInfo:
25
+ category: str
26
+ name: str
27
+
28
+ @staticmethod
29
+ def from_str(fname):
30
+ if fname.endswith("_schedule.json"):
31
+ fname = fname[:-14]
32
+ info = fname.split("_")
33
+ if len(info) == 1:
34
+ return ScheduleInfo("f3a", info[0].lower())
35
+ else:
36
+ return ScheduleInfo(info[0].lower(), info[1].lower())
37
+
38
+ def __str__(self):
39
+ return f"{self.category}_{self.name}".lower()
40
+
41
+ def fcj_to_pfc(self):
42
+ def lookup(val, data):
43
+ return data[val] if val in data else val
44
+
45
+ return ScheduleInfo(
46
+ lookup(self.category, fcj_categories),
47
+ lookup(self.name, fcj_schedules)
48
+ )
49
+
50
+ def pfc_to_fcj(self):
51
+
52
+ def rev_lookup(val, data):
53
+ return next(k for k, v in data.items() if v == val) if val in data.values() else val
54
+
55
+ return ScheduleInfo(
56
+ rev_lookup(self.category, fcj_categories),
57
+ rev_lookup(self.name, fcj_schedules)
58
+ )
59
+
60
+ @staticmethod
61
+ def from_fcj_sch(sch):
62
+ return ScheduleInfo(*sch).fcj_to_pfc()
63
+
64
+ def to_fcj_sch(self):
65
+ return list(self.pfc_to_fcj().__dict__.values())
66
+
67
+ @staticmethod
68
+ def build(category, name):
69
+ return ScheduleInfo(category.lower(), name.lower())
70
+
71
+
72
+ schedule_library = [ScheduleInfo.from_str(fname) for fname in list_resources('schedule')]
@@ -62,11 +62,11 @@ class Element:
62
62
  def score_series_builder(self, index):
63
63
  return lambda data: pd.Series(data, index=index)
64
64
 
65
- def analyse(self, flown:State, template:State) -> Results:
66
- return self.intra_scoring.apply(self, flown, template)
65
+ def analyse(self, flown:State, template:State, limits=True) -> Results:
66
+ return self.intra_scoring.apply(self, flown, template, limits)
67
67
 
68
- def analyse_exit(self, fl, tp) -> Results:
69
- return self.exit_scoring.apply(self, fl, tp)
68
+ def analyse_exit(self, fl, tp, limits=True) -> Results:
69
+ return self.exit_scoring.apply(self, fl, tp, limits)
70
70
 
71
71
  def ref_frame(self, template: State) -> g.Transformation:
72
72
  return template[0].transform
@@ -140,9 +140,9 @@ class Element:
140
140
  istate = istate if isinstance(istate, State) else State.from_transform(istate)
141
141
  tp = self.create_template(istate, fl.time)
142
142
  if self.uid=='entry_line':
143
- res = self.analyse_exit(fl, tp)
143
+ res = self.analyse_exit(fl, tp, False)
144
144
  else:
145
- res = self.analyse(fl, tp)
145
+ res = self.analyse(fl, tp, False)
146
146
  return res, tp
147
147
 
148
148
  @staticmethod
@@ -1,16 +1,18 @@
1
1
  from __future__ import annotations
2
- from dataclasses import dataclass, field
2
+ from dataclasses import dataclass
3
3
  import numpy as np
4
- from typing import Union
4
+
5
5
 
6
6
  @dataclass
7
7
  class Exponential:
8
8
  factor: float
9
9
  exponent: float
10
- limit: Union[float, None] = None
11
- def __call__(self, value):
12
- val = self.factor * value ** self.exponent
13
- if self.limit:
10
+ limit: float | None = None
11
+ def __call__(self, value, visibility=1, limits=True):
12
+ if np.isscalar(visibility) and not np.isscalar(value):
13
+ visibility = np.full_like(value, visibility)
14
+ val = visibility * self.factor * value ** self.exponent
15
+ if self.limit and limits:
14
16
  val = np.minimum(val, self.limit)
15
17
  return val
16
18