<jupyter_start><jupyter_text>Multirotor validator eCalc<jupyter_code>import ipywidgets as widgets
from ipywidgets import interact, Dropdown, HBox
import ipyvuetify as v
import math
from math import pi, sqrt
from IPython.display import clear_output
from ipywidgets import interactive, AppLayout, HTML, Layout
import numpy as np
import pandas as pd

path='./Propeller/'
df_pro = pd.read_csv(path+'Propeller_Data.csv', sep=';')
path='./Batteries/'
df_bat = pd.read_csv(path+'Batteries_Data.csv', sep=';')
path='./Motors/'
df_mot = pd.read_csv(path+'Motors_Data.csv', sep=';')
path='./ESC/'
df_esc = pd.read_csv(path+'ESC_Data.csv', sep=';')

style = {'description_width': '150pt'}
layout = {'width': '500pt'}
label_layout = widgets.Layout(width='50px')

Motmodel =widgets.HTML(value = f"<b><font color='red'>{'Motor parameters'}</b>")

Mot= Dropdown(
    options= df_mot['Model'].values,
    description='Motor model:',
    value='?Scorpion SII-4020-420KV',
    disabled=False,
)
df_motfilter=df_mot[df_mot['Model']== Mot.value] #filter data containing such values

Kt_DC= Dropdown(
    options=df_motfilter['Kt_Nm_A'].values,
    description='K_T:(Nm/A)',
    disabled=True,
)

Tmot_DC= Dropdown(
    options=df_motfilter['Tnom_Nm'].values,
    description='Nominal torque(N.m)',
    disabled=True,
)

Propmodel =widgets.HTML(value = f"<b><font color='red'>{'Propeller parameters'}</b>")

Dia_DC= Dropdown(
    options= sorted(df_pro['DIAMETER_IN'].unique().tolist()),
    description='Propeller diameter: (in)',
    value=10,
    disabled=False,
)

df_profilter=df_pro[df_pro['DIAMETER_IN']== Dia_DC.value] #filter data containing such values

Pitch_DC= Dropdown(
    options= sorted(df_profilter['BETA'].unique().tolist()),
    description='Pitch/diameter:',
    disabled=False,)


Batmodel =widgets.HTML(value = f"<b><font color='red'>{'Battery parameters'}</b>")
                       
Cbat_DC= Dropdown(
    options= sorted(df_bat['Capacity_mAh'].unique().tolist()),
    value=4000,
    description='Capacity (mAh):',
    disabled=False,)

df_batfilter=df_bat[df_bat['Capacity_mAh']== Cbat_DC.value] #filter data containing such values

Ubat_DC= Dropdown(
    options= sorted(df_batfilter['Voltage_V'].unique().tolist()),
    description='Voltage (V):',
    disabled=False,)

df_batfilter_model=df_bat[(df_bat['Capacity_mAh']==Cbat_DC.value) & (df_bat['Voltage_V']==Ubat_DC.value)] #filter data containing such values

Modelbat= Dropdown(
    options=sorted(df_batfilter_model['Model'].unique().tolist()),
    description='Model battery',
    disabled=False,
)

ESCmodel =widgets.HTML(value = f"<b><font color='red'>{'ESC parameters'}</b>")

Pesc_DC= Dropdown(
    options= sorted(df_esc['Power_max_W'].unique().tolist()),
    description='Power ESC:',
    value=266,
    disabled=False,)

df_escfilter=df_esc[df_esc['Power_max_W']== Pesc_DC.value] #filter data containing such values

Vesc_DC= Dropdown(
    options= sorted(df_escfilter['V_max_V'].unique().tolist()),
    description='Voltage ESC (V):',
    disabled=False,)

df_escfilter_model=df_esc[(df_esc['Power_max_W']==Pesc_DC.value) & (df_esc['V_max_V']==Vesc_DC.value)] #filter data containing such values

Modelesc= Dropdown(
    options=sorted(df_escfilter_model['Model'].unique().tolist()),
    description='Model ESC',
    disabled=False,
)
                                             

archit = widgets.HTML(value = f"<b><font color='red'>{'Architecture'}</b>")

Narm_slider_DC = widgets.FloatSlider(
    value=8,
    min=3,
    max=12,
    step=1,
    description='Number of arms [-]',
    readout_format='.0f', style=style, layout=layout
)

Narm_tex_DC = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Narm_slider_DC, 'value'), (Narm_tex_DC, 'value'))
                      
D_ratio_slider_DC = widgets.FloatSlider(
    value=0.8,
    min=0.01,
    max=0.99,
    step=1,
    description='Ratio inner / outer diameter [-]',
    readout_format='.0f', style=style, layout=layout
)

D_ratio_tex_DC = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((D_ratio_slider_DC, 'value'), (D_ratio_tex_DC, 'value'))

Narm_DC=widgets.HBox([Narm_slider_DC,Narm_tex_DC,D_ratio_slider_DC,D_ratio_tex_DC])                     

Np_arm_DC=widgets.ToggleButtons(options=['Single rotor setup', 'Coaxial setup'],
    description='Number of propellers per arm:',
    disabled=False,style=style)

Mod_DC=widgets.ToggleButtons(options=['Direct Drive', 'Gear Drive'],
    description='Motor configuration:',
    tooltips=['No speed reductor', 'Motor with reduction'],style=style)

