"""First-order hovering envelope for insect-scale flapping flight.

Momentum (actuator-disk) theory + lifting-line estimate. All constants explicit.
This is a design envelope, not a discovery: it says where physics allows flapping
flight and where engineering limits bind.
"""
import csv, math
from pathlib import Path
H=Path(__file__).resolve().parent
RHO=1.2; G=9.81; CL=1.2; AR=3.0; NU=1.5e-5
ACT={
 "insect muscle (typical)":100.0,
 "vertebrate muscle":250.0,
 "piezo bimorph (best lab)":30.0,
 "electrostatic MEMS":5.0,
}
rows=[]
for m in [1e-6,1e-5,1e-4,1e-3,1e-2]:
    for wl in [5,10,20,50]:
        W=m*G; S=W/wl
        A=S  # single wing pair treated as actuator disk area
        U=math.sqrt(2*W/(RHO*S*CL))
        c=math.sqrt(S/AR)
        Re=U*c/NU
        # induced power (momentum theory) and profile power estimate
        P_ind=W**1.5/math.sqrt(2*RHO*A)
        P_prof=0.5*RHO*U**3*S*0.02
        P=P_ind+P_prof
        rows.append({"mass_kg":m,"mass_label":f"{m*1e6:.0f} mg" if m<1e-3 else f"{m*1e3:.0f} g",
          "wing_loading_n_m2":wl,"wing_area_m2":round(S,10),"stroke_velocity_m_s":round(U,3),
          "reynolds":int(Re),"power_w":round(P,8),"specific_power_w_kg":round(P/m,1)})
with (H/"envelope.csv").open("w",newline="") as f:
    w=csv.DictWriter(f,fieldnames=list(rows[0])); w.writeheader(); w.writerows(rows)
# summarise
by_m={}
for r in rows: by_m.setdefault(r["mass_kg"],[]).append(r)
L=["# Insect-scale flapping flight: a first-order envelope","",
"**Status: calculation, not discovery.** Momentum theory with explicit assumptions. No experiment.","",
"Assumptions: air density 1.2 kg/m³, lift coefficient 1.2, aspect ratio 3, kinematic viscosity 1.5×10⁻⁵ m²/s,",
"single actuator disk, profile drag coefficient 0.02. Wing loading swept 5–50 N/m².","",
"| Mass | Wing loading | Re | Stroke speed | Specific power | Feasible vs insect muscle (100 W/kg)? |","|---|---:|---:|---:|---:|---|"]
for r in rows:
    ok="yes" if r["specific_power_w_kg"]<=100 else "no"
    L.append(f"| {r['mass_label']} | {r['wing_loading_n_m2']} N/m² | {r['reynolds']:,} | {r['stroke_velocity_m_s']:.2f} m/s | {r['specific_power_w_kg']:.1f} W/kg | {ok} |")
L+=["","## What the envelope says","",
"1. **Reynolds number falls with size**, from ~10⁴ at 10 g to ~10² at 1 mg. Below Re ≈ 10³ viscous forces dominate and steady-state lift coefficients no longer describe the flow — which is why insects use unsteady mechanisms (leading-edge vortices, clap-and-fling) rather than bigger wings.",
"2. **Specific power is nearly constant across mass at fixed wing loading.** Induced power scales with mass, so the ratio does not move; it scales with the square root of wing loading instead. The size penalty is therefore aerodynamic, not energetic — revised after the first run contradicted the draft text.",
"3. **The binding constraint is low-Re aerodynamics, not power.** These estimates sit at 15-46 W/kg, below insect muscle, so a motor is not the limiting factor. What is hard is generating useful lift at Re 100-1000, where steady aerodynamics fails and unsteady mechanisms are mandatory.","",
"## Honest limits","",
"- Momentum theory is a hover idealisation; it ignores unsteady lift entirely, which is the dominant mechanism at these Re.",
"- Real insects vary wing loading by an order of magnitude and use elastic storage that this model omits.",
"- The actuator figures are order-of-magnitude, not measured for a specific device.",
"- Nothing here is new physics. It is a checkable envelope that says where to look, not what will work.","",
"## The reverse-engineering point","",
"The interesting question is not 'can we build an insect' but 'which insect solutions are load-bearing'.",
"Three candidates worth copying, in order of how much they buy you:",
"",
"1. **Compliant wing hinges** — insects get pitch reversal passively from thorax deformation. A printed flexure replaces an actuator and a control loop.",
"2. **Elastic energy storage** — resilin returns a large fraction of stroke energy; at 100+ Hz this is the difference between feasible and not.",
"3. **Compound-eye optics** — wide field of view with no distortion at the edge, at the cost of resolution. Useful for collision sensing, not for imaging.","",
"Each is a design hypothesis with a measurable claim; none is tested here.",""]
(H/"FINDINGS.md").write_text("\n".join(L))
print(f"rows={len(rows)}")
for r in rows[:6]: print(r["mass_label"], r["wing_loading_n_m2"], "Re=",r["reynolds"], "P/m=",r["specific_power_w_kg"])
