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(r%22%22%22%23%20Climb%20Performance%22%22%22)%0A%20%20%20%20return%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%20rf%22%22%22%0A%20%20%20%20%23%23%20TECS%20Trigger%0A%0A%20%20%20%20A%20%5BFacebook%20post%5D(https%3A%2F%2Fwww.facebook.com%2Fshare%2Fp%2F1VcBovxhNS%2F)%20by%20Agostino%20De%20Marco%20regarding%20an%20optimal%20time%20to%20%0A%20%20%20%20climb%20profile%20making%20use%20of%20an%20autopilot%20based%20on%20the%20Total%20Energy%20Control%20System%20(TECS)%20triggered%20my%20interest%20in%20%0A%20%20%20%20the%20topic%20of%20climb%20performance.%0A%0A%20%20%20%20%7Bmo.image('public%2FClimbPerformance%2FTECSROC.jpg')%7D%0A%0A%20%20%20%20I%20asked%20how%20the%20contour%20plot%20of%20rate%20of%20climb%20(ROC)%20against%20altitude%20and%20airspeed%20was%20generated%3A%0A%0A%20%20%20%20%3E%20You%20trim%20the%20model%20for%20those%20%22operating%20points%22%20in%20level%20flight.%20For%20each%20point%20you%20calculate%20the%20maximum%20excess%20thrust%20and%20maximum%20excess%20power%20w.r.t.%20the%20level-flight%20required%20values.%20Those%20quantities%20divided%20by%20A%2FC%20weight%20give%20you%20the%20maximum%20attainable%20flight%20path%20angle%20and%20RoC.%0A%0A%20%20%20%20Lastly%20Agostino%20mentioned%20that%3A%0A%0A%20%20%20%20%3E%20another%20interesting%20fact%20emerging%20from%20this%20max-RoC%20tracking%20simulation%20is%20that%2C%20while%20climbing%2C%20the%20max%20performance%20condition%20is%20perfectly%20pursued%3B%20yet%20this%20optimal%20climb%20is%20achieved%20by%20an%20energy-based%20MIMO%20control%20known%20as%20TECS%2C%20with%20**no%20need%20to%20push%20the%20throttle%20setting%20to%20its%20max**.%20A%20nice%20combination%20of%20elevator%20and%20throttle%20laws%20does%20the%20job%20nicely.%0A%0A%20%20%20%20Let's%20take%20a%20look%20at%20the%20basic%20climb%20performance%20theory%20and%20use%20JSBSim%20to%20test%20and%20compare%20the%20results%20with%20the%20theory%20and%20then%20look%0A%20%20%20%20at%20the%20TECS%20based%20max-ROC%20autopilot%20performance.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%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%20rf%22%22%22%0A%20%20%20%20%23%23%20Theory%0A%0A%20%20%20%20For%20a%20steady%2Fnon-accelerating%20climb.%0A%0A%20%20%20%20%7Bmo.image('public%2FClimbPerformance%2FAnglesForces.png'%2C%20width%3D400%2C%20caption%3D'Figure%201')%7D%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%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%24%24%0A%20%20%20%20%5Cbegin%7Balign%7D%0A%20%20%20%20T%20-%20D%20-%20W%20%5Csin%20%5Ctheta%20%26%3D%200%20%20%5Ctag%7B1%7D%20%5C%5C%0A%20%20%20%20%5Cnonumber%20%5C%5C%0A%20%20%20%20L%20-%20W%20%5Ccos%20%5Ctheta%20%26%3D%200%20%20%5Ctag%7B2%7D%0A%20%20%20%20%5Cend%7Balign%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20vertical%20component%20of%20the%20velocity%20is%20the%20**rate%20of%20climb**%20(%24R%2FC%24)%20of%20the%20aircraft.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Balign%7D%0A%20%20%20%20R%2FC%20%26%3D%20V_%7B%5Cinfty%7D%20%5Csin%20%5Ctheta%20%20%5Ctag%7B3%7D%20%5C%5C%0A%20%20%20%20%5Cnonumber%20%5C%5C%0A%20%20%20%20V_%7B%5Cinfty%7D%20%5Csin%20%5Ctheta%20%3D%20R%2FC%20%26%3D%20%5Cfrac%7BT%20V_%7B%5Cinfty%7D%20-%20D%20V_%7B%5Cinfty%7D%7D%7BW%7D%20%20%5Ctag%7B4%7D%20%5C%5C%0A%20%20%20%20%5Cnonumber%20%5C%5C%0A%20%20%20%20Excess%5C%20Power%20%26%3D%20T%20V_%7B%5Cinfty%7D%20-%20D%20V_%7B%5Cinfty%7D%20%20%5Ctag%7B5%7D%0A%20%20%20%20%5Cend%7Balign%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20**Question%3A**%20Assumption%20appears%20to%20be%20that%20%24%5Calpha%24%20is%20very%20small%20so%20%24%5Ctheta%20%5Capprox%20%5Cgamma%24%3F%0A%0A%20%20%20%20**Answer%3A**%20Came%20across%20the%20following%20in%20%5BFlight%20Dynamics%20-%20Robert%20Stengel%5D(https%3A%2F%2Fstengel.mycpanel.princeton.edu%2FFlightDynamics.html)%0A%0A%20%20%20%20%3E%20If%20the%20thrust%20is%20parallel%20to%20the%20aircraft%20centerline%2C%20it%20is%20offset%20from%20the%20velocity%20vector%0A%20%20%20%20%3E%20by%20the%20aircraft's%20angle%20of%20attack%2C%20and%20specific%20excess%20power%2C%20or%20excess%20power%20per%20unit%20of%20weight%0A%20%20%20%20%3E%20is%0A%20%20%20%20%3E%20%24SEP%20%3D%20%5Cdfrac%7BV(T%20%5Ccos%20%5Calpha%20-%20D)%7D%7BW%7D%24%0A%0A%20%20%20%20Then%20mentions%20%24%5Ccos%20%5Calpha%20%5Capprox%201%24%20so%20drops%20it%20from%20the%20rest%20of%20the%20equations.%0A%0A%20%20%20%20The%20power%20required%2C%20%24P_R%24%2C%20which%20is%20equal%20to%20%24DV_%5Cinfty%24%2C%20for%20level%20flight%20at%20a%20particular%20%0A%20%20%20%20altitude%20is%20calculated%20for%20and%20plotted%20against%20a%20range%20of%20true%20airspeeds%20%24V_%5Cinfty%24.%20%0A%20%20%20%20The%20maximum%20power%20available%2C%20%24P_A%24%2C%20which%20is%20equal%20to%20%24TV_%5Cinfty%24%20at%20the%20particular%20altitude%20%0A%20%20%20%20is%20also%20plotted%20against%20%24V_%5Cinfty%24.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(rf%22%22%22%7Bmo.image('public%2FClimbPerformance%2FExcessPowerPropellor.png'%2C%20width%3D400%2C%20caption%3D'Figure%202')%7D%22%22%22)%0A%20%20%20%20return%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%24%24R%2FC%20%3D%20%5Cfrac%7BExcess%5C%20Power%7D%7BW%7D%20%20%5Ctag%7B6%7D%24%24%0A%0A%20%20%20%20The%20true%20airspeed%20at%20which%20the%20maximum%20rate%20of%20climb%20occurs%20for%20a%20particular%20altitude%2C%20%24V_%7B%7B(R%2FC)_%7Bmax%7D%7D%7D%24%2C%20%0A%20%20%20%20occurs%20at%20the%20airspeed%20where%20excess%20power%20is%20a%20maximum.%0A%0A%20%20%20%20For%20a%20jet%20engine%20the%20thrust%20is%20essentially%20constant%20with%20velocity%2C%20therefore%20the%20power%20available%2C%20%24P_A%24%20has%20a%20linear%0A%20%20%20%20relationship%20to%20%24V_%5Cinfty%24%20resulting%20in%20the%20following%20graph.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(rf%22%22%22%7Bmo.image('public%2FClimbPerformance%2FExcessPowerJet.png'%2C%20width%3D400%2C%20caption%3D'Figure%203')%7D%22%22%22)%0A%20%20%20%20return%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%20rf%22%22%22%0A%20%20%20%20%23%23%23%20Hodograph%20Diagram%0A%0A%20%20%20%20Is%20a%20plot%20of%20the%20aircraft's%20vertical%20velocity%20%24V_V%24%20versus%20its%20horizontal%20velocity%20%24V_H%24.%20Consider%20an%0A%20%20%20%20arbitary%20point%20on%20the%20hodograph%20curve%2C%20denoted%20by%20point%201.%20Draw%20a%20line%20from%20the%20origin%20to%20point%201.%0A%20%20%20%20Geometrically%2C%20the%20length%20of%20the%20line%20is%20%24V%24%2C%20and%20the%20angle%20it%20makes%20with%20the%20horizontal%20axis%20is%20the%0A%20%20%20%20corresponding%20climb%20angle%20at%20that%20velocity.%0A%0A%20%20%20%20Point%202%20denotes%20the%20maximum%20%24R%2FC%24%3B%20the%20length%20of%20the%20line%20from%20the%20origin%20to%20point%202%20is%20the%20aircraft's%0A%20%20%20%20velocity%20at%20maxmum%20%24R%2FC%24%20and%20the%20angle%20it%20makes%20with%20the%20horizontal%20axis%20is%20the%20climb%20angle%20for%20maximum%20%24R%2FC%24.%0A%0A%20%20%20%20A%20line%20drawn%20from%20the%20origin%20and%20tangent%20to%20the%20hodograph%20curve%20locates%20point%203.%20The%20angle%20of%20this%20line%20relative%0A%20%20%20%20to%20the%20horizontal%20axis%20defines%20the%20maximum%20possible%20climb%20angle.%0A%0A%20%20%20%20%7Bmo.image('public%2FClimbPerformance%2FHodograph.png'%2C%20width%3D400%2C%20caption%3D'Figure%204')%7D%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%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%20In%20aircraft%20flight%20manuals%20%24V_%7B%5Ctheta_%7Bmax%7D%7D%24%20is%20typically%20denoted%20as%20%24V_x%24%20and%20%24V_%7B%7B(R%2FC)%7D_%7Bmax%7D%7D%24%20as%20%24V_y%24%20after%20%0A%20%20%20%20being%20converted%20to%20IAS.%0A%0A%20%20%20%20So%20climbing%20at%20an%20airspeed%20of%20%24V_x%24%20will%20give%20you%20the%20steepest%20climb%20possible%2C%20useful%20for%20clearing%20obstacles%0A%20%20%20%20whereas%20climbing%20at%20an%20airspeed%20of%20%24V_y%24%20will%20give%20you%20the%20fastest%20climb%20rate%20possible%2C%20both%20for%20a%20particular%0A%20%20%20%20altitude%2C%20i.e.%20%24V_x%24%20and%20%24V_y%24%20will%20vary%20with%20altitude.%20Note%20%24V_x%24%20and%20%24V_y%24%20will%20be%20specified%20as%20CAS%20and%20not%20TAS.%0A%0A%20%20%20%20Another%20way%20of%20calulating%20the%20airspeed%20for%20the%20steepest%20climb%20is%20to%20plot%20thrust%20available%20%24T_A%24%20versus%20true%20airspeed%20and%0A%20%20%20%20drag%2Fthrust%20required%20%24T_R%24%20versus%20true%20airspeed%20for%20level%20flight.%20The%20airspeed%20at%20which%20%24T_A%20-%20T_R%24%20is%20a%20maximum%20will%0A%20%20%20%20determine%20the%20airspeed%20for%20the%20steepest%20climb.%20In%20other%20words%20using%20thrust%20as%20opposed%20to%20power.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%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%23%20Using%20JSBSim%20to%20Test%20and%20Compare%0A%0A%20%20%20%20We'll%20use%20the%20Boeing%20737%20model%20from%20the%20JSBSim%20repo.%0A%0A%20%20%20%20The%20thrust%20factor%20table%20for%20the%20737's%20CFM56%20jet%20engine%20based%20on%20density%20altitude%20and%20Mach%20shows%0A%20%20%20%20that%20there%20is%20only%20a%20small%20variation%20in%20thrust%20based%20on%20velocity%2C%20so%20matching%20the%20assumption%20that%0A%20%20%20%20thrust%20for%20a%20jet%20engine%20is%20essentialy%20constant%20with%20velocity.%0A%0A%20%20%20%20%60%60%60xml%0A%20%20%20%20%20%20%3Cfunction%20name%3D%22MilThrust%22%3E%0A%20%20%20%20%20%20%20%3Ctable%3E%0A%20%20%20%20%20%20%20%20%3CindependentVar%20lookup%3D%22row%22%3Evelocities%2Fmach%3C%2FindependentVar%3E%0A%20%20%20%20%20%20%20%20%3CindependentVar%20lookup%3D%22column%22%3Eatmosphere%2Fdensity-altitude%3C%2FindependentVar%3E%0A%20%20%20%20%20%20%20%20%3CtableData%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20-10000%20%20%20%20%20%20%200%20%20%2010000%20%20%2020000%20%20%2030000%20%20%2040000%20%20%2050000%20%20%2060000%0A%20%20%20%20%20%20%20%20%200.0%20%20%201.2600%20%201.0000%20%200.7400%20%200.5340%20%200.3720%20%200.2410%20%200.1490%20%200.0%0A%20%20%20%20%20%20%20%20%200.2%20%20%201.1710%20%200.9340%20%200.6970%20%200.5060%20%200.3550%20%200.2310%20%200.1430%20%200.0%0A%20%20%20%20%20%20%20%20%200.4%20%20%201.1500%20%200.9210%20%200.6920%20%200.5060%20%200.3570%20%200.2330%20%200.1450%20%200.0%0A%20%20%20%20%20%20%20%20%200.6%20%20%201.1810%20%200.9510%20%200.7210%20%200.5320%20%200.3780%20%200.2480%20%200.1540%20%200.0%0A%20%20%20%20%20%20%20%20%200.8%20%20%201.2580%20%201.0200%20%200.7820%20%200.5820%20%200.4170%20%200.2750%20%200.1700%20%200.0%0A%20%20%20%20%20%20%20%20%201.0%20%20%201.3690%20%201.1200%20%200.8710%20%200.6510%20%200.4750%20%200.3150%20%200.1950%20%200.0%0A%20%20%20%20%20%20%20%20%201.2%20%20%200.0000%20%200.0000%20%200.0000%20%200.0000%20%200.0000%20%200.0000%20%200.0000%20%200.0%0A%20%20%20%20%20%20%20%20%3C%2FtableData%3E%0A%20%20%20%20%20%20%20%3C%2Ftable%3E%0A%20%20%20%20%20%20%3C%2Ffunction%3E%0A%0A%20%20%20%20%60%60%60%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(plot_thrust_carpet)%3A%0A%20%20%20%20plot_thrust_carpet()%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%23%20Thrust%20Data%20Setup%20and%20Calculation%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20%23%20Setup%20thrust%20data%20for%20CFM56%0A%0A%20%20%20%20%23%20Create%20a%20grid%20of%20mach%20and%20alt%20values%0A%20%20%20%20mach%20%3D%20np.linspace(0%2C%201%2C%206)%0A%20%20%20%20alt%20%3D%20np.linspace(0%2C%2040000%2C%205)%0A%20%20%20%20mach%2C%20alt%20%3D%20np.meshgrid(mach%2C%20alt)%0A%0A%20%20%20%20%23%20Thrust%20values%0A%20%20%20%20thrust%20%3D%20np.zeros(mach.shape)%0A%0A%20%20%20%20static_thrust%20%3D%2040000%20%20%23%20lbf%0A%0A%20%20%20%20%23%20From%20JSBSim's%20engine%5CCFM56.xml%0A%20%20%20%20data%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%5B1.0%2C%20%20%200.934%2C%200.921%2C%200.951%2C%201.02%2C%20%201.12%5D%2C%20%20%20%23%200ft%0A%20%20%20%20%20%20%20%20%5B0.74%2C%20%200.697%2C%200.692%2C%200.721%2C%200.782%2C%200.871%5D%2C%20%20%23%2010%2C000ft%0A%20%20%20%20%20%20%20%20%5B0.534%2C%200.506%2C%200.506%2C%200.532%2C%200.582%2C%200.651%5D%2C%20%20%23%2020%2C000ft%0A%20%20%20%20%20%20%20%20%5B0.372%2C%200.355%2C%200.357%2C%200.378%2C%200.417%2C%200.475%5D%2C%20%20%23%2030%2C000ft%0A%20%20%20%20%20%20%20%20%5B0.241%2C%200.231%2C%200.233%2C%200.248%2C%200.275%2C%200.315%5D%20%20%20%23%2040%2C000ft%0A%20%20%20%20%5D%0A%0A%20%20%20%20%23%20Populate%20thrust%20mesh%0A%20%20%20%20for%20alt_index%20in%20range(len(data))%3A%0A%20%20%20%20%20%20%20%20for%20mach_index%20in%20range(len(data%5Balt_index%5D))%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20thrust%5Balt_index%2C%20mach_index%5D%20%3D%20data%5Balt_index%5D%5Bmach_index%5D%20*%20static_thrust%0A%20%20%20%20return%20alt%2C%20mach%2C%20thrust%0A%0A%0A%40app.cell%0Adef%20_(RegularGridInterpolator%2C%20np%2C%20thrust)%3A%0A%20%20%20%20%23%20Thrust%20lookup%0A%0A%20%20%20%20mach_grid%20%3D%20np.linspace(0%2C%201%2C%206)%0A%20%20%20%20alt_grid%20%3D%20np.linspace(0%2C%2040000%2C%205)%0A%0A%20%20%20%20%23%20Create%202D%20interpolator%0A%20%20%20%20thrust_interpolator%20%3D%20RegularGridInterpolator((alt_grid%2C%20mach_grid)%2C%20thrust)%0A%0A%20%20%20%20def%20max_thrust(alt%2C%20mach)%3A%0A%20%20%20%20%20%20%20%20bleed_demand%20%3D%200.04%20%23%20To%20match%20JSBSim's%20bleed%20demand%20in%20CFM56.xml%0A%20%20%20%20%20%20%20%20return%20thrust_interpolator(%5B%5Balt%2C%20mach%5D%5D)%5B0%5D%20*%20(1%20-%20bleed_demand)%0A%20%20%20%20return%20(max_thrust%2C)%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%23%23%20Climb%20Performance%20Routine%0A%0A%20%20%20%20Using%20the%20737%20JSBSim%20model%2C%20for%20a%20given%20altitude%20and%20a%20range%20of%20airspeeds%20we'll%20use%20JSBSim%20to%20trim%20the%20aircraft%0A%20%20%20%20for%20level%20flight%20at%20the%20given%20altitude.%20Then%20query%20JSBSim%20for%20the%20drag%20at%20the%20trim%20point.%20Using%20the%20Mach%0A%20%20%20%20value%20returned%20by%20JSBSim%20and%20the%20%60max_thrust(alt%2C%20mach)%60%20routine%20the%20thrust%20available%20can%20be%20calculated.%0A%0A%20%20%20%20Using%20the%20TAS%20for%20the%20trim%20point%2C%20the%20drag%20and%20thrust%20available%2C%20the%20power%20required%20and%20power%20available%20can%0A%20%20%20%20then%20be%20calculated.%0A%0A%20%20%20%20Lastly%20using%20equation%20%24(6)%24%20the%20ROC%20can%20then%20be%20calculated%3A%0A%0A%0A%20%20%20%20%24%24R%2FC%20%3D%20%5Cfrac%7BExcess%5C%20Power%7D%7BW%7D%20%20%5Ctag%7B6%7D%24%24%0A%0A%20%20%20%20%7CReturn%20Parameters%20per%20airspeed%20trim%20point%7C%0A%20%20%20%20%7C------------------------------%7C%0A%20%20%20%20%7CTAS%20(kt)%7C%0A%20%20%20%20%7CMach%7C%0A%20%20%20%20%7CCAS%20(kt)%7C%0A%20%20%20%20%7CDrag%20(lbf)%7C%0A%20%20%20%20%7CThrust%20Available%20(lbf)%7C%0A%20%20%20%20%7CPower%20Required%20(%24%5Cmathrm%20%7Bft%7D%20%5C%2C%20%5Cmathrm%20%7Blbf%7D%20%2F%20%5Cmathrm%20s%24)%7C%0A%20%20%20%20%7CPower%20Available%20(%24%5Cmathrm%20%7Bft%7D%20%5C%2C%20%5Cmathrm%20%7Blbf%7D%20%2F%20%5Cmathrm%20s%24)%7C%0A%20%20%20%20%7CROC%20(fps)%7C%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_(jsbsim%2C%20math%2C%20max_thrust%2C%20np)%3A%0A%20%20%20%20%23%20For%20a%20given%20altitude%20and%20TAS%20range%0A%20%20%20%20%23%20Return%20np%20array%20of%20tuples%20-%20(tas%2C%20mach%2C%20cas%2C%20drag%2C%20thrust_avail%2C%20power_required%2C%20power_avail%2C%20roc)%0A%0A%20%20%20%20kt2fps%20%3D%201.687664%0A%0A%20%20%20%20def%20sim_climb(minTAS%2C%20maxTAS%2C%20altitude)%3A%0A%0A%20%20%20%20%20%20%20%20AIRCRAFT_NAME%3D%22737%22%0A%20%20%20%20%20%20%20%20%23%20Path%20to%20JSBSim%20files%2C%20location%20of%20the%20folders%20%22aircraft%22%2C%20%22engines%22%20and%20%22systems%22%0A%20%20%20%20%20%20%20%20PATH_TO_JSBSIM_FILES%3D%22data%2Fjsbsim%22%0A%0A%20%20%20%20%20%20%20%20%23%20Avoid%20flooding%20the%20console%20with%20log%20messages%0A%20%20%20%20%20%20%20%20jsbsim.FGJSBBase().debug_lvl%20%3D%200%0A%0A%20%20%20%20%20%20%20%20fdm%20%3D%20jsbsim.FGFDMExec(PATH_TO_JSBSIM_FILES)%0A%0A%20%20%20%20%20%20%20%20%23%20Load%20the%20aircraft%20model%0A%20%20%20%20%20%20%20%20fdm.load_model(AIRCRAFT_NAME)%0A%0A%20%20%20%20%20%20%20%20%23%20Set%20engines%20running%0A%20%20%20%20%20%20%20%20fdm%5B'propulsion%2Fset-running'%5D%20%3D%20-1%0A%0A%20%20%20%20%20%20%20%20%23%20Set%20alpha%20range%20for%20trim%20solutions%0A%20%20%20%20%20%20%20%20fdm%5B'aero%2Falpha-max-rad'%5D%20%3D%20math.radians(12)%0A%20%20%20%20%20%20%20%20fdm%5B'aero%2Falpha-min-rad'%5D%20%3D%20math.radians(-8.0)%0A%0A%20%20%20%20%20%20%20%20%23%20Range%20of%20airspeeds%20(TAS)%0A%20%20%20%20%20%20%20%20airspeeds%20%3D%20np.linspace(minTAS%2C%20maxTAS%2C%2050)%0A%0A%20%20%20%20%20%20%20%20result%20%3D%20%5B%5D%0A%0A%20%20%20%20%20%20%20%20for%20airspeed%20in%20airspeeds%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'ic%2Fh-sl-ft'%5D%20%3D%20altitude%0A%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'ic%2Fgamma-deg'%5D%20%3D%200%20%20%20%20%20%20%20%23%20Level%20trim%0A%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'ic%2Fvt-kts'%5D%20%3D%20airspeed%20%20%20%23%20TAS%0A%20%20%20%20%20%20%20%20%20%20%20%20fdm.run_ic()%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'simulation%2Fdo_simple_trim'%5D%20%3D%201%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mach%20%3D%20fdm%5B'velocities%2Fmach'%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cas%20%3D%20fdm%5B'velocities%2Fvc-kts'%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20weight%20%3D%20fdm%5B'inertia%2Fweight-lbs'%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20drag%20%3D%20fdm%5B'forces%2Ffwx-aero-lbs'%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23drag%20%3D%202%20*%20fdm%5B'propulsion%2Fengine%5B0%5D%2Fthrust-lbs'%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20thrust_avail%20%3D%20max_thrust(altitude%2C%20mach)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20power_avail%20%3D%20thrust_avail%20*%20airspeed%20*%20kt2fps%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20power_required%20%3D%20drag%20*%20airspeed%20*%20kt2fps%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20roc%20%3D%20(power_avail%20-%20power_required)%20%2F%20weight%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20result.append((airspeed%2C%20mach%2C%20cas%2C%20drag%2C%20thrust_avail%2C%20power_required%2C%20power_avail%2C%20roc))%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20except%20jsbsim.TrimFailureError%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pass%20%20%23%20Ignore%20trim%20failures%20%20%20%20%20%20%20%20%0A%0A%20%20%20%20%20%20%20%20return%20np.array(result)%0A%20%20%20%20return%20kt2fps%2C%20sim_climb%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20sim_climb)%3A%0A%20%20%20%20%23%20Calculate%20climb%20performance%20data%20using%20JSBSim%20for%20various%20altitudes.%0A%20%20%20%20%23%20JSBSim%20used%20to%20trim%20for%20level%20flight%20for%20thrust%20required%20and%20power%20required.%0A%0A%20%20%20%20%23%20Supress%20stdout%20messages%20about%20expected%20trim%20failures%0A%20%20%20%20with%20mo.redirect_stdout()%3A%0A%0A%20%20%20%20%20%20%20%20minTAS%20%3D%20150%0A%20%20%20%20%20%20%20%20maxTAS%20%3D%20550%0A%0A%20%20%20%20%20%20%20%20sim_results%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%3A%20sim_climb(minTAS%2C%20maxTAS%2C%20150)%2C%20%20%23%20150ft%20out%20of%20ground%20effect%0A%20%20%20%20%20%20%20%20%20%20%20%2010000%20%3A%20sim_climb(minTAS%2C%20maxTAS%2C%2010000)%2C%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%2020000%20%3A%20sim_climb(minTAS%2C%20maxTAS%2C%2020000)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%2030000%20%3A%20sim_climb(minTAS%2C%20maxTAS%2C%2030000)%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20return%20maxTAS%2C%20minTAS%2C%20sim_results%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%23%23%20Thrust%20Available%20vs%20Thrust%20Required%20Results%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(plot_thrust_difference)%3A%0A%20%20%20%20plot_thrust_difference()%0A%20%20%20%20return%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%23%23%20Power%20Available%20vs%20Power%20Required%20Results%0A%0A%20%20%20%20Unlike%20in%20the%20example%20power%20graph%20from%20the%20theory%20section%20these%20don't%20have%20the%20%24P_R%24%20and%20%24P_A%24%20curves%20intersecting%0A%20%20%20%20on%20the%20low%20speed%20side.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(plot_power_difference)%3A%0A%20%20%20%20plot_power_difference()%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**Question%3A**%20Should%20JSBSim's%20trim%20routines%20be%20able%20to%20generate%20more%20level%20trim%20solutions%20on%20the%20low%20speed%20portions%20of%20the%20envelope%20in%20order%20for%20%24P_R%24%20and%20%24P_A%24%20to%20intersect%3F%20Looks%20like%20on%20the%20low%20speed%20end%20the%20trim%20routine%20is%20running%20into%20a%20limit%20with%20the%20maximum%20AoA%20available%20at%20%24C_%7BL_%7Bmax%7D%7D%24.%20A%20flaps%20down%20configuration%20would%20probably%20result%20in%20an%20intersection.%22%22%22)%0A%20%20%20%20return%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%20rf%22%22%22%0A%20%20%20%20%23%23%23%20ROC%20Results%0A%0A%20%20%20%20Rate%20of%20climb%20for%204%20different%20altitudes%20with%20the%20airspeed%20(TAS)%20for%20maximum%20ROC%20displayed%20as%20a%20dashed%20line.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(plot_roc)%3A%0A%20%20%20%20plot_roc()%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%22ROC%20for%20different%20altitudes%20displayed%20on%20a%20combined%20graph.%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(plot_roc_combined)%3A%0A%20%20%20%20plot_roc_combined()%0A%20%20%20%20return%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%23%23%20Hodograph%20Results%0A%0A%20%20%20%20In%20the%20**ROC%20Results**%20section%20above%20the%20plot%20of%20ROC%20is%20against%20%24V_%5Cinfty%24%2C%20whereas%20for%20a%20Hodograph%20it%20is%20ROC%20(%24V_V%24)%0A%20%20%20%20against%20%24V_H%24.%0A%0A%20%20%20%20**Question%3A**%20Hmm%2C%20given%20the%20need%20for%20the%20x%20and%20y%20axes%20to%20have%20the%20same%20scale%20in%20order%20for%20the%20vector%20lengths%20to%20work%20and%20angles%2C%0A%20%20%20%20these%20Hodographs%20are%20not%20as%20easy%20to%20read%20compared%20to%20the%20example%20in%20the%20theory%20section.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(plot_hodograph)%3A%0A%20%20%20%20plot_hodograph()%0A%20%20%20%20return%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%20rf%22%22%22%0A%20%20%20%20%23%23%23%20Trimmed%20for%20Maximum%20ROC%0A%0A%20%20%20%20Previously%20I'd%20used%20JSBSim%20in%20order%20to%20generate%20a%20%5BTrim%20Envelope%5D(https%3A%2F%2Fseanmcleod70.github.io%2FFlightDynamicsCalcs%2FTrimEnvelope.html)%20for%20the%20737%20model%20at%2015%2C000ft.%0A%0A%20%20%20%20%7Bmo.image('public%2FClimbPerformance%2FTrimEnvelope.svg'%2C%20caption%3D'Figure%2011')%7D%0A%0A%20%20%20%20It%20used%20a%20brute%20force%20approach%20of%20trying%20to%20calculate%20a%20trim%20solution%20at%20each%20airspeed%20across%20a%20range%20of%20%0A%20%20%20%20flight%20path%20angles%20%24%5Cgamma%24%20from%20%2B10%20to%20-10%20degrees.%20The%20graphs%20included%20information%20on%20the%20required%20amount%0A%20%20%20%20of%20thrust%20as%20well%20as%20the%20AoA%20for%20the%20trim%20point.%0A%0A%20%20%20%20The%20maximum%20ROC%20for%20each%20airspeed%20can%20be%20calculated%20from%20these%20graphs%20by%20converting%20the%20airspeed%20into%20TAS%20from%20IAS%0A%20%20%20%20and%20then%20using%3A%0A%0A%20%20%20%20%24ROC%20%3D%20V_%7B%7BTAS%7D%7D%20%5Csin%20%5Cgamma%24%0A%0A%20%20%20%20So%20for%20comparison%20to%20the%20graphs%20generated%20above%20showing%20ROC%20versus%20TAS%20using%20excess%20power%20and%20weight%20to%20calculate%20the%0A%20%20%20%20ROC%20we'll%20now%20use%20JSBSim's%20trim%20routine%20to%20work%20out%20a%20maximum%20ROC%20for%20each%20airspeed.%20Doing%20so%20by%20determining%20the%20maximum%0A%20%20%20%20flight%20path%20angle%20%24%5Cgamma%24%20with%20a%20feasible%20trim%20solution%2C%20for%20each%20given%20airspeed.%20Making%20use%20of%20a%20bisection%20style%0A%20%20%20%20loop.%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_(maxTAS%2C%20minTAS%2C%20mo%2C%20trim_max_gamma_range)%3A%0A%20%20%20%20%23%20Calculate%20climb%20performance%20data%20using%20JSBSim%20to%20find%20maximum%20gamma%20for%20feasible%20trim%0A%20%20%20%20%23%20for%20each%20airspeed%20at%20specified%20altitude.%0A%0A%20%20%20%20%23%20Supress%20stdout%20messages%20about%20expected%20trim%20failures%0A%20%20%20%20with%20mo.redirect_stdout()%3A%0A%0A%20%20%20%20%20%20%20%20sim_climb_results%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%3A%20trim_max_gamma_range(minTAS%2C%20maxTAS%2C%20150)%20%20%23%20150ft%20out%20of%20ground%20effect%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20return%20(sim_climb_results%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(plot_jsbsim_climb_trim_roc)%3A%0A%20%20%20%20plot_jsbsim_climb_trim_roc(0)%0A%20%20%20%20return%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%20There%20is%20a%20fairly%20close%20match%20between%20the%20graphs%20showing%20ROC%20vs%20TAS%20at%20sea%20level%20between%20the%20approach%20using%0A%20%20%20%20excess%20power%20and%20the%20approach%20using%20JSBSim%20to%20calculate%20a%20trim%20climb%20solution%20for%20a%20maximum%20%24%5Cgamma%24.%20With%20a%20%0A%20%20%20%20peak%20ROC%20from%20the%20JSBSim%20trimb%20climb%20solution%20of%2097fps%20versus%2096fps%20for%20the%20excess%20power%20calculation.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(plot_roc_excess_power_climb_trim_comparison)%3A%0A%20%20%20%20plot_roc_excess_power_climb_trim_comparison(0)%20%20%23%20Sea%20level%0A%20%20%20%20return%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%20What%20is%20interesting%20is%20that%20from%20about%20150KTAS%20to%20360KTAS%20the%20climb%20trim%20solution%20is%20producing%20a%20ROC%20that%20is%20slightly%0A%20%20%20%20greater%20than%20the%20ROC%20calculated%20via%20the%20theoritical%20excess%20power%20formula.%20Looking%20at%20figure%201%20above%2C%20equation%20(2)%20above%0A%20%20%20%20%24L%20%3D%20W%20%5Ccos%20%5Ctheta%24%20and%20equation%20(4)%20for%20calculating%20ROC%20based%20on%20specific%20excess%20power%20there%20is%20an%20assumption%20that%20%0A%20%20%20%20the%20drag%20for%20level%20trim%20and%20climb%20trim%20is%20identical.%0A%0A%20%20%20%20However%20as%20per%20equation%20(2)%20as%20the%20flight%20path%20angle%20increases%20(%24%5Ctheta%24%20in%20equation%20(2))%20the%20required%20amount%20of%20lift%20%0A%20%20%20%20reduces%20compared%20to%20the%20amount%20of%20lift%20required%20for%20level%20trim.%20Which%20means%20that%20the%20JSBSim%20trim%20routine%20trims%20the%0A%20%20%20%20aircraft%20in%20the%20climb%20at%20a%20smaller%20angle%20of%20attack%2C%20given%20that%20%24V%24%20is%20constant%20between%20level%20trim%20and%20climb%20trim.%0A%0A%20%20%20%20Given%20the%20smaller%20angle%20of%20attack%20required%20for%20climb%20trim%20that%20means%20the%20drag%20is%20reduced%20compared%20to%20level%20trim.%20However%0A%20%20%20%20equation%20(4)%20in%20calculating%20the%20excess%20power%20doesn't%20take%20this%20reduction%20in%20drag%20into%20account%2C%20therefore%20slightly%0A%20%20%20%20underestimating%20the%20ROC%20that%20can%20be%20achieved.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%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%20rf%22%22%22%0A%20%20%20%20%23%23%20TECS%0A%0A%20%20%20%20Summary%20of%20TECS%20from%20Agostino's%20slide%20presentation%20at%20NODYCON%202025.%0A%0A%20%20%20%20%7Bmo.image('public%2FClimbPerformance%2FTECSSummary.png'%2C%20caption%3D'Figure%2014')%7D%0A%0A%20%20%20%20So%20the%20throttle%20controls%20the%20total%20energy%20available%20and%20the%20elevator%20controls%20how%20the%20energy%20available%20is%20split%0A%20%20%20%20between%20an%20increase%20in%20kinetic%20energy%20and%20an%20increase%20in%20potential%20energy.%0A%0A%20%20%20%20So%20it%20seems%20counterintuitive%20that%20you%20could%20climb%20at%20max%20ROC%20with%20the%20throttle%20at%20less%20than%20100%25.%20Since%20if%20the%20aircraft%0A%20%20%20%20was%20at%20the%20optimal%20climb%20speed%2C%20i.e.%20no%20need%20for%20an%20increase%20in%20kinetic%20energy%20surely%20any%20excess%20energy%20over%20and%20above%0A%20%20%20%20what%20the%20throttle%20was%20supplying%20at%20less%20than%20100%25%20could%20be%20turned%20into%20an%20increase%20in%20potential%20energy%2C%20i.e.%20to%20increase%0A%20%20%20%20the%20ROC%3F%0A%0A%20%20%20%20Also%20in%20terms%20of%20the%20climb%20theory%20above%2C%20less%20than%20100%25%20thrust%20will%20result%20in%20lower%20excess%20power%20and%20therefore%20a%20lower%0A%20%20%20%20ROC.%0A%0A%20%20%20%20I've%20digitized%20the%20following%20plots%20to%20compare%20the%20ROC%20from%20the%20TECS%20based%20autopilot%20with%20the%20ROC%20values%20calculated%20for%0A%20%20%20%20the%20contour%20plot%20of%20ROC%20versus%20airspeed%20and%20altitude%2C%20which%20is%20based%20on%20excess%20power%20divided%20by%20weight.%0A%0A%20%20%20%20%7Bmo.image('public%2FClimbPerformance%2FTECSROCDigitized.png'%2C%20caption%3D'Figure%2015')%7D%0A%0A%20%20%20%20%7CAltitude%7CThrottle%7CROC%20%20%20%20%20%20%7CContour%20Plot%20ROC%7CROC%20Factor%7C%0A%20%20%20%20%7C--------%7C--------%7C---------%7C----------------%7C----------%7C%0A%20%20%20%20%7C0%20ish%20%20%20%7C%2078%25%20%20%20%20%7C%2018.9m%2Fs%20%7C%20%3E%2022m%2Fs%20%7C%20%3C%2086%25%20%7C%0A%20%20%20%20%7C2000m%20%20%20%7C%2078%25%20%20%20%20%7C%2017.5m%2Fs%20%7C%2020m%2Fs%20%20%20%7C%2086%25%20%7C%0A%20%20%20%20%7C4000m%20%20%20%7C%2075%25%20%20%20%20%7C%2014.0m%2Fs%20%7C%2016m%2Fs%20%20%20%7C%2088%25%20%7C%0A%20%20%20%20%7C6000m%20%20%20%7C%2078%25%20%20%20%20%7C%2010.8m%2Fs%20%7C%2012.5m%2Fs%20%7C%2086%25%20%7C%0A%20%20%20%20%7C8000m%20%20%20%7C%2060%25%20%20%20%20%7C%208.0m%2Fs%20%20%7C%209.5m%2Fs%20%20%7C%2084%25%20%7C%0A%20%20%20%20%7C10%2C000m%20%7C%2064%25%20%20%20%20%7C%205.5m%2Fs%20%20%7C%206.5m%2Fs%20%20%7C%2085%25%20%7C%0A%0A%20%20%20%20So%20for%20each%20of%20the%20data%20points%20the%20ROC%20achieved%20by%20the%20TECS%20based%20autopilot%20is%20~15%25%20less%20than%20the%20ROC%0A%20%20%20%20indicated%20on%20the%20contour%20plot.%0A%0A%20%20%20%20The%20TECS%20based%20autopilot%20followed%20the%20velocity%20setpoint%20fairly%20accurately%20to%20climb%20at%20the%20optimal%20airspeed%0A%20%20%20%20to%20maximize%20the%20ROC%20as%20defined%20by%20the%20contour%20plots%20for%20the%20specific%20altitude.%0A%0A%20%20%20%20%7Bmo.image('public%2FClimbPerformance%2FTECSVelocityTracking.png'%2C%20caption%3D'Figure%2016')%7D%0A%0A%20%20%20%20However%2C%20even%20though%20the%20aircraft%20was%20flying%20at%20the%20optimal%20speed%20given%20the%20reduced%20thrust%20below%20100%25%20of%20the%0A%20%20%20%20available%20thrust%20it%20would%20appear%20that%20the%20aircraft%20didn't%20attain%20the%20maximum%20ROC%20at%20each%20point%20along%20it's%20climb%2C%20%0A%20%20%20%20as%20defined%20by%20the%20contour%20plots.%20Presumumably%20climbing%20at%20a%20shallower%20flight%20path%20angle%20than%20the%20flight%20path%20angle%20required%20to%20achieve%20the%20maximum%20ROC.%0A%0A%20%20%20%20So%20was%20this%20climb%20by%20the%20TECS%20based%20autopilot%20really%20achieving%20an%20optimal%20climb%2C%20in%20terms%20of%20minimum%20time%20to%20the%0A%20%20%20%20set-point%20altitude%3F%20If%20the%20throttle%20had%20been%20fixed%20at%20100%25%20during%20the%20climb%20wouldn't%20it%20have%20achieved%20a%20quicker%20time%0A%20%20%20%20to%20altitude%3F%0A%0A%20%20%20%20In%20terms%20of%20an%20optimal%20climb%20to%20altitude%20how%20achievable%20is%20it%20to%20exactly%20match%20the%20optimal%20climb%20profile%20based%20on%20%0A%20%20%20%20the%20contour%20plot%20generated%20using%20the%20excess%20power%20calculation%3F%0A%0A%20%20%20%20Even%20if%20the%20aircraft%20could%20be%20trimmed%20at%20each%20altitude%20at%20the%20airspeed%20for%20maximum%20ROC%20with%20100%25%20throttle%0A%20%20%20%20there%20is%20often%20a%20need%20for%20the%20aircraft%20to%20increase%20it's%20kinetic%20energy%20in%20order%20to%20achieve%20the%20airspeed%20required%20for%0A%20%20%20%20maximum%20ROC%20at%20a%20higher%20altitude.%20So%20based%20on%20the%20TECS%20reservoir%20analogy%20in%20order%20to%20increase%20the%20kinetic%20energy%0A%20%20%20%20that%20means%20some%20of%20the%20total%20energy%20available%20will%20then%20be%20diverted%20from%20achieving%20the%20maximum%20ROC%20during%20this%20transition.%0A%0A%20%20%20%20For%20example%20these%20were%20the%20required%20TAS%20at%20increasing%20altitude%20in%20order%20to%20achieve%20the%20maximum%20ROC%20possible%20at%0A%20%20%20%20each%20altitude%20based%20on%20the%20excess%20power%20calculation.%0A%0A%20%20%20%20%7CAltitude%7CTAS%7C%0A%20%20%20%20%7C--------%7C---%7C%0A%20%20%20%20%7C0ft%20%20%20%20%20%7C321kt%7C%0A%20%20%20%20%7C10%2C000ft%7C330kt%7C%0A%20%20%20%20%7C20%2C000ft%7C338kt%7C%0A%20%20%20%20%7C30%2C000ft%7C370kt%7C%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%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%20Plotting%20Functions%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20mach%2C%20np%2C%20plt%2C%20thrust)%3A%0A%20%20%20%20def%20plot_thrust_carpet()%3A%0A%20%20%20%20%20%20%20%20%23%20Create%20a%203D%20plot%0A%20%20%20%20%20%20%20%20fig%20%3D%20plt.figure(figsize%3D(8%2C8)%2C%20layout%3D'constrained')%0A%20%20%20%20%20%20%20%20ax%20%3D%20fig.add_subplot(111%2C%20projection%3D'3d')%0A%0A%20%20%20%20%20%20%20%20%23%20Plot%20the%20surface%0A%20%20%20%20%20%20%20%20surface%20%3D%20ax.plot_surface(mach%2C%20alt%2C%20thrust%2F1000%2C%20cmap%3D'viridis'%2C%20edgecolor%3D'red')%0A%0A%20%20%20%20%20%20%20%20%23%20Flip%20axes%0A%20%20%20%20%20%20%20%20ax.set_ylim(%5B45000%2C%200%5D)%0A%20%20%20%20%20%20%20%20ax.set_xlim(%5B1.05%2C%20-0.05%5D)%0A%0A%20%20%20%20%20%20%20%20ax.yaxis.set_ticks(np.arange(0%2C%2040001%2C%2010000))%0A%0A%20%20%20%20%20%20%20%20%23%20Set%20labels%0A%20%20%20%20%20%20%20%20ax.set_xlabel('Mach')%0A%20%20%20%20%20%20%20%20ax.set_ylabel('Altitude%20(ft)')%0A%20%20%20%20%20%20%20%20ax.set_zlabel('Thrust%20(k%20lbf)')%0A%0A%20%20%20%20%20%20%20%20fig.suptitle('Thrust%20vs%20Density%20Altitude%20and%20Mach')%0A%20%20%20%20%20%20%20%20fig.supxlabel('Figure%205')%0A%0A%20%20%20%20%20%20%20%20%23%20Show%20the%20plot%0A%20%20%20%20%20%20%20%20%23mo.mpl.interactive(plt.gca())%0A%20%20%20%20%20%20%20%20return%20plt.gca()%0A%20%20%20%20return%20(plot_thrust_carpet%2C)%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plt%2C%20sim_results)%3A%0A%20%20%20%20def%20plot_roc()%3A%0A%20%20%20%20%20%20%20%20fig%20%3D%20plt.figure(figsize%3D(16%2C4)%2C%20layout%3D'constrained')%0A%20%20%20%20%20%20%20%20axes%20%3D%20fig.subplots(1%2C%204)%0A%0A%20%20%20%20%20%20%20%20for%20i%20in%20range(4)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20altitude%20%3D%20i*10000%0A%20%20%20%20%20%20%20%20%20%20%20%20sim_data%20%3D%20sim_results%5Baltitude%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.plot(sim_data%5B%3A%2C0%5D%2C%20sim_data%5B%3A%2C7%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20roc_max_index%20%3D%20np.argmax(sim_data%5B%3A%2C7%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20v_roc_max%20%3D%20sim_data%5B%3A%2C0%5D%5Broc_max_index%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20max_roc%20%3D%20sim_data%5B%3A%2C7%5D%5Broc_max_index%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.axvline(x%3Dv_roc_max%2C%20color%3D'red'%2C%20linestyle%3D'--'%2C%20linewidth%3D2)%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_xlabel('TAS%20(kt)')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_ylabel('ROC%20(fps)')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_title(f'ROC%20-%20%7Baltitude%7Dft')%0A%0A%20%20%20%20%20%20%20%20fig.supxlabel('Figure%208')%0A%0A%20%20%20%20%20%20%20%20return%20plt.gca()%0A%20%20%20%20return%20(plot_roc%2C)%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plt%2C%20sim_results)%3A%0A%20%20%20%20def%20plot_roc_combined()%3A%0A%20%20%20%20%20%20%20%20fig%20%3D%20plt.figure(figsize%3D(12%2C%208))%0A%0A%20%20%20%20%20%20%20%20for%20i%20in%20range(4)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20altitude%20%3D%20i*10000%0A%20%20%20%20%20%20%20%20%20%20%20%20sim_data%20%3D%20sim_results%5Baltitude%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20plt.plot(sim_data%5B%3A%2C0%5D%2C%20sim_data%5B%3A%2C7%5D%2C%20label%3Df'%7Baltitude%7Dft')%0A%20%20%20%20%20%20%20%20%20%20%20%20roc_max_index%20%3D%20np.argmax(sim_data%5B%3A%2C7%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20v_roc_max%20%3D%20sim_data%5B%3A%2C0%5D%5Broc_max_index%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20max_roc%20%3D%20sim_data%5B%3A%2C7%5D%5Broc_max_index%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20plt.vlines(v_roc_max%2C%200%2C%20max_roc%2C%20color%3D'red'%2C%20linestyle%3D'--'%2C%20linewidth%3D2)%0A%20%20%20%20%20%20%20%20%20%20%20%20plt.scatter(v_roc_max%2C%20max_roc%2C%20label%3Df'%7Bmax_roc%3A.0f%7Dfps%20-%20%7Bv_roc_max%3A.0f%7Dkt')%0A%0A%20%20%20%20%20%20%20%20plt.title('ROC')%0A%20%20%20%20%20%20%20%20plt.xlabel('TAS%20(kt)')%0A%20%20%20%20%20%20%20%20plt.ylabel('ROC%20(fps)')%0A%20%20%20%20%20%20%20%20plt.legend()%0A%0A%20%20%20%20%20%20%20%20fig.supxlabel('Figure%209')%0A%0A%20%20%20%20%20%20%20%20return%20plt.gca()%0A%20%20%20%20return%20(plot_roc_combined%2C)%0A%0A%0A%40app.cell%0Adef%20_(kt2fps%2C%20math%2C%20np%2C%20plt%2C%20sim_results)%3A%0A%20%20%20%20def%20plot_hodograph()%3A%0A%20%20%20%20%20%20%20%20figure%2C%20axes%20%3D%20plt.subplots(1%2C%204%2C%20figsize%3D(16%2C%204)%2C%20layout%3D'constrained')%0A%0A%20%20%20%20%20%20%20%20for%20i%20in%20range(4)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20altitude%20%3D%20i*10000%0A%20%20%20%20%20%20%20%20%20%20%20%20sim_data%20%3D%20sim_results%5Baltitude%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20v_h%20%3D%20np.sqrt(sim_data%5B%3A%2C0%5D**2%20-%20sim_data%5B%3A%2C7%5D**2)%20*%20kt2fps%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.plot(v_h%2C%20sim_data%5B%3A%2C7%5D)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20roc_max_index%20%3D%20np.argmax(sim_data%5B%3A%2C7%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20v_roc_max%20%3D%20sim_data%5B%3A%2C0%5D%5Broc_max_index%5D%20*%20kt2fps%0A%20%20%20%20%20%20%20%20%20%20%20%20max_roc%20%3D%20sim_data%5B%3A%2C7%5D%5Broc_max_index%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20v_h_roc_max%20%3D%20np.sqrt(v_roc_max**2%20-%20max_roc**2)%0A%20%20%20%20%20%20%20%20%20%20%20%20gamma%20%3D%20math.degrees(math.atan2(max_roc%2C%20v_h_roc_max))%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.scatter(v_h_roc_max%2C%20max_roc%2C%20label%3Df'R%2FC%20%3D%20%7Bmax_roc%3A.0f%7D%20%24%5Cgamma%24%20%3D%20%7Bgamma%3A.1f%7D%24%5E%7B%7B%5Ccirc%7D%7D%24')%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.plot(%5B0%2C%20v_h_roc_max%5D%2C%20%5B0%2C%20max_roc%5D)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_xlim(%5B0%2C%20550*kt2fps%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_ylim(%5B0%2C%20550*kt2fps%5D)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_xlabel('%24V_H%24%20(fps)')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_ylabel('ROC%20%24V_V%24%20(fps)')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_title(f'Hodograph%20-%20%7Baltitude%7Dft')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.legend()%0A%0A%20%20%20%20%20%20%20%20figure.supxlabel('Figure%2010')%0A%0A%20%20%20%20%20%20%20%20return%20plt.gca()%0A%20%20%20%20return%20(plot_hodograph%2C)%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plt%2C%20sim_results)%3A%0A%20%20%20%20def%20plot_power_difference()%3A%0A%20%20%20%20%20%20%20%20figure%2C%20axes%20%3D%20plt.subplots(1%2C%204%2C%20figsize%3D(16%2C%204)%2C%20layout%3D'constrained')%0A%0A%20%20%20%20%20%20%20%20for%20i%20in%20range(4)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20altitude%20%3D%20i*10000%0A%20%20%20%20%20%20%20%20%20%20%20%20sim_data%20%3D%20sim_results%5Baltitude%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.plot(sim_data%5B%3A%2C0%5D%2C%20sim_data%5B%3A%2C5%5D%2C%20label%3D'%24P_R%24')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.plot(sim_data%5B%3A%2C0%5D%2C%20sim_data%5B%3A%2C6%5D%2C%20label%3D'%24P_A%24')%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Calculate%20max%20excess%0A%20%20%20%20%20%20%20%20%20%20%20%20max_excess_index%20%3D%20np.argmax(sim_data%5B%3A%2C6%5D%20-%20sim_data%5B%3A%2C5%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20max_excess_v%20%20%3D%20sim_data%5B%3A%2C0%5D%5Bmax_excess_index%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20max_excess_pr%20%3D%20sim_data%5B%3A%2C5%5D%5Bmax_excess_index%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20max_excess_pa%20%3D%20sim_data%5B%3A%2C6%5D%5Bmax_excess_index%5D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.vlines(max_excess_v%2C%20max_excess_pr%2C%20max_excess_pa%2C%20color%3D'red'%2C%20linestyle%3D'--'%2C%20linewidth%3D2)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_xlabel('TAS%20(kt)')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_ylabel('Power')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_title(f'Power%20-%20%7Baltitude%7Dft')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.legend()%0A%0A%20%20%20%20%20%20%20%20figure.supxlabel('Figure%207')%0A%0A%20%20%20%20%20%20%20%20return%20plt.gca()%0A%20%20%20%20return%20(plot_power_difference%2C)%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plt%2C%20sim_results)%3A%0A%20%20%20%20def%20plot_thrust_difference()%3A%0A%20%20%20%20%20%20%20%20figure%2C%20axes%20%3D%20plt.subplots(1%2C%204%2C%20figsize%3D(16%2C%204)%2C%20layout%3D'constrained')%0A%0A%20%20%20%20%20%20%20%20for%20i%20in%20range(4)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20altitude%20%3D%20i*10000%0A%20%20%20%20%20%20%20%20%20%20%20%20sim_data%20%3D%20sim_results%5Baltitude%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.plot(sim_data%5B%3A%2C0%5D%2C%20sim_data%5B%3A%2C3%5D%2F1000%2C%20label%3D'%24T_R%24')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.plot(sim_data%5B%3A%2C0%5D%2C%20sim_data%5B%3A%2C4%5D%2F1000%2C%20label%3D'%24T_A%24')%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Calculate%20max%20excess%0A%20%20%20%20%20%20%20%20%20%20%20%20max_excess_index%20%3D%20np.argmax(sim_data%5B%3A%2C4%5D%20-%20sim_data%5B%3A%2C3%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20max_excess_v%20%20%3D%20sim_data%5B%3A%2C0%5D%5Bmax_excess_index%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20max_excess_tr%20%3D%20sim_data%5B%3A%2C3%5D%5Bmax_excess_index%5D%2F1000%0A%20%20%20%20%20%20%20%20%20%20%20%20max_excess_ta%20%3D%20sim_data%5B%3A%2C4%5D%5Bmax_excess_index%5D%2F1000%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.vlines(max_excess_v%2C%20max_excess_tr%2C%20max_excess_ta%2C%20color%3D'red'%2C%20linestyle%3D'--'%2C%20linewidth%3D2)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_xlabel('TAS%20(kt)')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_ylabel('Thrust%20(k%20lbf)')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_title(f'Thrust%20-%20%7Baltitude%7Dft')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.legend()%0A%0A%20%20%20%20%20%20%20%20figure.supxlabel('Figure%206')%0A%0A%20%20%20%20%20%20%20%20return%20plt.gca()%0A%20%20%20%20return%20(plot_thrust_difference%2C)%0A%0A%0A%40app.cell%0Adef%20_(jsbsim%2C%20kt2fps%2C%20math%2C%20np)%3A%0A%20%20%20%20%23%20Use%20JSBSim%20trim%20routine%20using%20a%20bisection%20style%20loop%20to%20determine%20the%20maximum%20flight%20path%0A%20%20%20%20%23%20angle%20for%20a%20valid%20trim%20solution%0A%0A%20%20%20%20def%20trim(fdm%2C%20alt%2C%20TAS%2C%20gamma)%3A%0A%20%20%20%20%20%20%20%20fdm%5B'ic%2Fh-sl-ft'%5D%20%3D%20alt%0A%20%20%20%20%20%20%20%20fdm%5B'ic%2Fvt-kts'%5D%20%3D%20TAS%0A%20%20%20%20%20%20%20%20fdm%5B'ic%2Fgamma-deg'%5D%20%3D%20gamma%0A%0A%20%20%20%20%20%20%20%20%23%20Initialize%20the%20aircraft%20with%20initial%20conditions%0A%20%20%20%20%20%20%20%20fdm.run_ic()%0A%0A%20%20%20%20%20%20%20%20%23%20Trim%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'simulation%2Fdo_simple_trim'%5D%20%3D%201%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20(gamma%2C%20fdm%5B'fcs%2Fthrottle-cmd-norm%5B0%5D'%5D%2C%20fdm%5B'aero%2Falpha-deg'%5D)%0A%20%20%20%20%20%20%20%20except%20jsbsim.TrimFailureError%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20None%0A%0A%20%20%20%20def%20trim_max_gamma(fdm%2C%20alt%2C%20TAS)%3A%0A%20%20%20%20%20%20%20%20%23%20Assume%20absolute%20max%20gamma%20is%2020%0A%20%20%20%20%20%20%20%20max_gamma%20%3D%2020%0A%20%20%20%20%20%20%20%20min_gamma%20%3D%200%0A%20%20%20%20%20%20%20%20last_trim%20%3D%20trim(fdm%2C%20alt%2C%20TAS%2C%20min_gamma)%0A%20%20%20%20%20%20%20%20if%20last_trim%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20None%0A%0A%20%20%20%20%20%20%20%20level_alpha%20%3D%20last_trim%5B2%5D%0A%20%20%20%20%20%20%20%20level_throttle%20%3D%20last_trim%5B1%5D%0A%20%20%20%20%20%20%20%20last_gamma%20%3D%20min_gamma%0A%20%20%20%20%20%20%20%20next_gamma%20%3D%2020%0A%0A%20%20%20%20%20%20%20%20%23%20Bisection%20loop%0A%20%20%20%20%20%20%20%20for%20i%20in%20range(15)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20current_trim%20%3D%20trim(fdm%2C%20alt%2C%20TAS%2C%20next_gamma)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20current_trim%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20next_gamma%20%3D%20(next_gamma%20%2B%20last_gamma)%2F2%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20last_trim%20%3D%20current_trim%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20last_gamma%20%3D%20next_gamma%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20next_gamma%20%3D%20(next_gamma%20%2B%20max_gamma)%2F2%0A%0A%20%20%20%20%20%20%20%20return%20last_trim%20%2B%20(level_alpha%2C%20level_throttle%2C)%0A%0A%20%20%20%20def%20trim_max_gamma_range(min_TAS%2C%20max_TAS%2C%20alt)%3A%0A%20%20%20%20%20%20%20%20AIRCRAFT_NAME%3D%22737%22%0A%20%20%20%20%20%20%20%20%23%20Path%20to%20JSBSim%20files%2C%20location%20of%20the%20folders%20%22aircraft%22%2C%20%22engines%22%20and%20%22systems%22%0A%20%20%20%20%20%20%20%20PATH_TO_JSBSIM_FILES%3D%22data%2Fjsbsim%22%0A%0A%20%20%20%20%20%20%20%20%23%20Avoid%20flooding%20the%20console%20with%20log%20messages%0A%20%20%20%20%20%20%20%20jsbsim.FGJSBBase().debug_lvl%20%3D%200%0A%0A%20%20%20%20%20%20%20%20fdm%20%3D%20jsbsim.FGFDMExec(PATH_TO_JSBSIM_FILES)%0A%0A%20%20%20%20%20%20%20%20%23%20Load%20the%20aircraft%20model%0A%20%20%20%20%20%20%20%20fdm.load_model(AIRCRAFT_NAME)%0A%0A%20%20%20%20%20%20%20%20%23%20Set%20engines%20running%0A%20%20%20%20%20%20%20%20fdm%5B'propulsion%2Fset-running'%5D%20%3D%20-1%0A%0A%20%20%20%20%20%20%20%20%23%20Set%20alpha%20range%20for%20trim%20solutions%0A%20%20%20%20%20%20%20%20fdm%5B'aero%2Falpha-max-rad'%5D%20%3D%20math.radians(12)%0A%20%20%20%20%20%20%20%20fdm%5B'aero%2Falpha-min-rad'%5D%20%3D%20math.radians(-4.0)%0A%0A%20%20%20%20%20%20%20%20results%20%3D%20%5B%5D%0A%0A%20%20%20%20%20%20%20%20for%20tas%20in%20np.linspace(min_TAS%2C%20max_TAS%2C%2050)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20trim_data%20%3D%20trim_max_gamma(fdm%2C%20alt%2C%20tas)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20trim_data%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gamma%2C%20throttle%2C%20alpha%2C%20level_alpha%2C%20level_throttle%20%3D%20trim_data%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20roc%20%3D%20(tas*kt2fps)*math.sin(math.radians(gamma))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20results.append((tas%2C%20gamma%2C%20roc%2C%20throttle%2C%20level_throttle%2C%20alpha%2C%20level_alpha))%0A%0A%20%20%20%20%20%20%20%20return%20np.array(results)%0A%0A%20%20%20%20return%20(trim_max_gamma_range%2C)%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plt%2C%20sim_climb_results)%3A%0A%20%20%20%20def%20plot_jsbsim_climb_trim_roc(alt)%3A%0A%20%20%20%20%20%20%20%20figure%2C%20axes%20%3D%20plt.subplots(1%2C%204%2C%20figsize%3D(16%2C%204)%2C%20layout%3D'constrained')%0A%0A%20%20%20%20%20%20%20%20results%20%3D%20sim_climb_results%5Balt%5D%0A%0A%20%20%20%20%20%20%20%20axes%5B0%5D.plot(results%5B%3A%2C0%5D%2C%20results%5B%3A%2C2%5D)%0A%20%20%20%20%20%20%20%20axes%5B1%5D.plot(results%5B%3A%2C0%5D%2C%20results%5B%3A%2C1%5D)%0A%20%20%20%20%20%20%20%20axes%5B2%5D.plot(results%5B%3A%2C0%5D%2C%20results%5B%3A%2C3%5D%2C%20label%3D'Climb')%0A%20%20%20%20%20%20%20%20axes%5B2%5D.plot(results%5B%3A%2C0%5D%2C%20results%5B%3A%2C4%5D%2C%20label%3D'Level'%2C%20linestyle%3D'--')%0A%20%20%20%20%20%20%20%20axes%5B3%5D.plot(results%5B%3A%2C0%5D%2C%20results%5B%3A%2C5%5D%2C%20label%3D'Climb')%0A%20%20%20%20%20%20%20%20axes%5B3%5D.plot(results%5B%3A%2C0%5D%2C%20results%5B%3A%2C6%5D%2C%20label%3D'Level'%2C%20linestyle%3D'--')%0A%0A%20%20%20%20%20%20%20%20roc_max_index%20%3D%20np.argmax(results%5B%3A%2C2%5D)%0A%20%20%20%20%20%20%20%20v_roc_max%20%3D%20results%5B%3A%2C0%5D%5Broc_max_index%5D%0A%20%20%20%20%20%20%20%20max_roc%20%3D%20results%5B%3A%2C2%5D%5Broc_max_index%5D%0A%20%20%20%20%20%20%20%20max_gamma%20%3D%20results%5B%3A%2C1%5D%5Broc_max_index%5D%0A%0A%20%20%20%20%20%20%20%20for%20i%20in%20range(4)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.axvline(x%3Dv_roc_max%2C%20color%3D'red'%2C%20linestyle%3D'--'%2C%20linewidth%3D2)%0A%0A%20%20%20%20%20%20%20%20axes%5B0%5D.scatter(v_roc_max%2C%20max_roc%2C%20label%3Df'R%2FC%20%3D%20%7Bmax_roc%3A.0f%7D')%0A%20%20%20%20%20%20%20%20axes%5B1%5D.scatter(v_roc_max%2C%20max_gamma%2C%20label%3Df'%24%5C%5Cgamma%24%20%3D%20%7Bmax_gamma%3A.0f%7D')%0A%0A%20%20%20%20%20%20%20%20yaxes_info%20%3D%20%5B%20'ROC%20(fps)'%2C%20'Gamma%20%24%5C%5Cgamma%24'%2C%20'Throttle'%2C%20'AoA%20%24%5C%5Calpha%24'%20%5D%0A%0A%20%20%20%20%20%20%20%20for%20i%20in%20range(len(axes))%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_xlabel('TAS%20(kt)')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_ylabel(yaxes_info%5Bi%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.set_title('Altitude%200ft')%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5Bi%5D.legend()%0A%0A%20%20%20%20%20%20%20%20figure.supxlabel('Figure%2012')%0A%0A%20%20%20%20%20%20%20%20return%20plt.gca()%0A%20%20%20%20return%20(plot_jsbsim_climb_trim_roc%2C)%0A%0A%0A%40app.cell%0Adef%20_(plt%2C%20sim_climb_results%2C%20sim_results)%3A%0A%20%20%20%20%23%20Plot%20comparison%20of%20ROC%20from%20excess%20power%20calculation%20versus%20from%20max%20climb%20trim%20solution%0A%0A%20%20%20%20def%20plot_roc_excess_power_climb_trim_comparison(alt)%3A%0A%20%20%20%20%20%20%20%20figure%2C%20axes%20%3D%20plt.subplots(1%2C%202%2C%20figsize%3D(16%2C%208)%2C%20layout%3D'constrained')%0A%0A%20%20%20%20%20%20%20%20climb_trim_tas%20%3D%20sim_climb_results%5Balt%5D%5B%3A%2C0%5D%0A%20%20%20%20%20%20%20%20climb_trim_roc%20%3D%20sim_climb_results%5Balt%5D%5B%3A%2C2%5D%0A%0A%20%20%20%20%20%20%20%20power_tas%20%3D%20sim_results%5Balt%5D%5B%3A%2C0%5D%0A%20%20%20%20%20%20%20%20power_roc%20%3D%20sim_results%5Balt%5D%5B%3A%2C7%5D%0A%0A%20%20%20%20%20%20%20%20axes%5B0%5D.plot(climb_trim_tas%2C%20climb_trim_roc%2C%20label%3D'Climb%20Trim')%0A%20%20%20%20%20%20%20%20axes%5B0%5D.plot(power_tas%2C%20power_roc%2C%20label%3D'Excess%20Power')%0A%0A%20%20%20%20%20%20%20%20axes%5B1%5D.plot(climb_trim_tas%2C%20climb_trim_roc%2Fpower_roc)%0A%20%20%20%20%20%20%20%20axes%5B1%5D.axhline(y%3D1.0%2C%20linestyle%3D'--'%2C%20color%3D'grey')%0A%0A%20%20%20%20%20%20%20%20for%20axis%20in%20axes%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20axis.set_xlabel('TAS%20(kt)')%0A%20%20%20%20%20%20%20%20%20%20%20%20axis.set_title(f'Altitude%20%7Balt%7Dft')%0A%0A%20%20%20%20%20%20%20%20axes%5B0%5D.set_ylabel('ROC%20(fps)')%0A%20%20%20%20%20%20%20%20axes%5B0%5D.legend()%0A%20%20%20%20%20%20%20%20axes%5B1%5D.set_ylabel('Climb%20Trim%20ROC%20%2F%20Excess%20Power%20ROC')%0A%0A%20%20%20%20%20%20%20%20figure.supxlabel('Figure%2013')%0A%0A%20%20%20%20%20%20%20%20return%20plt.gca()%0A%20%20%20%20return%20(plot_roc_excess_power_climb_trim_comparison%2C)%0A%0A%0A%40app.cell%0Adef%20_(jsbsim%2C%20math)%3A%0A%20%20%20%20def%20trim_analysis(tas%2C%20alt%2C%20gamma)%3A%0A%20%20%20%20%20%20%20%20AIRCRAFT_NAME%3D%22737%22%0A%20%20%20%20%20%20%20%20%23%20Path%20to%20JSBSim%20files%2C%20location%20of%20the%20folders%20%22aircraft%22%2C%20%22engines%22%20and%20%22systems%22%0A%20%20%20%20%20%20%20%20PATH_TO_JSBSIM_FILES%3D%22data%2Fjsbsim%22%0A%0A%20%20%20%20%20%20%20%20%23%20Avoid%20flooding%20the%20console%20with%20log%20messages%0A%20%20%20%20%20%20%20%20jsbsim.FGJSBBase().debug_lvl%20%3D%200%0A%0A%20%20%20%20%20%20%20%20fdm%20%3D%20jsbsim.FGFDMExec(PATH_TO_JSBSIM_FILES)%0A%0A%20%20%20%20%20%20%20%20%23%20Load%20the%20aircraft%20model%0A%20%20%20%20%20%20%20%20fdm.load_model(AIRCRAFT_NAME)%0A%0A%20%20%20%20%20%20%20%20%23%20Set%20engines%20running%0A%20%20%20%20%20%20%20%20fdm%5B'propulsion%2Fset-running'%5D%20%3D%20-1%0A%0A%20%20%20%20%20%20%20%20%23%20Set%20alpha%20range%20for%20trim%20solutions%0A%20%20%20%20%20%20%20%20fdm%5B'aero%2Falpha-max-rad'%5D%20%3D%20math.radians(12)%0A%20%20%20%20%20%20%20%20fdm%5B'aero%2Falpha-min-rad'%5D%20%3D%20math.radians(-4.0)%0A%0A%20%20%20%20%20%20%20%20results%20%3D%20%5B%5D%0A%0A%20%20%20%20%20%20%20%20fdm%5B'ic%2Fh-sl-ft'%5D%20%3D%20alt%0A%20%20%20%20%20%20%20%20fdm%5B'ic%2Fvt-kts'%5D%20%3D%20tas%0A%20%20%20%20%20%20%20%20fdm%5B'ic%2Fgamma-deg'%5D%20%3D%20gamma%0A%0A%20%20%20%20%20%20%20%20%23%20Initialize%20the%20aircraft%20with%20initial%20conditions%0A%20%20%20%20%20%20%20%20fdm.run_ic()%0A%0A%20%20%20%20%20%20%20%20%23%20Trim%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'simulation%2Fdo_simple_trim'%5D%20%3D%201%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20(gamma%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'fcs%2Fthrottle-cmd-norm%5B0%5D'%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'aero%2Falpha-deg'%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'forces%2Ffwz-aero-lbs'%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'forces%2Ffwx-aero-lbs'%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%202*fdm%5B'propulsion%2Fengine%5B0%5D%2Fthrust-lbs'%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'inertia%2Fweight-lbs'%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fdm%5B'velocities%2Fmach'%5D)%0A%20%20%20%20%20%20%20%20except%20jsbsim.TrimFailureError%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(max_thrust)%3A%0A%20%20%20%20%23%202D%20interpolation%20thrust%20lookup%20test%0A%20%20%20%20max_thrust(150%2C%200.498)%0A%20%20%20%20return%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%23%20References%0A%0A%20%20%20%20Most%20of%20the%20theory%20section%20in%20this%20notebook%20comes%20from%20the%20SRM%20class%20notes%20reference.%0A%0A%20%20%20%20%5BSRM%20Institute%20of%20Science%20and%20Technology%20-%20Class%20Notes%5D(https%3A%2F%2Fwebstor.srmist.edu.in%2Fweb_assets%2Fsrm_mainsite%2Ffiles%2Fdownloads%2Fclass12-2012.pdf)%0A%0A%20%20%20%20%5BMSc%20thesis%20-%20Aircraft%20Flight%20Control%3A%20Advancing%20Towards%20Human-Like%20Behavior%20(Leonardo%20Molino)%5D()%0A%0A%20%20%20%20%5BEnergy-based%20Multiple-Input-Multiple-Output%20nonlinear%20control%20of%20fixed-wing%20aircraft%20(Leonardo%20Molino%2C%20Agostino%20De%20Marco%2C%20Sabato%20Manfredi)%5D(https%3A%2F%2Fwww.linkedin.com%2Fposts%2Fagostino-de-marco-08398a7_presentation-by-de-marco-et-al-nodycon-2025-activity-7343309822525607937-opP5%3Futm_source%3Dshare%26utm_medium%3Dmember_desktop%26rcm%3DACoAAAAbR04BVZw2ZGYntq-M24BwQiSJ1KHuRiQ)%0A%0A%20%20%20%20%23%23%23%23%20TECS%0A%0A%20%20%20%20%5BIntegrated%20Autopilot%2FAutothrottle%20Based%20on%20a%20Total%20Energy%20Control%20Concept%3A%20Design%20and%20Evaluation%20%0A%20%20%20%20of%20Additional%20Autopilot%20Modes%5D(https%3A%2F%2Fntrs.nasa.gov%2Fapi%2Fcitations%2F19880010924%2Fdownloads%2F19880010924.pdf)%0A%0A%20%20%20%20%5BNASA%20B737%20Flight%20Test%20Results%20of%20the%20Total%20Energy%20Control%20System%5D(https%3A%2F%2Fntrs.nasa.gov%2Fapi%2Fcitations%2F19870017485%2Fdownloads%2F19870017485.pdf)%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%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%20Imports%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20import%20math%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20from%20mpl_toolkits.mplot3d%20import%20Axes3D%0A%20%20%20%20from%20scipy.interpolate%20import%20RegularGridInterpolator%0A%20%20%20%20import%20jsbsim%0A%20%20%20%20return%20RegularGridInterpolator%2C%20jsbsim%2C%20math%2C%20mo%2C%20np%2C%20plt%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
a6dc4d90f08a279f4cec7a2b3a7ecb6c1ced3e8abf4d879073502bece7680751