# A_top_slider = widgets.FloatSlider(
#     value=0.09,
#     min=0.01,
#     max=1,
#     step=0.01,
#     description='Top surface [m^2]',
#     readout_format='.2f', style=style, layout=layout
# )

# A_top_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

# widgets.link((A_top_slider, 'value'), (A_top_tex, 'value'))

# A_top_DC = widgets.HBox([A_top_slider,A_top_tex])   
                      
arc=widgets.HBox([Np_arm_DC,Mod_DC]) 
                      
perf = widgets.HTML(value = f"<b><font color='red'>{'Performance'}</b>")

k_maxthrust_slider_DC = widgets.FloatSlider(
    value=3,
    min=1.1,
    max=4,
    step=.1,
    description='Ratio max thrust-hover [-]',
    readout_format='.1f', style=style, layout=layout
)

k_maxthrust_tex_DC = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((k_maxthrust_slider_DC, 'value'), (k_maxthrust_tex_DC, 'value'))

k_maxthrust_DC=widgets.HBox([k_maxthrust_slider_DC,k_maxthrust_tex_DC])                     

V_cl_slider_DC = widgets.FloatSlider(
    value=8,
    min=1,
    max=10,
    step=1,
    description='Rate of climb [m/s]',
    readout_format='.0f', style=style, layout=layout
)

V_cl_tex_DC = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((V_cl_slider_DC, 'value'), (V_cl_tex_DC, 'value'))

V_cl_DC = widgets.HBox([V_cl_slider_DC,V_cl_tex_DC])                     

Nred_slider_DC = widgets.FloatSlider(
    value=1,
    min=1,
    max=3,
    step=1,
    description='Geat ratio',
    readout_format='.2f', style=style, layout=layout
)

Nred_tex_DC = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Nred_slider_DC, 'value'), (Nred_tex_DC, 'value'))

Nred_DC = widgets.HBox([Nred_slider_DC,Nred_tex_DC])  

Ncel_slider_DC = widgets.FloatSlider(
    value=4,
    min=1,
    max=30,
    step=1,
    description='Cell number in series',
    readout_format='.0f', style=style, layout=layout
)

Ncel_tex_DC = widgets.FloatText(description="", continuous_update=False)

widgets.link((Ncel_slider_DC, 'value'), (Ncel_tex_DC, 'value'))

Ncel_DC = widgets.HBox([Ncel_slider_DC,Ncel_tex_DC])  

NcelPar_slider_DC = widgets.FloatSlider(
    value=3,
    min=1,
    max=30,
    step=1,
    description='Cell number in parallel',
    readout_format='.0f', style=style, layout=layout
)

NcelPar_tex_DC = widgets.FloatText(description="", continuous_update=False)

widgets.link((NcelPar_slider_DC, 'value'), (NcelPar_tex_DC, 'value'))

NcelPar_DC = widgets.HBox([NcelPar_slider_DC,NcelPar_tex_DC])  
                    
M_pay_DC = widgets.FloatSlider(
    value=4.,
    min=1,
    max=100.0,
    step=.1,
    description='Load mass [kg]:',
    readout_format='.1f', style=style, layout=layout
)

M_load_tex_DC = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((M_pay_DC, 'value'), (M_load_tex_DC, 'value'))

M_load_DC=widgets.HBox([M_pay_DC,M_load_tex_DC])                     

NDmax_slider = widgets.FloatSlider(
    value=105000/60*0.0254,
    min=0.1,
    max=100,
    step=1,
    description='Max Rotational Speed [Hz*m]',
    readout_format='.2f', style=style, layout=layout
)

NDmax_tex = widgets.FloatText(description="", readout_format='.2f', continuous_update=False,layout=label_layout)

widgets.link((NDmax_slider, 'value'), (NDmax_tex, 'value'))

NDmax_w = widgets.HBox([NDmax_slider,NDmax_tex])                     

rho_air_slider = widgets.FloatSlider(
    value=1.2,
    min=1,
    max=1.3,
    step=0.01,
    description='Air density [kg/m^3]',
    readout_format='.2f', style=style, layout=layout
)

rho_air_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((rho_air_slider, 'value'), (rho_air_tex, 'value'))
                       
rho_air_w = widgets.HBox([rho_air_slider,rho_air_tex])                     
                       
C_D_slider = widgets.FloatSlider(
    value=1.18,
    min=1,
    max=3,
    step=0.1,
    description='Drag coefficient [-]',
    readout_format='.1f', style=style, layout=layout
)

C_D_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((C_D_slider, 'value'), (C_D_tex, 'value'))
                       
C_D_w = widgets.HBox([C_D_slider,C_D_tex])                     

Dpro_ref_slider = widgets.FloatSlider(
    value=11*.0254,
    min=0,
    max=50*0.0254,
    step=0.1,
    description='Propeller diameter of reference [m]',
    readout_format='.1f', style=style, layout=layout
)

Dpro_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Dpro_ref_slider, 'value'), (Dpro_ref_tex, 'value'))
                       
Dpro_ref_w= widgets.HBox([Dpro_ref_slider,Dpro_ref_tex])                     

Mpro_ref_slider = widgets.FloatSlider(
    value=0.53*0.0283,
    min=0,
    max=5,
    step=0.1,
    description='Propeller mass of reference [kg]',
    readout_format='.1f', style=style, layout=layout
)

