summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/naca/dune5
-rw-r--r--lib/naca/naca.mli.bkp6
-rw-r--r--lib/naca/naca4.ml143
-rw-r--r--lib/naca/naca5.ml18
-rw-r--r--lib/naca/naca5.mli6
5 files changed, 178 insertions, 0 deletions
diff --git a/lib/naca/dune b/lib/naca/dune
new file mode 100644
index 0000000..18fe976
--- /dev/null
+++ b/lib/naca/dune
@@ -0,0 +1,5 @@
+(library
+ (name naca)
+ (modules naca4)
+ (public_name aircraft_studio.naca)
+ (libraries plplot))
diff --git a/lib/naca/naca.mli.bkp b/lib/naca/naca.mli.bkp
new file mode 100644
index 0000000..7027549
--- /dev/null
+++ b/lib/naca/naca.mli.bkp
@@ -0,0 +1,6 @@
+(* -*- mode: tuareg; -*- *)
+
+(** Interface for NACA 4-digit airfoil generation *)
+
+val generate_coordinates : string -> float -> (float * float) list
+(** Generates coordinates for a 4-digit NACA airfoil given its number and chord length. *)
diff --git a/lib/naca/naca4.ml b/lib/naca/naca4.ml
new file mode 100644
index 0000000..d65e581
--- /dev/null
+++ b/lib/naca/naca4.ml
@@ -0,0 +1,143 @@
+(* -*- mode: tuareg; -*- *)
+
+type naca4_num = string
+type naca4_params = { m : float; p : float; t : float }
+type coord = Coordinate of { x : float; y : float }
+type naca4_coords = { c : coord array; u : coord array; l : coord array }
+type naca4_arfoil = { naca_num : naca4_num; coords : naca4_coords }
+
+let get_params naca_num =
+ if String.length naca_num <> 4 then
+ raise (Invalid_argument "NACA number must be a 4-digit string");
+ (* Maximum camber *)
+ let m = String.sub naca_num 0 1 |> float_of_string |> ( *. ) 0.01 in
+ (* Location of maximum camber *)
+ let p = String.sub naca_num 1 1 |> float_of_string |> ( *. ) 0.10 in
+ (* Maximum thickness *)
+ let t = String.sub naca_num 2 2 |> float_of_string |> ( *. ) 0.01 in
+ { m; p; t }
+
+let y_t t x =
+ 5. *. t
+ *. ((0.2969 *. sqrt x)
+ -. (0.1260 *. x)
+ -. (0.3516 *. (x ** 2.))
+ +. (0.2843 *. (x ** 3.))
+ -. (0.1015 *. (x ** 4.)))
+
+let array_of_amt amt =
+ Array.init (amt + 1) (fun x -> float_of_int x /. float_of_int amt)
+
+let densified_array_of_amt amt =
+ let pct = 0.25 in
+ let dense_amt = int_of_float (pct *. float_of_int amt) in
+ let factor = 5. in
+ let dense_array =
+ Array.init
+ (int_of_float (pct *. amt *. factor))
+ (fun x -> float_of_int x /. (10. *. factor))
+ in
+ let sparse_array =
+ let pct = 1. -. pct in
+ Array.init
+ (int_of_float (pct *. (amt)))
+ (fun x -> (float_of_int x +. (pct *. factor)) /. factor)
+ in
+ Array.append dense_array sparse_array
+
+(* Symmetrical airfoil *)
+module Symmetrical = struct
+ let center_coord x = Coordinate { x; y = 0. }
+
+ let upper_coord t x =
+ let y = y_t x t in
+ Coordinate { x; y }
+
+ let lower_coord t x =
+ let y = -.y_t x t in
+ Coordinate { x; y }
+
+ let get_coords t xs =
+ {
+ c = Array.map center_coord xs;
+ u = Array.map (upper_coord t) xs;
+ l = Array.map (lower_coord t) xs;
+ }
+end
+
+(* Cambered airfoil *)
+module Cambered = struct
+ let y_c m p x =
+ if 0. <= x && x <= p then m /. (p ** 2.) *. ((2. *. p *. x) -. (x ** 2.))
+ else if p <= x && x <= 1. then
+ m /. ((1. -. p) ** 2.) *. (1. -. (2. *. p) +. (2. *. p *. x) -. (x ** 2.))
+ else failwith "x value out of bounds"
+
+ let theta m p x =
+ let dy_c_over_dx =
+ if 0. <= x && x <= p then 2. *. m /. (p ** 2.) *. (p -. x)
+ else if p <= x && x <= 1. then 2. *. m /. ((1. -. p) ** 2.) *. (p -. x)
+ else failwith "x value out of bounds"
+ in
+ atan dy_c_over_dx
+
+ let camber_coord m p x =
+ let y = y_c m p x in
+ Coordinate { x; y }
+
+ let upper_coord m p t x =
+ let y_t = y_t t x in
+ let y_c = y_c m p x in
+ let theta = theta m p x in
+ let x = x -. (y_t *. sin theta) in
+ let y = y_c +. (y_t *. cos theta) in
+ Coordinate { x; y }
+
+ let lower_coord m p t x =
+ let y_t = y_t t x in
+ let y_c = y_c m p x in
+ let theta = theta m p x in
+ let x = x +. (y_t *. sin theta) in
+ let y = y_c -. (y_t *. cos theta) in
+ Coordinate { x; y }
+
+ let get_coords m p t xs =
+ {
+ c = Array.map (camber_coord m p) xs;
+ u = Array.map (upper_coord m p t) xs;
+ l = Array.map (lower_coord m p t) xs;
+ }
+end
+
+let get_coords naca_num ?(amt = 100) () =
+ let { m; p; t } = get_params naca_num in
+ let x_coords = densified_array_of_amt amt in
+ let airfoil_is_symmetrical = m = 0. && p = 0. in
+ if airfoil_is_symmetrical then Symmetrical.get_coords t x_coords
+ else Cambered.get_coords m p t x_coords
+
+let extract_coords coords =
+ let get_x (Coordinate c) = c.x in
+ let get_y (Coordinate c) = c.y in
+ let xs = Array.map get_x coords in
+ let ys = Array.map get_y coords in
+ (xs, ys)
+
+let plot_curve coords =
+ let get_x (Coordinate c) = c.x in
+ let get_y (Coordinate c) = c.y in
+ let xs = Array.map get_x coords in
+ let ys = Array.map get_y coords in
+ (xs, ys)
+
+let plot_airfoil naca_num ?(amt = 100) () =
+ let naca_coords = get_coords naca_num ~amt () in
+ let xs, ys = extract_coords naca_coords.c in
+ Plplot.plcol0 1;
+ Plplot.plpoin xs ys 1;
+ let xs, ys = extract_coords naca_coords.u in
+ Plplot.plcol0 6;
+ Plplot.plline xs ys;
+ let xs, ys = extract_coords naca_coords.l in
+ Plplot.plcol0 6;
+ Plplot.plline xs ys
diff --git a/lib/naca/naca5.ml b/lib/naca/naca5.ml
new file mode 100644
index 0000000..865f3ec
--- /dev/null
+++ b/lib/naca/naca5.ml
@@ -0,0 +1,18 @@
+(* -*- mode: tuareg; -*- *)
+
+type naca5 = { l : float; p : float; s : int; t : float }
+
+(** Implementation for NACA 5-digit airfoil generation *)
+
+let generate_coordinates (naca_num : string) =
+ (* Logic for generating 5-digit NACA airfoil coordinates *)
+ naca_num
+
+(* type naca4 = { m : float; p : float; t : float } *)
+
+let parse_naca5 (naca_num : string) =
+ let l = String.sub naca_num 0 1 |> float_of_string |> ( *. ) 0.15 in
+ let p = String.sub naca_num 1 1 |> float_of_string |> ( *. ) 0.05 in
+ let s = String.sub naca_num 2 2 |> int_of_string in
+ let t = String.sub naca_num 2 2 |> float_of_string |> ( *. ) 0.01 in
+ { l; p; s; t }
diff --git a/lib/naca/naca5.mli b/lib/naca/naca5.mli
new file mode 100644
index 0000000..07377d8
--- /dev/null
+++ b/lib/naca/naca5.mli
@@ -0,0 +1,6 @@
+(* -*- mode: tuareg; -*- *)
+
+(** Interface for NACA 5-digit airfoil generation *)
+
+val generate_coordinates : int -> float -> (float * float) list
+(** Generates coordinates for a 5-digit NACA airfoil given its number and chord length. *)
Copyright 2019--2025 Marius PETER