import%20marimo%0A%0A__generated_with%20%3D%20%220.14.10%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%23%20CAS%20TAS%20Mach%0A%0A%20%20%20%20The%20relationship%20between%20calibrated%20airspeed%20(CAS)%2C%20true%20airspeed%20(TAS)%20and%20Mach%20versus%20altitude%20can%20be%20plotted%20using%20the%0A%20%20%20%20%60plotCASTASMach()%60%20function%20provided%20below.%0A%0A%20%20%20%20Using%20the%20%5BInternational%20Standard%20Atmosphere%5D(InternationalStandardAtmosphere.html)%20class%20and%20the%20utility%20airspeed%0A%20%20%20%20functions%20it%20provides%20we%20can%20plot%20lines%20of%20constant%20CAS%20and%20Mach%20based%20on%20TAS%20and%20altitude.%0A%0A%20%20%20%20The%20%60plotCASTASMach()%60%20allows%20you%20to%20specify%20custom%20plot%20ranges%20for%20altitude%2C%20TAS%2C%20CAS%20and%20Mach%20and%20to%20specify%20the%20step%20%0A%20%20%20%20interval%20for%20CAS%20and%20Mach.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plotCASTASMach)%3A%0A%20%20%20%20plotCASTASMach(minAlt%3D0%2C%20maxAlt%3D60000%2C%20minTAS%3D0%2C%20maxTAS%3D1000%2C%20minCAS%3D50%2C%20maxCAS%3D700%2C%20casStep%3D50%2C%20minMach%3D0.2%2C%20maxMach%3D1.6%2C%20machStep%3D0.1)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plotCASTASMach)%3A%0A%20%20%20%20plotCASTASMach(minAlt%3D0%2C%20maxAlt%3D40000%2C%20minTAS%3D100%2C%20maxTAS%3D500%2C%20minCAS%3D125%2C%20maxCAS%3D450%2C%20casStep%3D25%2C%20minMach%3D0.3%2C%20maxMach%3D0.8%2C%20machStep%3D0.1)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%23%20Plot%20Routine%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20from%20ISA%20import%20ISAtmosphere%2C%20CAStoTAS%2C%20TAStoCAS%0A%20%20%20%20%23from%20labellines%20import%20labelLines%0A%0A%20%20%20%20max_altitude%20%3D%2060000%0A%0A%20%20%20%20ISA%20%3D%20ISAtmosphere()%0A%0A%20%20%20%20def%20SpeedOfSound(altitude)%3A%0A%20%20%20%20%20%20%20%20_%2C%20_%2C%20_%2C%20speed_of_sound%20%3D%20ISA.state(ftTom(altitude))%0A%20%20%20%20%20%20%20%20return%20msTokt(speed_of_sound)%0A%0A%20%20%20%20def%20tas2mach(tas%2C%20alt%3Dmax_altitude)%3A%0A%20%20%20%20%20%20%20%20return%20tas%20%2F%20SpeedOfSound(alt)%0A%0A%20%20%20%20def%20mach2tas(mach%2C%20alt%3Dmax_altitude)%3A%0A%20%20%20%20%20%20%20%20return%20SpeedOfSound(alt)%20*%20mach%0A%0A%20%20%20%20def%20ftTom(ft)%3A%0A%20%20%20%20%20%20%20%20return%20ft%20%2F%203.28084%0A%0A%20%20%20%20def%20mToft(m)%3A%0A%20%20%20%20%20%20%20%20return%20m%20*%203.28084%0A%0A%20%20%20%20def%20msTokt(ms)%3A%0A%20%20%20%20%20%20%20%20return%20ms%20*%201.944012%0A%0A%20%20%20%20def%20ktToms(kt)%3A%0A%20%20%20%20%20%20%20%20return%20kt%20%2F%201.944012%20%0A%0A%0A%20%20%20%20def%20plotCASTASMach(minAlt%2C%20maxAlt%2C%20minTAS%2C%20maxTAS%2C%20minCAS%2C%20maxCAS%2C%20casStep%2C%20minMach%2C%20maxMach%2C%20machStep)%3A%0A%0A%20%20%20%20%20%20%20%20max_altitude%20%3D%20maxAlt%0A%0A%20%20%20%20%20%20%20%20fig%2C%20ax%20%3D%20plt.subplots(layout%3D'constrained'%2C%20figsize%3D(10%2C%205))%0A%0A%20%20%20%20%20%20%20%20ax.margins(y%3D0)%0A%0A%20%20%20%20%20%20%20%20%23%20Plot%20Mach%20lines%0A%20%20%20%20%20%20%20%20alt%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20altitude%20in%20range(int(ftTom(minAlt))%2C%20int(ftTom(maxAlt))%2B1%2C%201000)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20alt.append(mToft(altitude))%0A%20%20%20%20%20%20%20%20alt.append(maxAlt)%0A%0A%20%20%20%20%20%20%20%20for%20mach%20in%20np.arange(minMach%2C%20maxMach%2B0.01%2C%20machStep)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20tas%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20altitude%20in%20alt%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_%2C%20_%2C%20_%2C%20speed_of_sound%20%3D%20ISA.state(ISA.geometric_altitude(ftTom(altitude)))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tas.append(msTokt(speed_of_sound%20*%20mach))%0A%20%20%20%20%20%20%20%20%20%20%20%20ax.plot(tas%2C%20alt%2C%20color%3D'gray')%0A%0A%20%20%20%20%20%20%20%20%23%20Plot%20CAS%20lines%0A%20%20%20%20%20%20%20%20for%20cas%20in%20range(minCAS%2C%20maxCAS%2B1%2C%20casStep)%3A%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20tas%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20alt%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20altitude%20in%20range(0%2C%20max_altitude%2B1%2C%201000)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tas.append(msTokt(CAStoTAS(ktToms(cas)%2C%20ftTom(altitude))))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alt.append(altitude)%0A%20%20%20%20%20%20%20%20%20%20%20%20ax.plot(tas%2C%20alt%2C%20label%3Df'%7Bcas%7DKCAS')%0A%0A%20%20%20%20%20%20%20%20ax.set_xlabel('TAS%20(kts)')%0A%20%20%20%20%20%20%20%20ax.set_ylabel('Altitude%20(ft)')%0A%20%20%20%20%20%20%20%20ax.set_title('CAS%20TAS%20Mach')%0A%20%20%20%20%20%20%20%20ax.set_xlim(minTAS%2C%20maxTAS)%0A%0A%20%20%20%20%20%20%20%20secax%20%3D%20ax.secondary_xaxis('top'%2C%20functions%3D(tas2mach%2C%20mach2tas))%0A%20%20%20%20%20%20%20%20secax.set_xlabel('Mach')%0A%20%20%20%20%20%20%20%20plt.legend()%0A%20%20%20%20%20%20%20%20plt.grid(True%2C%20linestyle%3D'--')%0A%0A%20%20%20%20%20%20%20%20return%20plt.gca()%0A%0A%20%20%20%20return%20(plotCASTASMach%2C)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20return%20(mo%2C)%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
4647e8ceb6cf4d77d6ef5f8e0ff68ba292ba7e9d888eaa2a55e6164a0ede9010