@jjlmoya/utils-drones 1.35.0 → 1.37.0

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 (63) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +4 -0
  3. package/src/entries.ts +8 -0
  4. package/src/index.ts +1 -0
  5. package/src/tests/locale_completeness.test.ts +2 -2
  6. package/src/tests/tool_validation.test.ts +2 -2
  7. package/src/tool/drone-mission-battery-reserve-planner/bibliography.astro +6 -0
  8. package/src/tool/drone-mission-battery-reserve-planner/bibliography.ts +7 -0
  9. package/src/tool/drone-mission-battery-reserve-planner/component.astro +229 -0
  10. package/src/tool/drone-mission-battery-reserve-planner/controller.ts +124 -0
  11. package/src/tool/drone-mission-battery-reserve-planner/dom-views.ts +114 -0
  12. package/src/tool/drone-mission-battery-reserve-planner/drone-mission-battery-reserve-planner.css +392 -0
  13. package/src/tool/drone-mission-battery-reserve-planner/entry.ts +27 -0
  14. package/src/tool/drone-mission-battery-reserve-planner/evaluator.ts +23 -0
  15. package/src/tool/drone-mission-battery-reserve-planner/i18n/de.ts +223 -0
  16. package/src/tool/drone-mission-battery-reserve-planner/i18n/en.ts +223 -0
  17. package/src/tool/drone-mission-battery-reserve-planner/i18n/es.ts +223 -0
  18. package/src/tool/drone-mission-battery-reserve-planner/i18n/fr.ts +223 -0
  19. package/src/tool/drone-mission-battery-reserve-planner/i18n/id.ts +223 -0
  20. package/src/tool/drone-mission-battery-reserve-planner/i18n/it.ts +223 -0
  21. package/src/tool/drone-mission-battery-reserve-planner/i18n/ja.ts +223 -0
  22. package/src/tool/drone-mission-battery-reserve-planner/i18n/ko.ts +223 -0
  23. package/src/tool/drone-mission-battery-reserve-planner/i18n/nl.ts +223 -0
  24. package/src/tool/drone-mission-battery-reserve-planner/i18n/pl.ts +223 -0
  25. package/src/tool/drone-mission-battery-reserve-planner/i18n/pt.ts +223 -0
  26. package/src/tool/drone-mission-battery-reserve-planner/i18n/ru.ts +223 -0
  27. package/src/tool/drone-mission-battery-reserve-planner/i18n/sv.ts +223 -0
  28. package/src/tool/drone-mission-battery-reserve-planner/i18n/tr.ts +223 -0
  29. package/src/tool/drone-mission-battery-reserve-planner/i18n/zh.ts +223 -0
  30. package/src/tool/drone-mission-battery-reserve-planner/index.ts +11 -0
  31. package/src/tool/drone-mission-battery-reserve-planner/logic.test.ts +94 -0
  32. package/src/tool/drone-mission-battery-reserve-planner/logic.ts +203 -0
  33. package/src/tool/drone-mission-battery-reserve-planner/seo.astro +15 -0
  34. package/src/tool/drone-mission-battery-reserve-planner/storage.ts +59 -0
  35. package/src/tool/drone-mission-battery-reserve-planner/ui.ts +78 -0
  36. package/src/tool/fpv-drone-speed-calculator/bibliography.astro +6 -0
  37. package/src/tool/fpv-drone-speed-calculator/bibliography.ts +14 -0
  38. package/src/tool/fpv-drone-speed-calculator/component.astro +115 -0
  39. package/src/tool/fpv-drone-speed-calculator/controller.ts +105 -0
  40. package/src/tool/fpv-drone-speed-calculator/dom-views.ts +80 -0
  41. package/src/tool/fpv-drone-speed-calculator/entry.ts +27 -0
  42. package/src/tool/fpv-drone-speed-calculator/fpv-drone-speed-calculator.css +558 -0
  43. package/src/tool/fpv-drone-speed-calculator/i18n/de.ts +20 -0
  44. package/src/tool/fpv-drone-speed-calculator/i18n/en.ts +47 -0
  45. package/src/tool/fpv-drone-speed-calculator/i18n/es.ts +40 -0
  46. package/src/tool/fpv-drone-speed-calculator/i18n/fr.ts +13 -0
  47. package/src/tool/fpv-drone-speed-calculator/i18n/id.ts +13 -0
  48. package/src/tool/fpv-drone-speed-calculator/i18n/it.ts +13 -0
  49. package/src/tool/fpv-drone-speed-calculator/i18n/ja.ts +13 -0
  50. package/src/tool/fpv-drone-speed-calculator/i18n/ko.ts +13 -0
  51. package/src/tool/fpv-drone-speed-calculator/i18n/nl.ts +13 -0
  52. package/src/tool/fpv-drone-speed-calculator/i18n/pl.ts +13 -0
  53. package/src/tool/fpv-drone-speed-calculator/i18n/pt.ts +13 -0
  54. package/src/tool/fpv-drone-speed-calculator/i18n/ru.ts +13 -0
  55. package/src/tool/fpv-drone-speed-calculator/i18n/sv.ts +13 -0
  56. package/src/tool/fpv-drone-speed-calculator/i18n/tr.ts +13 -0
  57. package/src/tool/fpv-drone-speed-calculator/i18n/zh.ts +13 -0
  58. package/src/tool/fpv-drone-speed-calculator/index.ts +11 -0
  59. package/src/tool/fpv-drone-speed-calculator/logic.test.ts +53 -0
  60. package/src/tool/fpv-drone-speed-calculator/logic.ts +126 -0
  61. package/src/tool/fpv-drone-speed-calculator/seo.astro +16 -0
  62. package/src/tool/fpv-drone-speed-calculator/ui.ts +47 -0
  63. package/src/tools.ts +7 -0