Mpro_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Mpro_ref_slider, 'value'), (Mpro_ref_tex, 'value'))
                       
Mpro_ref_w= widgets.HBox([Mpro_ref_slider,Mpro_ref_tex])                     

Tmot_ref_slider = widgets.FloatSlider(
    value=2.32,
    min=0,
    max=15,
    step=0.1,
    description='Motor torque of reference [N.m]',
    readout_format='.1f', style=style, layout=layout
)

Tmot_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Tmot_ref_slider, 'value'), (Tmot_ref_tex, 'value'))
                       
Tmot_ref_w= widgets.HBox([Tmot_ref_slider,Tmot_ref_tex])                     

Rmot_ref_slider = widgets.FloatSlider(
    value=0.03,
    min=0,
    max=1,
    step=0.01,
    description='Motor resistance of reference [Ohm]',
    readout_format='.1f', style=style, layout=layout
)

Rmot_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Rmot_ref_slider, 'value'), (Rmot_ref_tex, 'value'))
                       
Rmot_ref_w= widgets.HBox([Rmot_ref_slider,Rmot_ref_tex])                     

Mmot_ref_slider = widgets.FloatSlider(
    value=0.575,
    min=0,
    max=10,
    step=0.01,
    description='Motor mass of reference [kg]',
    readout_format='.1f', style=style, layout=layout
)

Mmot_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Mmot_ref_slider, 'value'), (Mmot_ref_tex, 'value'))
                       
Mmot_ref_w= widgets.HBox([Mmot_ref_slider,Mmot_ref_tex])     

Ktmot_ref_slider = widgets.FloatSlider(
    value=0.03,
    min=0,
    max=1,
    step=0.01,
    description='Torque coefficient of reference [N.m/A]',
    readout_format='.1f', style=style, layout=layout
)

Ktmot_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Ktmot_ref_slider, 'value'), (Ktmot_ref_tex, 'value'))
                       
Ktmot_ref_w= widgets.HBox([Ktmot_ref_slider,Ktmot_ref_tex])  
                      
                       
Tfmot_ref_slider = widgets.FloatSlider(
    value=0.03,
    min=0,
    max=1,
    step=0.01,
    description='Friction torque of reference [N.m/A]',
    readout_format='.1f', style=style, layout=layout
)

Tfmot_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Tfmot_ref_slider, 'value'), (Tfmot_ref_tex, 'value'))
                       
Tfmot_ref_w= widgets.HBox([Ktmot_ref_slider,Ktmot_ref_tex])  

Mbat_ref_slider = widgets.FloatSlider(
    value=0.329,
    min=0,
    max=40,
    step=0.01,
    description='Battery mass of reference [N.m/A]',
    readout_format='.2f', style=style, layout=layout
)

Mbat_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Mbat_ref_slider, 'value'), (Mbat_ref_tex, 'value'))
                       
Mbat_ref_w= widgets.HBox([Mbat_ref_slider,Mbat_ref_tex])
                       
Cbat_ref_slider = widgets.FloatSlider(
    value=3.400*3600,
    min=0,
    max=340*3600,
    step=0.01,
    description='Battery capacity of reference [A.s]',
    readout_format='.2f', style=style, layout=layout
)

Cbat_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Cbat_ref_slider, 'value'), (Cbat_ref_tex, 'value'))
                       
Cbat_ref_w= widgets.HBox([Cbat_ref_slider,Cbat_ref_tex])
                       
Vbat_ref_slider = widgets.FloatSlider(
    value=4*3.7,
    min=3.7,
    max=20*3.7,
    step=0.01,
    description='Battery voltage of reference [V]',
    readout_format='.2f', style=style, layout=layout
)

Vbat_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Vbat_ref_slider, 'value'), (Vbat_ref_tex, 'value'))
                       
Vbat_ref_w= widgets.HBox([Vbat_ref_slider,Vbat_ref_tex])
                       
Imax_ref_slider = widgets.FloatSlider(
    value=170,
    min=0,
    max=400,
    step=0.01,
    description='Max current of reference [A]',
    readout_format='.2f', style=style, layout=layout
)

Imax_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Imax_ref_slider, 'value'), (Imax_ref_tex, 'value'))
                       
Imax_ref_w= widgets.HBox([Imax_ref_slider,Imax_ref_tex])
                       
Pesc_ref_slider = widgets.FloatSlider(
    value=3108,
    min=0,
    max=6000,
    step=0.01,
    description='ESC power of reference [W]',
    readout_format='.0f', style=style, layout=layout
)

Pesc_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Pesc_ref_slider, 'value'), (Pesc_ref_tex, 'value'))
                       
Pesc_ref_w= widgets.HBox([Pesc_ref_slider,Pesc_ref_tex])

                       
Vesc_ref_slider = widgets.FloatSlider(
    value=44.4,
    min=0,
    max=100,
    step=0.01,
    description='ESC voltage of reference [W]',
    readout_format='.1f', style=style, layout=layout
)

Vesc_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Vesc_ref_slider, 'value'), (Vesc_ref_tex, 'value'))
                       
Vesc_ref_w= widgets.HBox([Vesc_ref_slider,Vesc_ref_tex])

Mesc_ref_slider = widgets.FloatSlider(
    value=.115,
    min=0,
    max=1,
    step=0.01,
    description='ESC power of reference [W]',
    readout_format='.3f', style=style, layout=layout
)

