# Mech3410-P1-Graphs # Cal Wing - Aug 2024 # import os, time import numpy as np import pandas as pd from tqdm import tqdm from numpy import sqrt from makeGraph import makeGraph, pltKeyClose, UQ_COLOURS as UQC, uq_colour_cycler_factory as uqccf # Custom Graphing Lib # Override Sin & Cos to use & return degrees def sin(angle): return np.sin(np.deg2rad(angle)) def cos(angle): return np.cos(np.deg2rad(angle)) # Make sure the relevant folders folder exists #folders = ["./images", "./tmp", "./data"] folders = ["./images", './images/pressure', './images/cp'] for folder in folders: if not os.path.isdir(folder): os.mkdir(folder) INCH_TO_M = 0.0254 GRAVITY = 9.81 #m/s^2 CHORD_LEN = 1000 #90 #mm PITOT_PLACEMENT = np.array((0,4,8,16,25,34,43,52,61,70,5,9,17,25,34,43,52,61,70)) # mm from base of chord PITOT_PLACEMENT_CHORD_NORM = PITOT_PLACEMENT / CHORD_LEN print("="*15, "Loading Data", "="*15) data_508rpm = { "rpm": 508, "airSpeed": 10, "data": pd.read_excel('.\\data\\508 RPM Results.xlsx', sheet_name=None, header=None), "AoA": (0,1,2,3,4,5,6,7,8,9) } data_1000rpm = { "rpm": 1000, "airSpeed": 20.40408122, "data": pd.read_excel('.\\data\\1000 RPM Results.xlsx', sheet_name=None, header=None), "AoA": (1,2,4,6,8,10,12,14,16) } print("="*15, "Loaded Data", "="*15) def make_pressure_graph(sheet1, aoa, rpm, air_speed, doGraph=True): water_density = sheet1.iloc[0, 2] # kg/m^3 air_density = sheet1.iloc[1, 2] # kg/m^3 atm_presure_inch = sheet1.iloc[24, 12] # inch pitot_height_inch = sheet1.iloc[4:23, 11] pitot_height_m = (pitot_height_inch - atm_presure_inch)*INCH_TO_M pressure = water_density * GRAVITY * pitot_height_m #print(pressure) #print(pressure.min(), pressure.max()) # Do the trapiztoal rule integration da = [] for i, _ in enumerate(pressure): if i in [0]: continue # Skip 0 if i in [10]: # Force tapping 11 to use tapping 1 rather then 0 da.append(((PITOT_PLACEMENT_CHORD_NORM[i] - PITOT_PLACEMENT_CHORD_NORM[0])/2) * (pressure.iloc[0] + pressure.iloc[i])) continue da.append(((PITOT_PLACEMENT_CHORD_NORM[i] - PITOT_PLACEMENT_CHORD_NORM[i-1])/2) * (pressure.iloc[i-1] + pressure.iloc[i])) da = np.array(da) #print("\n\n\n\n") #print(da) #print("\n\n\n\n") upper_force = da[:10].sum() lower_force = da[10 :].sum() force = lower_force - upper_force # Upper Sum (1-10) less Lower Sum (11-19) lift = force * cos(aoa) drag = force * sin(aoa) # Extrapolate Aerofoil Tip p1 = (PITOT_PLACEMENT[9], pressure.iloc[9]) p2 = (PITOT_PLACEMENT[18], pressure.iloc[18]) pN = (1.1*max(PITOT_PLACEMENT), p2[1] + (p1[1]-p2[1])/2) #print(aoa, rpm, p1[1], p2[1], (p1[1]-p2[1])/2, pN[1], pN[1] > p1[1]) graph = { "title": f"Pressure vs Pitot Placement along Chord\nfor a Clark Y 14% Aerofoil at:\nα = {int(aoa):d}° at {rpm:d} RPM ({air_speed:.1f}m/s)", "windowTitle": f"Pressure along Clark Y 14 Percent Airfoil - Alpha {int(aoa):d} Degrees - {rpm:d}rpm - {air_speed:.1f}m_s", "xLabel": "Pitot Placement [mm]", "yLabel": "Pressure [Pa]", "grid": True, "yLim": (pressure.min()-10, pressure.max()+10), "plots": [ # Draw Lines {"x": PITOT_PLACEMENT[:10], "y":pressure[:10], "colour": UQC["purple"]}, {"x": PITOT_PLACEMENT[10:], "y":pressure[10:], "colour": UQC["purple"]}, {"x": [PITOT_PLACEMENT[0], PITOT_PLACEMENT[10]], "y": [pressure.iloc[0], pressure.iloc[10]], "colour": UQC["purple"]}, #{"x": [PITOT_PLACEMENT[9], PITOT_PLACEMENT[18]], "y": [pressure.iloc[9], pressure.iloc[18]], "colour": UQC["purple"]}, # Draw Extrapolated Airfoil Tip {"x": [PITOT_PLACEMENT[9], pN[0]], "y": [pressure.iloc[9], pN[1]], "colour": UQC["aqua"], "label": "Extrapolated Airfoil Tip"}, {"x": [PITOT_PLACEMENT[9], pN[0]], "y": [pressure.iloc[18], pN[1]], "colour": UQC["aqua"]}, # Draw Colour Shading {"x": PITOT_PLACEMENT[:10], "y":pressure[:10], "colour": UQC["purple"], "alpha":0.2, "type":"fill"}, {"x": PITOT_PLACEMENT[10:], "y":pressure[10:], "colour": "w", "type":"fill"}, {"x":[PITOT_PLACEMENT[0], PITOT_PLACEMENT[10]], "y":[pressure.iloc[0], pressure.iloc[10]], "colour": "w", "type":"fill"}, {"x": [PITOT_PLACEMENT[9], pN[0]], "y": [pressure.iloc[9], pN[1]], "colour": UQC["aqua"], "type":"fill", "alpha":0.2}, {"x":[PITOT_PLACEMENT[9], pN[0]], "y": [pressure.iloc[18], pN[1]], "colour": "w", "type":"fill"}, # Draw Points & text {"x":PITOT_PLACEMENT, "y":pressure, "label":"Pressure Data", "type":"scatter", "args":{"zorder":2}}, {"label":[str(i) for i in range(1, len(PITOT_PLACEMENT)+1)], "x":PITOT_PLACEMENT, "y":pressure, "type":"annotate"}, {"type":"text", "x": 0.98, "y": 0.02, "text": f"Min: {pressure.min():.3f} Pa\nMax: {pressure.max():.3f} Pa\nForce: {force:.3f}N\nLift: {lift:.3f}N\nDrag: {drag:.3f}N", "align": ('bottom', 'right')} ] } if doGraph: makeGraph(graph, False, figSavePath=f'./images/pressure/{{0}}.png', closeFig=True) return pressure, graph, (water_density, air_density, atm_presure_inch, pitot_height_inch), (p1, p2, pN), aoa, (force, lift, drag, da, upper_force, lower_force) def make_cp_graph(pressure, aoa, rpm, air_speed, data, doGraph=True): water_density, air_density, atm_presure_inch, pitot_height_inch = data #print(pressure) #print(pressure.min(), pressure.max()) # Calculate Cp cp = pressure / (0.5 * air_density * (air_speed ** 2)) #print("force, lift, drag, upper_force, lower_force") #print(force, lift, drag, upper_force, lower_force) #print(f"{aoa}, ") # Extrapolate Aerofoil Tip p1 = (PITOT_PLACEMENT_CHORD_NORM[9], cp.iloc[9]) p2 = (PITOT_PLACEMENT_CHORD_NORM[18], cp.iloc[18]) pN = (1.1*max(PITOT_PLACEMENT_CHORD_NORM), p2[1] + (p1[1]-p2[1])/2) #print(aoa, rpm, p1[1], p2[1], (p1[1]-p2[1])/2, pN[1], pN[1] > p1[1]) graph = { "title": f"$C_p$ vs Pitot Placement along Chord\nfor a Clark Y 14% Aerofoil at:\nα = {int(aoa):d}° at {rpm:d} RPM ({air_speed:.1f}m/s)", "windowTitle": f"Cp along Clark Y 14 Percent Airfoil - Alpha {int(aoa):d} Degrees - {rpm:d}rpm - {air_speed:.1f}m_s", "xLabel": "Pitot Placement [m]", "yLabel": "$C_p$", "grid": True, "yLim": (cp.min()-0.5, cp.max()+0.5), "plots": [ # Draw Lines {"x": PITOT_PLACEMENT_CHORD_NORM[:10], "y":cp[:10], "colour": UQC["purple"]}, {"x": PITOT_PLACEMENT_CHORD_NORM[10:], "y":cp[10:], "colour": UQC["purple"]}, {"x": [PITOT_PLACEMENT_CHORD_NORM[0], PITOT_PLACEMENT_CHORD_NORM[10]], "y": [cp.iloc[0], cp.iloc[10]], "colour": UQC["purple"]}, #{"x": [PITOT_PLACEMENT_CHORD_NORM[9], PITOT_PLACEMENT_CHORD_NORM[18]], "y": [cp.iloc[9], cp.iloc[18]], "colour": UQC["purple"]}, # Draw Extrapolated Airfoil Tip {"x": [PITOT_PLACEMENT_CHORD_NORM[9], pN[0]], "y": [cp.iloc[9], pN[1]], "colour": UQC["aqua"], "label": "Extrapolated Airfoil Tip"}, {"x": [PITOT_PLACEMENT_CHORD_NORM[9], pN[0]], "y": [cp.iloc[18], pN[1]], "colour": UQC["aqua"]}, # Draw Colour Shading {"x": PITOT_PLACEMENT_CHORD_NORM[:10], "y":cp[:10], "colour": UQC["purple"], "alpha":0.2, "type":"fill"}, {"x": PITOT_PLACEMENT_CHORD_NORM[10:], "y":cp[10:], "colour": "w", "type":"fill"}, {"x":[PITOT_PLACEMENT_CHORD_NORM[0], PITOT_PLACEMENT_CHORD_NORM[10]], "y":[cp.iloc[0], cp.iloc[10]], "colour": "w", "type":"fill"}, {"x": [PITOT_PLACEMENT_CHORD_NORM[9], pN[0]], "y": [cp.iloc[9], pN[1]], "colour": UQC["aqua"], "type":"fill", "alpha":0.2}, {"x":[PITOT_PLACEMENT_CHORD_NORM[9], pN[0]], "y": [cp.iloc[18], pN[1]], "colour": "w", "type":"fill"}, # Draw Points & text {"x":PITOT_PLACEMENT_CHORD_NORM, "y":cp, "label":"cp Data", "type":"scatter", "args":{"zorder":2}}, {"label":[str(i) for i in range(1, len(PITOT_PLACEMENT_CHORD_NORM)+1)], "x":PITOT_PLACEMENT_CHORD_NORM, "y":cp, "type":"annotate"}, {"type":"text", "x": 0.98, "y": 0.02, "text": f"Min $C_p$: {cp.min():.3f}\nMax $C_p$: {cp.max():.3f}", "align": ('bottom', 'right')} ] } if doGraph: makeGraph(graph, False, figSavePath=f'./images/cp/{{0}}.png', closeFig=True) return cp, graph, (p1, p2, pN), aoa def make_rpm_graph(): air_density = data_508rpm["data"]["0 AoA"].iloc[1, 2] # kg/m^3 rpm = np.concat((np.array([0]), np.array(data_508rpm["data"]["0 AoA"].iloc[4:14, 2]))) pressure = np.concat((np.array([0]), np.array(data_508rpm["data"]["0 AoA"].iloc[4:14, 4], dtype=np.float64))) airSpeed = sqrt(-pressure * 2 / air_density) x = np.linspace(rpm[0], rpm[-1], 1000) y = 0.0212*x - 0.7751 graph = { "title": f"RPM vs Velocity for Wind Tunnel 3", "xLabel": "Fan RPM", "yLabel": "Airspeed [m/s]", "grid": True, "plots": [ {"x": x, "y":y, "label":"Linear Estimate", "args":{"linestyle":"--"}, "colour": UQC["neutral"]}, {"type": "scatter", "x":rpm, "y": airSpeed, "label": "Measured Velocity", "colour":UQC["purple"], "args":{"zorder":2}}, {"type": "point", "x":508, "y": 10, "label": "Selected RPM (508)", "colour":UQC["red"], "zorder":3}, {"type":"text", "x": 0.98, "y": 0.02, "text": f"Velocity at 508 RPM: {10:.3f} m/s\nVelocity at 1000 RPM: {airSpeed[-1]:.3f} m/s", "align": ('bottom', 'right')}, {"type":"text", "x": 0.80, "y": 0.85, "text": f"$y = 0.0212 \\cdot x - 0.7751$", "align": ('bottom', 'right'), "facecolour": UQC["neutral"]} ] } makeGraph(graph, False, figSavePath='./images/{0}.png') if __name__ == '__main__': print("Generating RPM Graph") #make_rpm_graph() print("Generated") print("Loading Data & Generating Pressure Graphs") data = {} for raw_data in tqdm((data_508rpm, data_1000rpm), position=0): aoa_data = {} cp_pain_data = [] for aoa in tqdm(raw_data["AoA"], position=1): sheet = raw_data["data"][f"{aoa} AoA"] aoa_data[aoa] = make_pressure_graph(sheet, aoa, raw_data["rpm"], raw_data["airSpeed"], True) cp_pain_data.append(aoa_data[aoa]) data[raw_data["rpm"]] = aoa_data if True: # All graph = { "title": f"Pressure vs Pitot Placement along Chord\nfor a Clark Y 14% Aerofoil at:\n{raw_data["rpm"]:d} RPM ({raw_data["airSpeed"]:.1f}m/s)", "windowTitle": f"All Pressure along Clark Y 14 Percent Airfoil - {raw_data["rpm"]:d}rpm - {raw_data["airSpeed"]:.1f}m_s", "xLabel": "Pitot Placement [mm]", "yLabel": "Pressure [Pa]", "grid": True, "ledgLoc": 1, "plots": [] } colour_cycle = uqccf() for aoa, c in zip(aoa_data, colour_cycle): #print(c["color"], c["color"].hex_lighten(1.4), c["color"].rgb(), c["color"].lighten(1.4)) #print(c["color"].hex_lighten(1), c["color"]) #exit() this_data = aoa_data[aoa] pressure = this_data[0] # Extrapolate Aerofoil Tip p1 = (PITOT_PLACEMENT[9], pressure.iloc[9]) p2 = (PITOT_PLACEMENT[18], pressure.iloc[18]) pN = (0.9*CHORD_LEN, p2[1] + (p1[1]-p2[1])/2) plts = ( {"x": PITOT_PLACEMENT[:10], "y":pressure[:10], "colour": c["color"]}, {"x": PITOT_PLACEMENT[10:], "y":pressure[10:], "colour": c["color"]}, {"x": [PITOT_PLACEMENT[0], PITOT_PLACEMENT[10]], "y": [pressure.iloc[0], pressure.iloc[10]], "colour": c["color"]}, #{"x": [PITOT_PLACEMENT[9], PITOT_PLACEMENT[18]], "y": [pressure.iloc[9], pressure.iloc[18]], "colour": c["color"]}, {"x": [PITOT_PLACEMENT[9], pN[0]], "y": [pressure.iloc[9], pN[1]], "colour": c["color"], "args":{"alpha":0.3}}, {"x": [PITOT_PLACEMENT[9], pN[0]], "y": [pressure.iloc[18], pN[1]], "colour": c["color"], "args":{"alpha":0.3}}, {"x":PITOT_PLACEMENT, "y":pressure, "label":f"α = {int(aoa):d}°", "type":"scatter", "colour": c["color"], "args":{"zorder":2}}, ) for plt in plts: graph["plots"].append(plt) if raw_data["rpm"] == 508: graph['xLim'] = ( min(PITOT_PLACEMENT) - 5, max(PITOT_PLACEMENT) + 25 ) graph["figSize"] = (8, 6) makeGraph(graph, False, figSavePath="./images/pressure/__{0}.png", closeFig=True) graph["plots"] = [] graph["windowTitle"] = f"Pressure along Clark Y 14 Percent Airfoil - {raw_data["rpm"]:d}rpm - {raw_data["airSpeed"]:.1f}m_s" colour_cycle = uqccf() for aoa, c in list(zip(aoa_data, colour_cycle))[1::2]: this_data = aoa_data[aoa] pressure = this_data[0] # Extrapolate Aerofoil Tip p1 = (PITOT_PLACEMENT[9], pressure.iloc[9]) p2 = (PITOT_PLACEMENT[18], pressure.iloc[18]) pN = (0.9*CHORD_LEN, p2[1] + (p1[1]-p2[1])/2) plts = ( {"x": PITOT_PLACEMENT[:10], "y":pressure[:10], "colour": c["color"]}, {"x": PITOT_PLACEMENT[10:], "y":pressure[10:], "colour": c["color"]}, {"x": [PITOT_PLACEMENT[0], PITOT_PLACEMENT[10]], "y": [pressure.iloc[0], pressure.iloc[10]], "colour": c["color"]}, #{"x": [PITOT_PLACEMENT[9], PITOT_PLACEMENT[18]], "y": [pressure.iloc[9], pressure.iloc[18]], "colour": c["color"]}, {"x": [PITOT_PLACEMENT[9], pN[0]], "y": [pressure.iloc[9], pN[1]], "colour": c["color"], "args":{"alpha":0.3}}, {"x": [PITOT_PLACEMENT[9], pN[0]], "y": [pressure.iloc[18], pN[1]], "colour": c["color"], "args":{"alpha":0.3}}, {"x":PITOT_PLACEMENT, "y":pressure, "label":f"α = {int(aoa):d}°", "type":"scatter", "colour": c["color"], "args":{"zorder":2}}, ) for plt in plts: graph["plots"].append(plt) makeGraph(graph, False, figSavePath="./images/pressure/__{0}.png") if True: aoa = [a[-2] for a in cp_pain_data][1::2] forces = [a[-1] for a in cp_pain_data][1::2] # Force Graphs graph = { "title": f"All Total, Lift & Drag Forces\nfor a Clark Y 14% Aerofoil at:\n{raw_data["rpm"]:d}rpm - {raw_data["airSpeed"]:.1f}m/s)", "windowTitle": f"All Total, Lift and Drag Forces for a Clark Y 14 Percent Airfoil - {raw_data["rpm"]:d}rpm - {raw_data["airSpeed"]:.1f}m_s", "xLabel": "Attack Angle [$\\alpha$]", "yLabel": "Force [N]", "grid": True, "ledgLoc": 1, "plots": [ {"x":aoa, "y":[f[0] for f in forces], "label":"Total Force"}, {"x":aoa, "y":[f[1] for f in forces], "label":"Lift"}, {"x":aoa, "y":[f[2] for f in forces], "label":"Drag"}, ] } makeGraph(graph, False, figSavePath="./images/{0}.png", closeFig=True) print("\n\n") print(raw_data["rpm"]) print("AoA Total Lift Drag ---- Upper Force Lower Force ") for aoa, force in [(a[-2], a[-1]) for a in cp_pain_data]: print(f"{aoa:d}\\textdegree & {force[0]:.3f} & {force[1]:.3f} & {force[2]:.3f} -- {force[4]:.3f} {force[5]:.3f} \\\\") print("-"*50) print("\n\n") print("Generating Cp Graphs") cp_data = {} for raw_data in tqdm((data_508rpm, data_1000rpm), position=0): cp_pain_data = [] for aoa in tqdm(raw_data["AoA"], position=1): this_data = data[raw_data["rpm"]][aoa] cp_data_this = make_cp_graph(this_data[0], aoa, raw_data["rpm"], raw_data["airSpeed"], this_data[2], True) cp_pain_data.append(cp_data_this) cp_data[raw_data["rpm"]] = cp_pain_data if True: # All graph = { "title": f"All $C_p$ vs Pitot Placement along Chord\nfor a Clark Y 14% Aerofoil at:\n{raw_data["rpm"]:d}rpm - {raw_data["airSpeed"]:.1f}m/s)", "windowTitle": f"All Cp along Clark Y 14 Percent Airfoil - {raw_data["rpm"]:d}rpm - {raw_data["airSpeed"]:.1f}m_s", "xLabel": "Pitot Placement [m]", "yLabel": "$C_p$", "grid": True, "ledgLoc": 1, "plots": [], } colour_cycle = uqccf() for this_data, c in zip(cp_pain_data, colour_cycle): cp = this_data[0] # Extrapolate Aerofoil Tip p1, p2, pN = this_data[2] plts = ( # Draw Lines {"x": PITOT_PLACEMENT_CHORD_NORM[:10], "y":cp[:10], "colour": c["color"]}, {"x": PITOT_PLACEMENT_CHORD_NORM[10:], "y":cp[10:], "colour": c["color"]}, {"x": [PITOT_PLACEMENT_CHORD_NORM[0], PITOT_PLACEMENT_CHORD_NORM[10]], "y": [cp.iloc[0], cp.iloc[10]], "colour": c["color"]}, # Draw Extrapolated Airfoil Tip {"x": [PITOT_PLACEMENT_CHORD_NORM[9], pN[0]], "y": [cp.iloc[9], pN[1]], "colour": c["color"], "args":{"alpha":0.3}}, {"x": [PITOT_PLACEMENT_CHORD_NORM[9], pN[0]], "y": [cp.iloc[18], pN[1]], "colour": c["color"], "args":{"alpha":0.3}}, # Draw Points & text {"x":PITOT_PLACEMENT_CHORD_NORM, "y":cp, "label":f"α = {int(this_data[-1]):d}°", "type":"scatter", "args":{"zorder":2}, "colour": c["color"]}, ) for plt in plts: graph["plots"].append(plt) if raw_data["rpm"] == 508: #graph['xLim'] = ( # min(PITOT_PLACEMENT_CHORD_NORM) - 0.5, # max(PITOT_PLACEMENT_CHORD_NORM) + 0.5 #) graph["figSize"] = (8, 6) makeGraph(graph, False, figSavePath="./images/cp/__{0}.png", closeFig=True) graph["title"] = f"$C_p$ vs Pitot Placement along Chord\nfor a Clark Y 14% Aerofoil at:\n{raw_data["rpm"]:d}rpm - {raw_data["airSpeed"]:.1f}m/s)" graph["windowTitle"] = f"Cp along Clark Y 14 Percent Airfoil - {raw_data["rpm"]:d}rpm - {raw_data["airSpeed"]:.1f}m_s" graph["plots"] = [] colour_cycle = uqccf() for this_data, c in list(zip(cp_pain_data, colour_cycle))[1::2]: cp = this_data[0] # Extrapolate Aerofoil Tip p1, p2, pN = this_data[2] plts = ( # Draw Lines {"x": PITOT_PLACEMENT_CHORD_NORM[:10], "y":cp[:10], "colour": c["color"]}, {"x": PITOT_PLACEMENT_CHORD_NORM[10:], "y":cp[10:], "colour": c["color"]}, {"x": [PITOT_PLACEMENT_CHORD_NORM[0], PITOT_PLACEMENT_CHORD_NORM[10]], "y": [cp.iloc[0], cp.iloc[10]], "colour": c["color"]}, # Draw Extrapolated Airfoil Tip {"x": [PITOT_PLACEMENT_CHORD_NORM[9], pN[0]], "y": [cp.iloc[9], pN[1]], "colour": c["color"], "args":{"alpha":0.3}}, {"x": [PITOT_PLACEMENT_CHORD_NORM[9], pN[0]], "y": [cp.iloc[18], pN[1]], "colour": c["color"], "args":{"alpha":0.3}}, # Draw Points & text {"x":PITOT_PLACEMENT_CHORD_NORM, "y":cp, "label":f"α = {int(this_data[-1]):d}°", "type":"scatter", "args":{"zorder":2}, "colour": c["color"]}, ) for plt in plts: graph["plots"].append(plt) makeGraph(graph, False, figSavePath="./images/cp/__{0}.png", closeFig=True) print("Complete")