@@ -0,0 +1,126 @@
1
+ export interface FpvDroneSpeedInputs {
2
+ motorKv: number;
3
+ batteryVoltage: number;
4
+ propellerPitchInches: number;
5
+ efficiencyPercent: number;
6
+ aircraftMassGrams: number;
7
+ }
8
+
9
+ export type SpeedDiagnosis = 'overspeed' | 'high-slip' | 'heavy-load' | 'planning';
10
+
11
+ export interface SpeedSensitivityPoint {
12
+ label: 'lower' | 'current' | 'higher';
13
+ pitchInches: number;
14
+ speedKmh: number;
15
+ }
16
+
17
+ export interface FpvDroneSpeedResults {
18
+ noLoadRpm: number;
19
+ loadedRpm: number;
20
+ pitchSpeedKmh: number;
21
+ estimatedSpeedKmh: number;
22
+ slipPercent: number;
23
+ loadPenaltyPercent: number;
24
+ rpmPerVolt: number;
25
+ diagnosis: SpeedDiagnosis;
26
+ sensitivity: SpeedSensitivityPoint[];
27
+ }
28
+
29
+ function clamp(value: number, min: number, max: number): number {
30
+ return Math.min(max, Math.max(min, value));
31
+ }
32
+
33
+ function validInputs(inputs: FpvDroneSpeedInputs): boolean {
34
+ return inputs.motorKv > 0
35
+ && inputs.batteryVoltage > 0
36
+ && inputs.propellerPitchInches > 0
37
+ && inputs.efficiencyPercent > 0
38
+ && inputs.aircraftMassGrams > 0;
39
+ }
40
+
41
+ export function calculateNoLoadRpm(motorKv: number, batteryVoltage: number): number {
42
+ if (motorKv <= 0 || batteryVoltage <= 0) return 0;
43
+ return motorKv * batteryVoltage;
44
+ }
45
+
46
+ export function calculateLoadedRpm(inputs: FpvDroneSpeedInputs): number {
47
+ if (!validInputs(inputs)) return 0;
48
+ const noLoadRpm = calculateNoLoadRpm(inputs.motorKv, inputs.batteryVoltage);
49
+ const efficiencyFactor = 0.82 + clamp(inputs.efficiencyPercent, 50, 98) / 1000;
50
+ const loadFactor = clamp(0.98 - inputs.aircraftMassGrams / 12000, 0.78, 0.98);
51
+ return Math.round(noLoadRpm * efficiencyFactor * loadFactor);
52
+ }
53
+
54
+ export function calculatePitchSpeedKmh(propellerPitchInches: number, rpm: number): number {
55
+ if (propellerPitchInches <= 0 || rpm <= 0) return 0;
56
+ return propellerPitchInches * rpm * 0.001524;
57
+ }
58
+
59
+ export function calculateEstimatedSpeedKmh(pitchSpeedKmh: number, efficiencyPercent: number): number {
60
+ if (pitchSpeedKmh <= 0 || efficiencyPercent <= 0) return 0;
61
+ return pitchSpeedKmh * clamp(efficiencyPercent, 50, 98) / 100;
62
+ }
63
+
64
+ export function calculateSlipPercent(pitchSpeedKmh: number, estimatedSpeedKmh: number): number {
65
+ if (pitchSpeedKmh <= 0) return 0;
66
+ return clamp((1 - estimatedSpeedKmh / pitchSpeedKmh) * 100, 0, 60);
67
+ }
68
+
69
+ export function calculateLoadPenaltyPercent(aircraftMassGrams: number): number {
70
+ if (aircraftMassGrams <= 0) return 0;
71
+ return (1 - clamp(0.98 - aircraftMassGrams / 12000, 0.78, 0.98)) * 100;
72
+ }
73
+
74
+ export function diagnoseSpeed(inputs: FpvDroneSpeedInputs, slipPercent: number): SpeedDiagnosis {
75
+ const noLoadRpm = calculateNoLoadRpm(inputs.motorKv, inputs.batteryVoltage);
76
+ if (noLoadRpm > 140000) return 'overspeed';
77
+ if (slipPercent >= 28) return 'high-slip';
78
+ if (inputs.aircraftMassGrams >= 2500) return 'heavy-load';
79
+ return 'planning';
80
+ }
81
+
82
+ function makeSensitivity(inputs: FpvDroneSpeedInputs, loadedRpm: number): SpeedSensitivityPoint[] {
83
+ const lowerPitch = Math.max(0.5, inputs.propellerPitchInches - 0.5);
84
+ const higherPitch = inputs.propellerPitchInches + 0.5;
85
+ return [
86
+ { label: 'lower', pitchInches: lowerPitch, speedKmh: calculateEstimatedSpeedKmh(calculatePitchSpeedKmh(lowerPitch, loadedRpm), inputs.efficiencyPercent) },
87
+ { label: 'current', pitchInches: inputs.propellerPitchInches, speedKmh: calculateEstimatedSpeedKmh(calculatePitchSpeedKmh(inputs.propellerPitchInches, loadedRpm), inputs.efficiencyPercent) },
88
+ { label: 'higher', pitchInches: higherPitch, speedKmh: calculateEstimatedSpeedKmh(calculatePitchSpeedKmh(higherPitch, loadedRpm), inputs.efficiencyPercent) },
89
+ ];
90
+ }
91
+
92
+ function emptyResults(): FpvDroneSpeedResults {
93
+ return {
94
+ noLoadRpm: 0,
95
+ loadedRpm: 0,
96
+ pitchSpeedKmh: 0,
97
+ estimatedSpeedKmh: 0,
98
+ slipPercent: 0,
99
+ loadPenaltyPercent: 0,
100
+ rpmPerVolt: 0,
101
+ diagnosis: 'planning',
102
+ sensitivity: [],
103
+ };
104
+ }
105
+
106
+ export function calculateFpvDroneSpeed(inputs: FpvDroneSpeedInputs): FpvDroneSpeedResults {
107
+ if (!validInputs(inputs)) return emptyResults();
108
+
109
+ const noLoadRpm = calculateNoLoadRpm(inputs.motorKv, inputs.batteryVoltage);
110
+ const loadedRpm = calculateLoadedRpm(inputs);
111
+ const pitchSpeedKmh = calculatePitchSpeedKmh(inputs.propellerPitchInches, loadedRpm);
112
+ const estimatedSpeedKmh = calculateEstimatedSpeedKmh(pitchSpeedKmh, inputs.efficiencyPercent);
113
+ const slipPercent = calculateSlipPercent(pitchSpeedKmh, estimatedSpeedKmh);
114
+
115
+ return {
116
+ noLoadRpm,
117
+ loadedRpm,
118
+ pitchSpeedKmh,
119
+ estimatedSpeedKmh,
120
+ slipPercent,
121
+ loadPenaltyPercent: calculateLoadPenaltyPercent(inputs.aircraftMassGrams),
122
+ rpmPerVolt: inputs.motorKv,
123
+ diagnosis: diagnoseSpeed(inputs, slipPercent),
124
+ sensitivity: makeSensitivity(inputs, loadedRpm),
125
+ };
126
+ }
@@ -0,0 +1,16 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { fpvDroneSpeedCalculator } from './entry';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const loader = fpvDroneSpeedCalculator.i18n[locale] || fpvDroneSpeedCalculator.i18n.en;
12
+ const content = await loader?.();
13
+ if (!content) return null;
14
+ ---
15
+
16
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -0,0 +1,47 @@
1
+ export interface FpvDroneSpeedUI extends Record<string, string> {
2
+ presetsLabel: string;
3
+ presetRacing: string;
4
+ presetFreestyle: string;
5
+ presetCruiser: string;
6
+ unitsLabel: string;
7
+ metricUnit: string;
8
+ imperialUnit: string;
9
+ inputsLabel: string;
10
+ motorKvLabel: string;
11
+ batteryVoltageLabel: string;
12
+ propellerPitchLabel: string;
13
+ efficiencyLabel: string;
14
+ aircraftMassLabel: string;
15
+ calculateFromLabel: string;
16
+ resultsLabel: string;
17
+ estimatedSpeedLabel: string;
18
+ pitchSpeedLabel: string;
19
+ loadedRpmLabel: string;
20
+ noLoadRpmLabel: string;
21
+ slipLabel: string;
22
+ loadEffectLabel: string;
23
+ speedLaneLabel: string;
24
+ sensitivityLabel: string;
25
+ lowerPitchLabel: string;
26
+ selectedPitchLabel: string;
27
+ higherPitchLabel: string;
28
+ diagnosisLabel: string;
29
+ diagnosisPlanning: string;
30
+ diagnosisHighSlip: string;
31
+ diagnosisHeavyLoad: string;
32
+ diagnosisOverspeed: string;
33
+ diagnosisPlanningAdvice: string;
34
+ diagnosisHighSlipAdvice: string;
35
+ diagnosisHeavyLoadAdvice: string;
36
+ diagnosisOverspeedAdvice: string;
37
+ assumptionsLabel: string;
38
+ assumptionsText: string;
39
+ safetyText: string;
40
+ speedAxisStart: string;
41
+ speedAxisEnd: string;
42
+ noLoadCaption: string;
43
+ loadedCaption: string;
44
+ slipCaption: string;
45
+ massUnit: string;
46
+ speedUnit: string;
47
+ }
package/src/tools.ts CHANGED
@@ -7,6 +7,8 @@ import { GSD_FLIGHT_PLANNER_TOOL } from './tool/gsd-flight-planner/index';
7
7
  import { DRONE_BATTERY_C_RATING_CALCULATOR_TOOL } from './tool/drone-battery-c-rating-calculator/index';