Mesc_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Mesc_ref_slider, 'value'), (Mesc_ref_tex, 'value'))
                       
Mesc_ref_w= widgets.HBox([Mesc_ref_slider,Mesc_ref_tex])

Mfra_ref_slider = widgets.FloatSlider(
    value=.347,
    min=0,
    max=1,
    step=0.01,
    description='Frame mass of reference [kg]',
    readout_format='.3f', style=style, layout=layout
)

Mfra_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Mfra_ref_slider, 'value'), (Mfra_ref_tex, 'value'))
                       
Mfra_ref_w= widgets.HBox([Mfra_ref_slider,Mfra_ref_tex])

Marm_ref_slider = widgets.FloatSlider(
    value=.14,
    min=0,
    max=1,
    step=0.1,
    description='Arms mass of reference [kg]',
    readout_format='.3f', style=style, layout=layout
)

Marm_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Marm_ref_slider, 'value'), (Marm_ref_tex, 'value'))
                       
Marm_ref_w= widgets.HBox([Marm_ref_slider,Marm_ref_tex])

Sigma_max_ref_slider = widgets.FloatSlider(
    value=280e6/4,
    min=0,
    max=1e8,
    step=10e6,
    description='Arms mass of reference [kg]',
    readout_format='.0f', style=style, layout=layout
)

Sigma_max_ref_tex = widgets.FloatText(description="", continuous_update=False,layout=label_layout)

widgets.link((Sigma_max_ref_slider, 'value'), (Sigma_max_ref_tex, 'value'))
                       
Sigma_max_ref_w= widgets.HBox([Sigma_max_ref_slider,Sigma_max_ref_tex])            

w2=v.Tabs(_metadata={'mount_id': 'content-main'}, children=[
    v.Tab(children=['Specs.']),
    v.Tab(children=['References']),
    v.TabItem(children=[Motmodel,HBox([Mot,Kt_DC,Tmot_DC]), Propmodel,HBox([Dia_DC,Pitch_DC]), Batmodel, HBox([Cbat_DC,Ubat_DC,Modelbat]), Ncel_DC,NcelPar_DC,ESCmodel, HBox([Pesc_DC,Vesc_DC, Modelesc]),archit, Narm_DC,arc, perf, k_maxthrust_DC,V_cl_DC,Nred_DC,M_load_DC]),
    v.TabItem(children=[rho_air_w,NDmax_w,C_D_w,Dpro_ref_w,Mpro_ref_w,Tmot_ref_w,Rmot_ref_w,Mmot_ref_w,Ktmot_ref_w,Tfmot_ref_w,Mbat_ref_w,
                       Cbat_ref_w,Vbat_ref_w,Imax_ref_w,Pesc_ref_w,Vesc_ref_w,Mesc_ref_w,Mfra_ref_w,Marm_ref_w,Sigma_max_ref_w]),
               ]
    )

display(w2)
def change_event(x):
    clear_output()    
    df_motfilter=df_mot[df_mot['Model']== Mot.value] #filter data containing such values
    df_profilter=df_pro[df_pro['DIAMETER_IN']== Dia_DC.value] #filter data containing such values
    df_batfilter=df_bat[df_bat['Capacity_mAh']== Cbat_DC.value] #filter data containing such values
    df_batfilter_model=df_bat[(df_bat['Capacity_mAh']==Cbat_DC.value) & (df_bat['Voltage_V']==Ubat_DC.value)] #filter data containing such values                   
    df_escfilter= df_esc[df_esc['Power_max_W']== Pesc_DC.value] #filter data containing such values
    df_escfilter_model=df_esc[(df_esc['Power_max_W']==Pesc_DC.value) & (df_esc['V_max_V']==Vesc_DC.value)] #filter data containing such values                   
    Kt_DC.options = df_motfilter['Kt_Nm_A'].values
    Tmot_DC.options = df_motfilter['Tnom_Nm'].values
    Ubat_DC.options= sorted(df_batfilter['Voltage_V'].unique().tolist())              
    Modelbat.options=sorted(df_batfilter_model['Model'].unique().tolist())
    Vesc_DC.options= sorted(df_escfilter['V_max_V'].unique().tolist())
    Modelesc.options= sorted(df_escfilter_model['Model'].unique().tolist())
    Pitch_DC.options = sorted(df_profilter['BETA'].unique().tolist())
    display(w2)

    
Dia_DC.observe(change_event)
Mot.observe(change_event)
Cbat_DC.observe(change_event)                       
Ubat_DC.observe(change_event) 
Vesc_DC.observe(change_event) 
Pesc_DC.observe(change_event)                    
def Calculator(param):
    Ktmot=float(param[0])
    Tmot=float(param[1])
    Dpro=float(param[2])
    beta=float(param[3])
    Cbat=float(param[4])#[As] Capacity battery As
    Ncel=float(param[5])
    NcelPar=float(param[6])
    Ubat=float(param[7])
    P_esc=float(param[8])

    Vesc=float(param[9])
    Narm=float(param[10])
    D_ratio=float(param[11])
    Np_arm=param[12]
    Mod=param[13]
    k_maxthrust=float(param[14])
    V_cl=float(param[15])
    Nred=float(param[16])
    M_load=float(param[17])

    #Ref. values:
    rho_air=float(param[18])
    NDmax=float(param[19])
    C_D=float(param[20])
    Dpro_ref=float(param[21])
    Mpro_ref=float(param[22])
    Tmot_ref=float(param[23])
    Rmot_ref=float(param[24])
    Mmot_ref=float(param[25])
    Ktmot_ref=float(param[26])
    Tfmot_ref=float(param[27])
    Mbat_ref=float(param[28])
    Cbat_ref=float(param[29])
    Vbat_ref=float(param[30])
    Imax_ref=float(param[31])
    Pesc_ref=float(param[32])
    Vesc_ref=float(param[33])
    Mesc_ref=float(param[34])
    Mfra_ref=float(param[35])
    Marm_ref=float(param[36])
    Sigma_max_ref=float(param[37])

