diff options
author | Marius Peter <marius.peter@tutanota.com> | 2025-05-01 12:27:50 +0200 |
---|---|---|
committer | Marius Peter <marius.peter@tutanota.com> | 2025-05-01 12:27:50 +0200 |
commit | 5c1c6665fba2cd76b75f05c7c9c621461b7518ef (patch) | |
tree | 4652e06e1353a483ac3eba757875a34a2055bcd1 /lib/naca/naca4.ml |
Diffstat (limited to 'lib/naca/naca4.ml')
-rw-r--r-- | lib/naca/naca4.ml | 143 |
1 files changed, 143 insertions, 0 deletions
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 |