8
8
  import { FPV_DRONE_THRUST_TO_WEIGHT_RATIO_TOOL } from './tool/fpv-drone-thrust-to-weight-ratio/index';
9
9
  import { DRONE_MOTOR_PROPELLER_CALCULATOR_TOOL } from './tool/drone-motor-propeller-calculator/index';
10
+ import { FPV_DRONE_SPEED_CALCULATOR_TOOL } from './tool/fpv-drone-speed-calculator/index';
11
+ import { DRONE_MISSION_BATTERY_RESERVE_PLANNER_TOOL } from './tool/drone-mission-battery-reserve-planner/index';
10
12
  import type { ToolDefinition } from './types';
11
13
 
12
14
  export const ALL_TOOLS: ToolDefinition[] = [
@@ -18,6 +20,8 @@ export const ALL_TOOLS: ToolDefinition[] = [
18
20
  DRONE_BATTERY_C_RATING_CALCULATOR_TOOL,
19
21
  FPV_DRONE_THRUST_TO_WEIGHT_RATIO_TOOL,
20
22
  DRONE_MOTOR_PROPELLER_CALCULATOR_TOOL,
23
+ FPV_DRONE_SPEED_CALCULATOR_TOOL,
24
+ DRONE_MISSION_BATTERY_RESERVE_PLANNER_TOOL,
21
25
  ];
22
26
 
23
27
  export {
@@ -29,4 +33,7 @@ export {
29
33
  DRONE_BATTERY_C_RATING_CALCULATOR_TOOL,
30
34
  FPV_DRONE_THRUST_TO_WEIGHT_RATIO_TOOL,
31
35
  DRONE_MOTOR_PROPELLER_CALCULATOR_TOOL,
36
+ FPV_DRONE_SPEED_CALCULATOR_TOOL,
37
+ DRONE_MISSION_BATTERY_RESERVE_PLANNER_TOOL,
32
38
  };
39
+