#     print(beta,V_cl)
    #Propeller number:

    if Np_arm=='Gear Drive':      
        Npro=1*(Narm) # [-] Propellers number
    else: 
        Npro=2*(Narm) # [-] Propellers number

    #Propeller models

    C_t_sta=4.27e-02 + 1.44e-01 * beta # Thrust coef with T=C_T.rho.n^2.D^4
    C_p_sta=-1.48e-03 + 9.72e-02 * beta  # Power coef with P=C_p.rho.n^3.D^5


    n_pro_to=NDmax/Dpro #[Hz] max rotational speed 
    F_pro_to=C_t_sta*(rho_air)*Dpro**4*n_pro_to**2# [N] max propeller thrust


    # Frame float(parameters

    Lbra=Dpro/2/(math.sin(pi/(Narm)))  #[m] length of the arm
    Dout=(F_pro_to*Lbra*32/(pi*Sigma_max_ref*(1-D_ratio**4)))**(1/3) # [m] outer diameter of the beam 

    #Total mass:
    Mpro=Mpro_ref*(Dpro/Dpro_ref)**3 # [kg] Propeller mass
    Mmot=Mmot_ref*(Tmot/Tmot_ref)**(3/3.5) # [kg] Motor mass
    Mesc = Mesc_ref*(P_esc/Pesc_ref) # [kg] Mass ESC
    Mbat=Mbat_ref*(NcelPar*Cbat/Cbat_ref)*(Ncel*Ubat/Vbat_ref) # Battery mass

    Marm=pi/4*(Dout**2-(D_ratio*Dout)**2)*Lbra*1700*(Narm) # [kg] mass of the arms

    Mfra=Mfra_ref*(Marm/Marm_ref)# [kg] mass of the frame

    #Gear box model
    if Mod=='Gear Drive':
        mg1=0.0309*Nred**2+0.1944*Nred+0.6389       # Ratio input pinion to mating gear
        WF=1+1/mg1+mg1+mg1**2+Nred**2/mg1+Nred**2   # Weight Factor (ƩFd2/C) [-]
        k_sd=1000                                   # Surface durability factor [lb/in]
        C=2*8.85*Tmot_hover/k_sd                    # Coefficient (C=2T/K) [in3]
        Fd2=WF*C                                    # Solid rotor volume [in3]
        Mgear=Fd2*0.3*0.4535                        # Mass reducer [kg] (0.3 is a coefficient evaluated for aircraft application and 0.4535 to pass from lb to kg)
        Fdp2=C*(Nred+1)/Nred                        # Solid rotor pinion volume [in3]
        dp=(Fdp2/0.7)**(1/3)*0.0254                 # Pinion diameter [m] (0.0254 to pass from in to m)
        dg=Nred*dp                                  # Gear diameter [m]
        di=mg1*dp                                   # Inler diameter [m]        

    # Propeller numbers:
    # Total mass:
    if Mod=='Direct Drive':
        Mtotal = (Mesc+Mpro+Mmot)*Npro+(M_load)+Mbat+Mfra+Marm #total mass without reducer
    else:
        Mtotal = (Mesc+Mpro+Mmot+Mgear)*Npro+(M_load)+Mbat+Mfra+Marm #total mass with reducer

    #Propeller thrust
    F_pro_hov=Mtotal*(9.81)/Npro # [N] Thrust per propeller for hover

    # Propeller selection with take-off scenario
    pitch=beta*Dpro # [m] Propeller pitch

    # Propeller selection with take-off scenario

    Wpro_to=n_pro_to*2*3.14 # [rad/s] Propeller speed
    Ppro_to=C_p_sta*(rho_air)*n_pro_to**3*Dpro**5# [W] Power per propeller
    Qpro_to=Ppro_to/Wpro_to # [N.m] Propeller torque

    # Propeller torque& speed for hover

    n_pro_hover=sqrt(F_pro_hov/(C_t_sta*(rho_air)*Dpro**4)) # [Hz] hover speed
    Wpro_hover=n_pro_hover*2*3.14 # [rad/s] Propeller speed    

    Ppro_hover=C_p_sta*(rho_air)*n_pro_hover**3*Dpro**5# [W] Power per propeller
    Qpro_hover=Ppro_hover/Wpro_hover # [N.m] Propeller torque    

    #---------------------------------
    # Motor
    # Motor selection & scaling laws
    # ---
        # Motor reference sized from max thrust
        # Ref : AXI 5325/16 GOLD LINE


    Tmot_max_ref=85/70*Tmot_ref # [N.m] max torque

    #Motor speeds:
    if Mod=='Gear Drive':
        W_hover_motor=Wpro_hover*Nred # [rad/s] Nominal motor speed with reduction
        W_to_motor=Wpro_to*Nred # [rad/s] Motor take-off speed with reduction
    else:
        W_hover_motor=Wpro_hover # [rad/s] Nominal motor speed 
        W_to_motor=Wpro_to # [rad/s] Motor take-off speed

    #Motor torque:

    if Mod=='Gear Drive':       
        Tmot_hover=Qpro_hover/Nred # [N.m] motor nominal torque with reduction
        Tmot_to=Qpro_to/Nred # [N.m] motor take-off torque with reduction


    else:
        Tmot_hover=Qpro_hover# [N.m] motor take-off torque
        Tmot_to=Qpro_to # [N.m] motor take-off torque

    Tmot_max=Tmot_max_ref*(Tmot/Tmot_ref)**(1) # [N.m] max torque


    # Selection with take-off speed
    Rmot=Rmot_ref*(Tmot/Tmot_ref)**(-5/3.5)*(Ktmot/Ktmot_ref)**(2)  # [Ohm] motor resistance
    Tfmot=Tfmot_ref*(Tmot/Tmot_ref)**(3/3.5) # [N.m] Friction torque

    # Hover current and voltage

    Imot_hover = (Tmot_hover+Tfmot)/Ktmot # [I] Current of the motor per propeller
    Umot_hover = Rmot*Imot_hover + W_hover_motor*Ktmot # [V] Voltage of the motor per propeller
    P_el_hover = Umot_hover*Imot_hover # [W] Hover : output electrical power

    # Take-Off current and voltage
    Imot_to = (Tmot_to+Tfmot)/Ktmot # [I] Current of the motor per propeller
    Umot_to = Rmot*Imot_to + W_to_motor*Ktmot # [V] Voltage of the motor per propeller
    P_el_to = Umot_to*Imot_to # [W] Takeoff : output electrical power

    #----------------
    #Battery

    I_bat = (P_el_hover*Npro)/.95/Ncel/Ubat # [I] Current of the battery
    t_hf = .8*NcelPar*Cbat/I_bat/60 # [min] Hover time 
    Imax=Imax_ref*NcelPar*Cbat/Cbat_ref # [A] max current battery

    col_names = ['Type', 'Name', 'Value', 'Unit', 'Comment']
    
    #print
    df = pd.DataFrame()
    df = df.append([{'Type': 'Constraints', 'Name': 'Const 0', 'Value': (Tmot_max-Tmot_to)/Tmot_max, 'Unit': '[-]', 'Comment': '(Tmot_max-Tmot_to)/Tmot_max'}],sort=True)[col_names]
    df = df.append([{'Type': 'Constraints', 'Name': 'Const 1', 'Value': (Tmot-Qpro_hover)/Tmot,  'Unit': '[-]', 'Comment': '(Tmot-Qpro_hover)/Tmot'}])[col_names]
    df = df.append([{'Type': 'Constraints', 'Name': 'Const 2', 'Value': (Ncel*Ubat-Umot_to)/Ubat, 'Unit': '[-]', 'Comment': '(V_bat-Umot_takeoff)/V_bat)'}])[col_names]
    df = df.append([{'Type': 'Constraints', 'Name': 'Const 3', 'Value': (Ncel*Ubat-Vesc)/Ncel/Ubat, 'Unit': '[-]', 'Comment': '(V_bat-Vesc)/V_bat'}])[col_names]
    df = df.append([{'Type': 'Constraints', 'Name': 'Const 4', 'Value': (Ncel*Ubat*Imax-Umot_to*Imot_to*Npro/0.95)/(Ncel*Ubat*I_bat), 'Unit': '[-]', 'Comment': '(V_bat*Imax-Umot_takeoff*Imot_takeoffr*Npro/0.95)/(V_bat*I_bat'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'F_pro_to', 'Value': F_pro_to, 'Unit': '[N]', 'Comment': 'Thrust for 1 propeller during Take Off'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'F_pro_hov', 'Value': F_pro_hov, 'Unit': '[N]', 'Comment': 'Thrust for 1 propeller during Hover'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'rho_air', 'Value': (rho_air), 'Unit': '[kg/m^3]', 'Comment': 'Air density'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'ND_max', 'Value': (NDmax), 'Unit': '[Hz.m]', 'Comment': 'Max speed limit (N.D max)'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'Dpro_ref', 'Value': Dpro_ref, 'Unit': '[m]', 'Comment': 'Reference propeller diameter'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'M_pro_ref', 'Value': Mpro_ref, 'Unit': '[kg]', 'Comment': 'Reference propeller mass'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'C_t_sta', 'Value': C_t_sta, 'Unit': '[-]', 'Comment': 'Static thrust coefficient of the propeller'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'C_p_sta', 'Value': C_p_sta, 'Unit': '[-]', 'Comment': 'Static power coefficient of the propeller'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'D_pro', 'Value': Dpro, 'Unit': '[m]', 'Comment': 'Diameter of the propeller'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'n_pro_to', 'Value': n_pro_to, 'Unit': '[Hz]', 'Comment': 'Rev speed of the propeller during takeoff'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'n_pro_hov', 'Value': n_pro_hover, 'Unit': '[Hz]', 'Comment': 'Rev speed of the propeller during hover'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'P_pro_to', 'Value': Ppro_to, 'Unit': '[W]', 'Comment': 'Power on the mechanical shaft of the propeller during takeoff'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'P_pro_hov', 'Value': Ppro_hover, 'Unit': '[W]', 'Comment': 'Power on the mechanical shaft of the propeller during hover'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'M_pro', 'Value': Mpro, 'Unit': '[kg]', 'Comment': 'Mass of the propeller'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'Omega_pro_to', 'Value': Wpro_to, 'Unit': '[rad/s]', 'Comment': 'Rev speed of the propeller during takeoff'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'Omega_pro_hov', 'Value': Wpro_hover, 'Unit': '[rad/s]', 'Comment': 'Rev speed of the propeller during hover'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'T_pro_hov', 'Value': Qpro_hover, 'Unit': '[N.m]', 'Comment': 'Torque on the mechanical shaft of the propeller during hover'}])[col_names]
    df = df.append([{'Type': 'Propeller', 'Name': 'T_pro_to', 'Value': Qpro_to, 'Unit': '[N.m]', 'Comment': 'Torque on the mechanical shaft of the propeller during takeoff'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'T_max_mot_ref', 'Value': Tmot_max_ref, 'Unit': '[N.m]', 'Comment': 'Max torque'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'R_mot_ref', 'Value': Rmot_ref, 'Unit': '[Ohm]', 'Comment': 'Resistance'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'M_mot_ref', 'Value': Mmot_ref, 'Unit': '[kg]', 'Comment': 'Reference motor mass'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'K_mot_ref', 'Value': Ktmot_ref, 'Unit': '[N.m/A]', 'Comment': 'Torque coefficient'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'T_mot_fr_ref', 'Value': Tfmot_ref, 'Unit': '[N.m]', 'Comment': 'Friction torque (zero load, nominal speed)'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'T_nom_mot', 'Value': Tmot_hover, 'Unit': '[N.m]', 'Comment': 'Continuous of the selected motor torque'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'T_mot_to', 'Value': Tmot_to, 'Unit': '[N.m]', 'Comment': 'Transient torque possible for takeoff'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'T_max_mot', 'Value': Tmot_max, 'Unit': '[N.m]', 'Comment': 'Transient torque possible for climbing'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'R_mot', 'Value': Rmot, 'Unit': '[Ohm]', 'Comment': 'Resistance'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'M_mot', 'Value': Mmot, 'Unit': '[kg]', 'Comment': 'Motor mass'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'K_mot', 'Value': Ktmot, 'Unit': '[N.m/A', 'Comment': 'Torque constant of the selected motor'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'T_mot_fr', 'Value': Tfmot, 'Unit': '[N.m]', 'Comment': 'Friction torque of the selected motor'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'I_mot_hov', 'Value': Imot_hover, 'Unit': '[A]', 'Comment': 'Motor current for hover'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'I_mot_to', 'Value': Imot_to, 'Unit': '[A]', 'Comment': 'Motor current for takeoff'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'U_mot_cl', 'Value': Umot_hover, 'Unit': '[V]', 'Comment': 'Motor voltage for climbing'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'U_mot_to', 'Value': Umot_to, 'Unit': '[V]', 'Comment': 'Motor voltage for takeoff'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'U_mot', 'Value': Umot_hover, 'Unit': '[V]', 'Comment': 'Nominal voltage '}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'P_el_mot_to', 'Value': P_el_to, 'Unit': '[W]', 'Comment': 'Motor electrical power for takeoff'}])[col_names]
    df = df.append([{'Type': 'Motor', 'Name': 'P_el_mot_hov', 'Value': P_el_hover, 'Unit': '[W]', 'Comment': 'Motor electrical power for hover'}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 'M_bat_ref', 'Value': Mbat_ref, 'Unit': '[kg]', 'Comment': 'Mass of the reference battery '}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 'M_esc_ref', 'Value': Mesc_ref, 'Unit': '[kg]', 'Comment': 'Reference ESC mass '}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 'P_esc_ref', 'Value': Pesc_ref, 'Unit': '[W]', 'Comment': 'Reference ESC power '}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 'U_bat', 'Value': (Ncel*Ubat), 'Unit': '[V]', 'Comment': 'Battery voltage '}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 'M_bat', 'Value': Mbat, 'Unit': '[kg]', 'Comment': 'Battery mass '}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 'C_bat', 'Value': NcelPar*Cbat, 'Unit': '[A.s]', 'Comment': 'Battery capacity '}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 'I_bat', 'Value': I_bat, 'Unit': '[A]', 'Comment': 'Battery current '}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 't_hf', 'Value': t_hf, 'Unit': '[min]', 'Comment': 'Hovering time '}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 'P_esc', 'Value': P_esc, 'Unit': '[W]', 'Comment': 'Power electronic power (corner power or apparent power) '}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 'M_esc', 'Value': Mesc, 'Unit': '[kg]', 'Comment': 'ESC mass '}])[col_names]
    df = df.append([{'Type': 'Battery & ESC', 'Name': 'V_esc', 'Value': Vesc, 'Unit': '[V]', 'Comment': 'ESC voltage '}])[col_names]
    df = df.append([{'Type': 'Frame', 'Name': 'N_arm', 'Value': (Narm), 'Unit': '[-]', 'Comment': 'Number of arms '}])[col_names]
    df = df.append([{'Type': 'Frame', 'Name': 'N_pro_arm', 'Value': (Np_arm), 'Unit': '[-]', 'Comment': 'Number of propellers per arm '}])[col_names]
    df = df.append([{'Type': 'Frame', 'Name': 'sigma_max', 'Value': Sigma_max_ref, 'Unit': '[Pa]', 'Comment': 'Max admisible stress'}])[col_names]
    df = df.append([{'Type': 'Frame', 'Name': 'L_arm', 'Value': Lbra, 'Unit': '[m]', 'Comment': 'Length of the arm'}])[col_names]
    df = df.append([{'Type': 'Frame', 'Name': 'D_out', 'Value': Dout, 'Unit': '[m]', 'Comment': 'Outer diameter of the arm (tube)'}])[col_names]
    df = df.append([{'Type': 'Frame', 'Name': 'Marm', 'Value': Marm, 'Unit': '[kg]', 'Comment': '1 Arm mass'}])[col_names]
    df = df.append([{'Type': 'Frame', 'Name': 'M_frame', 'Value': Mfra, 'Unit': '[kg]', 'Comment': 'Frame mass'}])[col_names]
    df = df.append([{'Type': 'Specifications', 'Name': 'M_load', 'Value': (M_load), 'Unit': '[kg]', 'Comment': 'Payload mass'}])[col_names]
    df = df.append([{'Type': 'Specifications', 'Name': 't_hf', 'Value': (t_hf), 'Unit': '[min]', 'Comment': 'Hovering time '}])[col_names]
    df = df.append([{'Type': 'Specifications', 'Name': 'k_maxthrust', 'Value': (k_maxthrust), 'Unit': '[-]', 'Comment': 'Ratio max thrust'}])[col_names]
    df = df.append([{'Type': 'Specifications', 'Name': 'N_arm', 'Value': (Narm), 'Unit': '[-]', 'Comment': 'Number of arms '}])[col_names]
    df = df.append([{'Type': 'Specifications', 'Name': 'N_pro_arm', 'Value': (Np_arm), 'Unit': '[-]', 'Comment': 'Number of propellers per arm '}])[col_names]
    df = df.append([{'Type': 'Specifications', 'Name': 'CD', 'Value': C_D, 'Unit': '[-]', 'Comment': 'Drag coefficient'}])[col_names]
    df = df.append([{'Type': 'Objective', 'Name': 'Objective','Value': Mtotal,  'Unit': '[kg]', 'Comment': 'Total mass'}])[col_names]

    items = sorted(df['Type'].unique().tolist())+['Optimization']
    
    if (Tmot_max-Tmot_to)/Tmot_max<0:
        print('Insufficient motor torque. Choose a larger motor.')
    if (Ncel*Ubat-Umot_to)/Ubat<0 or (Ncel*Ubat-Vesc)/Ncel/Ubat<0 or  (Ncel*Ubat*Imax-Umot_to*Imot_to*Npro/0.95)/(Ncel*Ubat*I_bat)<0:
        print('Insufficient battery power. Choose a larger battery')
        
    return df

