balloon-calc/notebooks/hotair-pyramid.ipynb

377 wiersze
14 KiB
Plaintext
Czysty Wina Historia

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"cells": [
{
"cell_type": "markdown",
"id": "c6b2e4d0-bf43-4a8a-a8e7-4fa081d61317",
"metadata": {
"extensions": {
"jupyter_dashboards": {
"activeView": "grid_default",
"views": {
"grid_default": {
"col": 0,
"height": 1,
"hidden": false,
"row": 0,
"width": 1
}
}
}
},
"tags": []
},
"source": [
"## Hot air balloon - lift calculator\n",
"### Inverted pyramid shape\n",
"[Source code](https://gitea.citizen4.eu/sp9unb/balloon-calc) \n",
"\n",
"[Run in mybinder.org IDE](https://mybinder.org/v2/git/https%3A%2F%2Fgitea.citizen4.eu%2Fsp9unb%2Fballoon-calc/HEAD?labpath=work%2Fhotair-pyramid.ipynb) "
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "6ea87a15-f571-4611-8487-5b7556e2ef45",
"metadata": {
"extensions": {
"jupyter_dashboards": {
"activeView": "grid_default",
"views": {
"grid_default": {
"col": null,
"height": 2,
"hidden": true,
"row": null,
"width": 2
}
}
}
}
},
"outputs": [],
"source": [
"# https://pythreejs.readthedocs.io\n",
"from pythreejs import *\n",
"from IPython.display import HTML,display\n",
"from math import pi\n",
"\n",
"# https://ipywidgets.readthedocs.io\n",
"import ipywidgets as widgets\n",
"from ipywidgets import Layout\n",
"\n",
"# https://pypi.org/project/termcolor/\n",
"from termcolor import colored\n",
"\n",
"#from scipy.interpolate import interp1d\n",
"#import numpy as np\n",
"\n",
"#math\n",
"from math import sin, tan, sqrt"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "d075a994-76bb-46f7-bdfb-cc6ef449dc43",
"metadata": {
"extensions": {
"jupyter_dashboards": {
"activeView": "grid_default",
"views": {
"grid_default": {
"col": null,
"height": 2,
"hidden": true,
"row": null,
"width": 2
}
}
}
}
},
"outputs": [],
"source": [
"# air density–temperature relationship at 1 atm or 101.325 kPa\n",
"# https://en.wikipedia.org/wiki/Density_of_air\n",
"# https://www.engineersedge.com/calculators/air-density.htm\n",
"# temp in st.C density in g/m3\n",
"\n",
"#temp = [-25,-20,-15,-10,-5,0,5,10,15,20,25,30,35]\n",
"#dens = [1422.4,1394.3,1367.3,1341.3,1316.3,1292.2,1269.0,1246.6,1225.0,1204.1,1183.9,1164.4,1145.5]\n",
"#dens_temp_func = interp1d(temp, dens)\n",
"\n",
"\n",
"def airDensity(temp=0.0):\n",
" tempK = temp + 273.0 # absolute temperature [K]\n",
" p = 101325.0 # pressure [Pa]\n",
" rSpec = 287.0500676 # specific gas constant for dry air [J⋅kg1⋅K1]\n",
" return 1000.0 * p / ( rSpec * tempK )"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "612a3232-e9cb-4405-86dd-bd60ac09cd2f",
"metadata": {},
"outputs": [],
"source": [
"# Ascent rate at ground level\n",
"# https://northstar-www.dartmouth.edu/~klynch/pmwiki-gc/uploads/BalloonCalulations.pdf\n",
"\n",
"# Coefficient of Drag assumed to 0.285 (spherical top) \n",
"Cd = 0.285\n",
"g = 9.81 # [m/s2]\n",
"\n",
"def ascentRate(volume=1.0, airDens=1.0, liftForce=1.0, topArea=1.0): \n",
" val = ( 2 * liftForce * g ) / ( Cd * airDens * topArea )\n",
" if val < 0.0:\n",
" val = 0.0\n",
" return sqrt( val )\n"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "229c0a36-bf1f-4c07-884c-f3522d5eaae5",
"metadata": {},
"outputs": [],
"source": [
"# math: https://pl.wikipedia.org/wiki/Wielok%C4%85t_foremny\n",
"\n",
"# radius of the circle described on the polygon\n",
"def outradius(a=1.0,n=3):\n",
" return a / ( 2 * sin( pi / n ))\n",
"\n",
"# radius of the circle inscribed in the polygon\n",
"def inradius(a=1.0,n=3):\n",
" return a / ( 2 * tan( pi / n )) \n",
"\n",
"# edge length\n",
"def edge_len(r=1.0,h=1.0):\n",
" return sqrt(pow(r,2) + pow(h,2))\n",
"\n",
"#pyramid area/volume\n",
"def base_area(a=1.0,n=3):\n",
" return 0.5 * n * pow(outradius(a,n),2) * sin( 2 * pi / n)\n",
"\n",
"def volume(a=1.0,h1=1.0,h2=1.0,n=3):\n",
" return base_area(a,n) * ( h1 + h2 ) / 3\n",
" \n",
"def surface_area(a=1.0,h1=1.0,h2=1.0,n=3):\n",
" return 0.5 * a * n * ( sqrt( pow(h1,2) + pow(inradius(a,n),2)) + sqrt( pow(h2,2) + pow(inradius(a,n),2)) )\n",
" \n"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "2f3b63fd-d5ea-40b6-a2f9-b31c84cfef36",
"metadata": {
"extensions": {
"jupyter_dashboards": {
"activeView": "grid_default",
"views": {
"grid_default": {
"col": null,
"height": 2,
"hidden": true,
"row": null,
"width": 2
}
}
}
}
},
"outputs": [
{
"data": {
"text/html": [
"<style>\n",
" .widget-hbox { margin-top: 20px; }\n",
" </style>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "3db54b9e2ef24677a45a78c94e21ed79",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(IntSlider(value=3, description='Segment num:', layout=Layout(width='500px'), max=12, min=3, sty…"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def f(num,width,heightT,heightB,airTemp,hotAirTemp,coatDens,tapeDens,payloadWeight):\n",
"\n",
" out=widgets.Output(layout={'margin': '10px 10px 10px 20px'}) \n",
" with out: \n",
" # Volume\n",
" vol = volume(width,heightB,heightT,num)\n",
" print( \"{:<20}{:>6.1f} [m3]\".format(\"Volume:\",vol)) \n",
" # Area\n",
" area = surface_area(width,heightB,heightT,num)\n",
" print( \"{:<20}{:>6.1f} [m2]\".format(\"Area:\",area)) \n",
" # Coating density (from: protective film for painting): 300g / 4x5m = 15g/m2 \n",
" coatingWeight = coatDens * area\n",
" print( \"{:<20}{:>6.1f} [g]\".format(\"Coating weight:\",coatingWeight)) \n",
" # adhesive tape density : average 2g/m \n",
" tapeLength = num * ( edge_len(outradius(width,num),heightT) + edge_len(outradius(width,num),heightB) )\n",
" tapeWeight = tapeDens * tapeLength\n",
" print( \"{:<20}{:>6.1f} [m]\".format(\"Adh.tape length:\",tapeLength)) \n",
" print( \"{:<20}{:>6.1f} [g]\".format(\"Adh.tape weight:\",tapeWeight)) \n",
" totalWeight = coatingWeight + tapeWeight\n",
" print( \"{:<20}{:>6.1f} [g]\".format(\"Total ball. weight:\",totalWeight)) \n",
" # Lift per volume g/m3 \n",
" # airDens = dens_temp_func( airTemp )\n",
" # hotAirDens = dens_temp_func( hotAirTemp ) \n",
" airDens = airDensity( airTemp )\n",
" hotAirDens = airDensity( hotAirTemp ) \n",
" lift = airDens - hotAirDens\n",
" print( \"{:<20}{:>6.1f} [g/m3]\".format(\"Lift/volume:\",lift)) \n",
" # Total lift force lift * volume \n",
" totalLiftForce = lift * vol\n",
" print( \"{:<20}{:>6.1f} [g]\".format(\"Total lift force:\",totalLiftForce)) \n",
" # Free lift force totalLiftForce - coatingWeight \n",
" freeLiftForce = totalLiftForce - totalWeight - payloadWeight\n",
" if freeLiftForce < 0:\n",
" color = 'red'\n",
" else:\n",
" color = None\n",
" print( colored(\"{:<20}{:>6.1f} [g]\".format(\"Free lift force:\",freeLiftForce),color)) \n",
" # Ascent rate \n",
" topArea = base_area(width,num)\n",
" ascRate = ascentRate(volume, airDens/1000.0, freeLiftForce/1000.0, topArea)\n",
" print( \"{:<20}{:>6.1f} [m/s]\".format(\"Ascent rate:\",ascRate)) \n",
" \n",
"# coating geometry \n",
" bottomGeometry = CylinderBufferGeometry(\n",
" radiusTop=outradius(width,num), \n",
" radiusBottom=0.0, \n",
" height=heightB, \n",
" radialSegments=num, \n",
" heightSegments=1, \n",
" openEnded=True, \n",
" thetaStart=0, \n",
" thetaLength=2.0*pi)\n",
" \n",
" bottomCylinder = Mesh(bottomGeometry,\n",
" material=MeshLambertMaterial(color='#c0c0c0'),\n",
" position=[0,0,0] \n",
" )\n",
" \n",
" zTop = ( heightB + heightT ) / 2.0\n",
" topGeometry = CylinderBufferGeometry(\n",
" radiusTop=0.0, \n",
" radiusBottom=outradius(width,num), \n",
" height=heightT, \n",
" radialSegments=num, \n",
" heightSegments=1, \n",
" openEnded=True, \n",
" thetaStart=0, \n",
" thetaLength=2.0*pi)\n",
" \n",
" topCylinder = Mesh(topGeometry,\n",
" material=MeshLambertMaterial(color='#c0c0c0'),\n",
" position=[0,zTop,0] \n",
" ) \n",
" \n",
" keyLight = DirectionalLight(color='white', position=[3, 5, 1], intensity=0.5)\n",
"\n",
" c = PerspectiveCamera(position=[2, 2, 6], up=[0, 1, 0], children=[keyLight])\n",
"\n",
" scene = Scene(children=[bottomCylinder,topCylinder, c, AmbientLight(color='#777777')], background=None)\n",
"\n",
" renderer = Renderer(camera=c,\n",
" scene=scene,\n",
" alpha=True,\n",
" clearOpacity=1.0,\n",
" clearColor='#62a0ea',\n",
" controls=[OrbitControls(controlling=c)])\n",
" display(widgets.HBox([renderer, out])) \n",
"\n",
"\n",
"\n",
"display(HTML('''<style>\n",
" .widget-hbox { margin-top: 20px; }\n",
" </style>'''))\n",
"\n",
"layout=Layout(width='500px')\n",
"style = {'description_width': 'initial'}\n",
" \n",
"num=widgets.IntSlider(min=3, max=12, step=1, value=3, description='Segment num:',layout=layout,style=style) \n",
"width=widgets.FloatSlider(min=0.1, max=5.0, step=0.1, value=3.0, description='Segment width [m]:',readout_format='.1f',layout=layout,style=style) \n",
"heightT=widgets.FloatSlider(min=0.1, max=5.0, step=0.1, value=1.0, description='Height top [m]:',readout_format='.1f',layout=layout,style=style) \n",
"heightB=widgets.FloatSlider(min=0.1, max=5.0, step=0.1, value=2.0, description='Height bottom [m]:',readout_format='.1f',layout=layout,style=style) \n",
"airTemp=widgets.FloatSlider(min=-40, max=35, step=1.0, value=10.0, description='Air temp.[°C]:',readout_format='.0f',layout=layout,style=style) \n",
"hotAirTemp=widgets.FloatSlider(min=-40, max=55, step=1.0, value=35.0, description='Hot air temp.[°C]:',readout_format='.0f',layout=layout,style=style)\n",
"coatDens=widgets.FloatSlider(min=1, max=50, step=1.0, value=15.0, description='Coating density [g/m2]:',readout_format='.0f',layout=layout,style=style) \n",
"tapeDens=widgets.FloatSlider(min=0.5, max=10, step=0.5, value=2.0, description='Adh. tape density [g/m]:',readout_format='.1f',layout=layout,style=style)\n",
"payloadWeight=widgets.FloatSlider(min=0.0, max=1000.0, step=1, value=0.0, description='Payload weight [g]:',readout_format='.0f',layout=layout,style=style)\n",
" \n",
"w = widgets.interactive_output(f, { 'num' : num,\n",
" 'width' : width,\n",
" 'heightT' : heightT,\n",
" 'heightB' : heightB,\n",
" 'airTemp' : airTemp,\n",
" 'hotAirTemp' : hotAirTemp,\n",
" 'coatDens' : coatDens,\n",
" 'tapeDens' : tapeDens,\n",
" 'payloadWeight' : payloadWeight\n",
" }\n",
" )\n",
"\n",
"widgets.VBox([num, width, heightT, heightB, airTemp, hotAirTemp, coatDens,tapeDens,payloadWeight, w])\n"
]
}
],
"metadata": {
"extensions": {
"jupyter_dashboards": {
"activeView": "grid_default",
"version": 1,
"views": {
"grid_default": {
"cellMargin": 2,
"defaultCellHeight": 60,
"maxColumns": 12,
"name": "grid",
"type": "grid"
}
}
}
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}