from IPython.display import display, clear_output
from ipywidgets import widgets
button = widgets.Button(description="Calculate")
display(button)

output = widgets.Output()

@output.capture()
def on_button_clicked(b):
    parameters=np.array((
        Kt_DC.value,
        Tmot_DC.value,
        Dia_DC.value*0.0254,
        Pitch_DC.value,
        Cbat_DC.value/1000*3600,#[As] Capacity battery As
        Ncel_slider_DC.value,
        NcelPar_slider_DC.value,
        Ubat_DC.value,
        Pesc_DC.value,

        Vesc_DC.value,
        Narm_slider_DC.value,
        D_ratio_slider_DC.value,
        Np_arm_DC.value,
        Mod_DC.value,
        k_maxthrust_slider_DC.value,
        V_cl_slider_DC.value,
        Nred_slider_DC.value,
        M_pay_DC.value,

        #Ref. values:
        rho_air_tex.value,
        NDmax_tex.value,
        C_D_tex.value,
        Dpro_ref_tex.value,
        Mpro_ref_tex.value,
        Tmot_ref_tex.value,
        Rmot_ref_tex.value,
        Mmot_ref_tex.value,
        Ktmot_ref_tex.value,
        Tfmot_ref_tex.value,
        Mbat_ref_tex.value,
        Cbat_ref_tex.value,
        Vbat_ref_tex.value,
        Imax_ref_tex.value,
        Pesc_ref_tex.value,
        Vesc_ref_tex.value,
        Mesc_ref_tex.value,
        Mfra_ref_tex.value,
        Marm_ref_tex.value,
        Sigma_max_ref_tex.value,
        ))
    clear_output()
    print("-----------------------------------------------")
    print("Final characteristics after calculation :")

    data=Calculator(parameters)

    pd.options.display.float_format = '{:,.3f}'.format

    def view(x=''):
        display(data[data['Type']==x])

    items = sorted(data['Type'].unique().tolist())

    w = widgets.Select(options=items)

    return display(interactive(view, x=w))
#     display(data)
button.on_click(on_button_clicked)
display(output)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.17654363391370975, 'fraction_numerical': 0.015429733942772597, 'mean_word_length': 4.07372654155496, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '427420', 'license': 'Apache-2.0', 'n_tokens_mistral': 14669, 'n_tokens_neox': 14179, 'n_words': 2498, 'path': 'notebooks/12-Multicopter_Validator_eCalc.ipynb', 'repo_name': 'aitorochotorena/multirotor-all', 'size': '37849'}