-
Notifications
You must be signed in to change notification settings - Fork 0
Referências da API
- ComponentDesign
- Dynamic
- Static
- Loads
- Stress
- Units
O modulo gears é resposavel por...
SpurAGMA(self,F,P_t,N_p,N_g,
poisson_p,poisson_g,E_p,E_g,
Q_v, n_p, n_g, N_cyc,
H_Bp,H_Bg,
N_c=9999,r_c=None,a_0 = 1.25,b_0=1,rho_a0=0.25,x_0 = 0,
phi_n=20,psi=0,
delta_s_n=0.024,x=0,
load = "tip", orientation = 'external',
coroamento = False, detrimento_superficie = False,
engrenamento = 'aberto',montagem_ajustada=False,tratamento = 'None',
fonte_potencia = 'uniforme', choque_maquina = 'uniforme',
trust = 99.99, temperatura = 20):
Modela engrenagens cilíndricas de dentes retos e helicoidais conforme metodologia da AGMA.
-
Parameters
- F : float Largura de face em mm.
- P_t : float Passo transversal em mm.
- N_p : int N° de dentes do Pinhão.
- N_g : int N° de dentes da Coroa.
- poisson_p : float Coeficiente de Poisson do Material do Pinhão.
- poisson_g : float Coeficiente de Poisson do Material da Coroa.
- E_p : float Módulo de Young em GPa do Material do Pinhão.
- E_g : float Módulo de Young em GPa do Material da Coroa.
- Q_v : float Número de qualidade.
- n_p : TYPE DESCRIPTION.
- n_g : TYPE DESCRIPTION.
- N_cyc : int Número de ciclos para vida em fadiga.
- H_Bp : float Dureza Brinnel do pinhão.
- H_Bg : float Dureza Brinnel da Coroa.
- N_c : int, optional Número de dentes da cremalheira de fabricação. The default is 9999.
- r_c : float, optional Raio nominal da cremalheria de fabricação. The default is None.
- a_0 : float, optional Adendo admensional da cremalheira de fabricação. The default is 1.25.
- b_0 : float, optional Dedendo adimensional da cremalheira de fabricação. The default is 1.
- rho_a0 : TYPE, optional Raio de adoçamento da cremalheira de fabricação. The default is 0.25.
- x_0 :float, optional Folga adimensional de "backlash" da cremalheira de fabricação. The default is 0.
- phi_n : float, optional Angulo de pressão em deg. The default is 20.
- psi : float, optional Angulo de hélice em deg. The default is 0.
- delta_s_n : float, optional Parametro de modificação do dente. The default is 0.024.
- x : float, optional Modificador de adendo do dente. The default is 0.
- load : str, optional
- Ponto de carregamento do dente: 'tip' para ponta ou 'HPSTC' para o ponto mais alto de contato em um único dente. The default is "tip".
- orientation : str, optional Tipo de engrenagem. 'internal' para internas e 'external' para externas. The default is 'external'.
- coroamento : bol, optional Define se há uso de coroamento nos dentes. The default is False.
- detrimento_superficie : bol, optional Define se há presenseça de detrimento superfiical. The default is False.
- engrenamento : str, optional Define o tipo de engrenamento. -1 ou 'aberto': engranamento aberto; -2 ou 'fecahdo comercial': Unidades fechadas comerciais; -3 ou 'fechado preciso': Unidades fechadas de precisão; -4 ou 'fechado extra-preciso': Unidades fechadas extra-precisas. O padrão é 'aberto'.
- montagem_ajustada: bool, optional Define o tipo de mntagem. O padrão é Falso.
- tratamento : str, optional Define o tipo de tratamento superficial. The default is 'None'.
- fonte_potencia : str, optional Define o nível de choque esperado na fonte. The default is 'uniforme'.
- choque_maquina : str, optional Define o nível de choque esperado na máquina. The default is 'uniforme'.
- trust : float, optional Define o nível de confialbilidade adotado. The default is 99.99.
- temperatura : float, optional Temperatura de operação em °C. The default is 20.
Metodo SpurAGMA.bending_stress_g
SpurAGMA.bending_stress_g(self,W_t):
Tensão de flexão na coroa
-
Parameters
----------
- W_t : float Carga transversal em N.
-
Returns
-------
- sigma : float Tensão em Pa.
Metodo SpurAGMA.bending_stress_p
SpurAGMA.bending_stress_p(self,W_t)
Tensão de flexão no pinhão
-
Parameters
- W_t : float Carga transversal em N.
-
Returns
- sigma : float Tensão em Pa.
Metodo SpurAGMA.contact_stress_p
SpurAGMA.contact_stress_p(self,W_t):
Tensão de contato no pinhão
-
Parameters
- W_t : float Carga transversal em N.
-
Returns -------
- sigma : float Tensão em Pa.
Metodo SpurAGMA.max_bending_g
SpurAGMA.max_bending_g(self,S_t,S_F):
Máxima tensão de flexão na coroa
-
Parameters ----------
- S_t : float Limite de resistência à flexão.
- S_F :float Fator de segurança.
-
** Returns** -------
-
- max_sigma : float Tensão em Pa.
-
Metodo SpurAGMA.max_bending_p
SpurAGMA.max_bending_p(self,S_t,S_F):
Máxima tensão de flexão admissível no pinhão
-
Parameters
- S_t : float Limite de resistência à flexão.
- S_F : float Fator de segurança.
-
Returns -------
- max_sigma : float Tensão em Pa.
Metodo SpurAGMA.max_contact_g
SpurAGMA.max_contact_g(self,S_c,S_F):
Máxima tensão de contato admissível na coroa
-
Parameters ----------
- S_t : float Limite de resistência ao contato.
- S_F : float Fator de segurança.
-
Returns -------
- max_sigma : float Tensão em Pa.
Metodo SpurAGMA.max_contact_p
SpurAGMA.max_contact_p(self,S_c,S_F):
Máxima tensão de contato admissível no pinhão
-
Parameters ----------
- S_t : float Limite de resistência ao contato.
- S_F :float Fator de segurança.
-
Returns -------
- max_sigma : float Tensão em Pa.
Método SpurAGMA.safety_bending_p
safety_bending_p(self,S_t,W_t)
Fator de segurança contra flexão do pinhão.
-
Parameters
- S_t : Float Tensão máxima de flexão admissível em MPa.
- W_t : float Carga transversal no dente em N.
-
Returns -------
- S_F : float Fator de Segurança a Flexão do Pinhão.
Método SpurAGMA.safety_contact_p
safety_contact_p(self,S_c,W_t)
Fator de segurança contra flexão do pinhão.
-
Parameters
* **S_c** : Float Tensão máxima de contato admissível em MPa. * **W_t** : float Carga transversal no dente em N. * **Returns** ------- S_F : float Fator de Segurança ao Contato do Pinhão.
def report_agma(self,precision=2,latex=False):
def report_stress(self,S_t,S_c,W_t,precision=2,latex=False): """
Parameters
----------
S_t : TYPE
DESCRIPTION.
S_c : TYPE
DESCRIPTION.
W_t : TYPE
DESCRIPTION.
precision : TYPE, optional
DESCRIPTION. The default is 2.
latex : TYPE, optional
DESCRIPTION. The default is False.
Returns
-------
params_dt: DataFrame or String
Dataframe com os dados das tensões.
def report_dims(self,precision=2,latex=False):
class WormAGMA():
def init(self, nw:float, dw:float, dc:float, Nw:int, Nc:int, px:float, lambd:float, casting_method:str = 'molde', **threadkwargs):
"""
Define os parâmetros de projeto para dimensionamento de pinhões
sem-fim de acorod com a metodologia da AGMA.
Parameters
----------
nw : float
Rotação do pinhão sem-fim em RPM.
dw : float
Diametro nominal do pinhão sem-fim em mm.
dc : float
Diametro nominal da coroa sem-fim em mm.
Nw : int
N° de dentes do pinhão sem-fim em mm.
Nc : int
N° de dentes da coroa sem-fim em mm.
px: float
passo axial do pinhão em mm
lambd : float
Ângulo de avanço em deg.
C : float
Distância entre centros em mm.
casting_method : str
Tipo de fundição utilizado no pinhão.
Opções: molde; resfriamento; centrifugo. O padrão é 'molde'
**threadkwargs: kwargs
Dados de adendo (kw: a) e dedendo (kw: b) e folga (kw: c) do
dente do pinhão. Somente nescessário se px < 4.06 mm. Por
padrão adota os valores padronizados para um angulo de pressão
de 20° de filente único.
Returns
-------
None.
def Wadm(self,E=303,unit='N',FS=1.5): """ Calcula a força tangencial admissível no dente da coroa (componente mais crítico) a partir do método AGMA, corrigido pela razão entre os módulo de elasticidade do material adotado e a liga de bronze adotada pela AGMA para o dimensionamento de ssitemas de engrenamento sem-fim.
Parameters
----------
E : float
Módulo de Young do material em MPa. O padrão é 303, idêntico à liga
de aluínio-bronze considerada para os cálculos padrões da AGMA.
unit : str, optional
Define a unidade desejada da força no output. The default is 'N'.
FS : float, optional
Fator de segurança para contabilizar parâmetros não previstos nos
efeitos da mudança de material. The default is 1.5.
Returns
-------
float
Força tangecial admissível na unidade específicada.
def get_params(self): """ Gera dicionário com os parâmetros de correção do método AGMA.
Returns
-------
params_dict : dict
Dicionário com os parâmetros de correção do método AGMA.
"""
params_dict = {'C_s':self.Cs,
'C_m':self.Cm,
'C_v':self.Cv,
'Vs':self.Vs
}
return params_dict
def get_dims(self): """ Gera dicionário com os parâmetros dimensionais do engrenamento
Returns
-------
params_dict : dict
Dicionário com os parâmetros dimensionais do engrenamento.
"""
params_dict = {'a':self.a,
'b':self.b,
'c':self.c,
'lambda':self.lambd,
'Pn':self.Pn,
'Pt':self.Pt}
return params_dict
O modulo Screws é responsavel por...
class PowerScrew():
def init(self, thread, F, p, nt, dm, f, dc = 0, fc = 0 ): """ Parameters ---------- thread : TYPE DESCRIPTION. F : int, float Carga externa. dm : int, float Diametro médio da rosca. p : int, float passo axial. nt: int. Número de filetes de rosca engajados. f : int, float coeficiente de atrito.
"""
def nofriction(self): """ Calcula o torque sem fricção no parafuso.
Returns
-------
float
Torque sem atrito do parafuso.
"""
return (self.F*self.l)/(2*np.pi)
def raise_torque(self): """ Calcula o torque para levantar uma carga externa
Returns
-------
Tr : float
Torque para levantar a carga.
"""
Tr = ((self.F*self.dm)/2)*((self.l+self.dm*np.pi*self.f/np.cos(self.alpha))/(np.pi*self.dm-self.f*self.l/np.cos(self.alpha))) + (self.F*self.fc*self.dc)/2 #Nm, Torque para subir o parafuso (descer a prensa)
return Tr
def raise_efficiency(self):
T = self.raise_torque()
T0 = self.nofriction()
return T0/T
def lower_torque(self): """ Calcula o torque para abaixar uma carga externa
-------
Tl : float
Torque para descer a carga.
"""
Tl = ((self.F*self.dm)/2)*((self.dm*np.pi*self.f/np.cos(self.alpha)-self.l)/(np.pi*self.dm+self.f*self.l/np.cos(self.alpha))) + (self.F*self.fc*self.dc)/2 #Nm, Torque para subir o parafuso (descer a prensa)
return Tl
def lower_efficiency(self):
T = self.lower_torque()
T0 = self.nofriction()
return T0/T
def stress_tensor(self, raise_load = True, wheight_threads = False): """
Parameters
----------
raise_load : bool, optional
Quandro True, inidca que o torque analisado é de subir a carga. The default is True.
wheight_threads : bol, optional
Quando True, indica que o partilhamento de cargas não é igual, de modo que a força no pimeiro
filete é 0,38*F. The default is False.
Returns
-------
S : numpy array
Tensor de tensões na raiz do parafuso.
"""
if wheight_threads is True:
F = 0.38*self.F
nt = 1
else:
F = self.F
nt = self.nt
alpha = self.alpha
dr = self.dr
p = self.p
t = p/2 * (1+np.tan(alpha))
if raise_load is True:
T = self.raise_torque()
else:
T = self.lower_torque()
sig_xx = (3*F)/(np.pi*dr*t*nt)
sig_yy = (4*F)/(np.pi*dr**2)
sig_zz = 0
tau_xy = 0
tau_xz = 0
tau_yz = (16*T)/(np.pi*dr**3)
S = np.array([[sig_xx,tau_xy,tau_xz],
[tau_xy,sig_yy,tau_yz],
[tau_xz,tau_yz,sig_zz]]
)
return S
O modulo Shafts é responsavel por...
def pitch_min_d(theta_max,L,E,F_H=[(0,0)],F_V=[(0,0)],M_H=[(0,0)],M_V=[(0,0)],FS=1,placement=1): """
Parameters
----------
theta_max : Float
Máxima inclinação em radianos.
L : FLoat
Distância entre mancais em mm.
E : Float
Módulo de elasticidade em GPa.
F_H : List of tuples, optional
Em cada item, a primeira entrada é Força horizontal em N e a segunda é a
Distância entre Força e Mancal Esquerdo. The default is [(0,0)].
F_V : List of tuples, optional
Em cada item, a primeira entrada é Força verrtical em N e a segunda é a
Distância entre Força e Mancal Esquerdo. The default is [(0,0)].
M_H : List of tuples, optional
Em cada item, a primeira entrada o Momento horizontal em Nm e a segunda é a
Distância entre o momento e Mancal Esquerdo. The default is [(0,0)].
M_V : List of tuples, optional
Em cada item, a primeira entrada é o Momento vertical em Nm e a segunda é a
Distância entre o momento e Mancal Esquerdo. The default is [(0,0)].
FS : float, optional
Fator de segurança. The default is 1.
placement : int, optional
Configuração das Cargas e Mancais
-1: Cargas Centralizadas entre Mancais, inclui momentos centralizados
-2: Cargas Sobressaltantes, a frente do mancal direito
-0: Definido em cada carga, deve-se adiconar à F_V e F_H
uma terceira entrada equivalente à configuração.
Ex: F_V = [(100,0.5,1),(200,1,2)]. The default is 1.
Returns
-------
d_l : Float
Diametro esquerdo em mm.
d_r : Float
Diametro direito em mm.
"""
E = E*1e9 #Converte GPa em Pa
def ab(array,plc=placement): if plc == 1: a_list = np.array([item[1] for item in array]) b_list = np.array([L-a for a in a_list])
a_list = a_list*1e-3
b_list = b_list*1e-3
return a_list,b_list
elif plc == 2:
a_list = np.array([item[1]-L for item in array])
b_list = np.array([0 for a in a_list])
a_list = a_list*1e-3
b_list = b_list*1e-3
return a_list,b_list
elif plc == 0:
a_list = []
b_list = []
for item in array:
if array != [(0,0)]:
x = item[1]
plc = item[2]
if plc == 1:
a_list.append(x)
b_list.append(L-x)
elif plc == 2:
a_list.append(x-L)
b_list.append(0)
else:
a_list.append(0)
b_list.append(0)
a_list = np.array(a_list)
b_list = np.array(b_list)
a_list = a_list*1e-3
b_list = b_list*1e-3
return a_list,b_list
F_H_list = np.array([F[0] for F in F_H])
a_FH, b_FH = ab(F_H)
F_V_list = np.array([F[0] for F in F_V])
a_FV,b_FV = ab(F_V)
M_H_list = np.array([M[0] for M in M_H])
a_MH,b_MH = ab(M_H)
M_V_list = np.array([M[0] for M in M_V])
a_MV,b_MV = ab(M_V)
H_sum_l = 0
V_sum_l = 0
H_sum_r = 0
V_sum_r = 0
#Somatorio de Forças em H
L = L*1e-3 #Converte mm em m
for i,(F,b,a) in enumerate(zip(F_H_list,b_FH,a_FH)):
if placement == 0:
plc = F_H[i][2]
else:
plc = placement
if plc == 1:
H_sum_l += F*b*(b**2-L**2)
H_sum_r += F*a*(L**2-a**2)
elif plc == 2:
H_sum_l += F*a*L**2
H_sum_r += F*a*3*L**2
#Acréscimo dos Momentos
H_sum_l += np.sum(M_H_list*(3*a_MH**2-6*a_MH*L+2*L**2))
H_sum_r += np.sum(M_H_list*(3*a_MH**2-L**2))
#Somatorio de Forças em V
for i,(F,b,a) in enumerate(zip(F_V_list,b_FV,a_FV)):
if placement == 0:
plc = F_V[i][2]
else:
plc = placement
if plc == 1:
V_sum_l += F*b*(b**2-L**2)
V_sum_r += F*a*(L**2-a**2)
elif plc == 2:
V_sum_l += F*a*L**2
V_sum_r += F*a*3*L**2
#Acréscimo dos Momentos
V_sum_l += np.sum(M_V_list*(3*a_MV**2-6*a_MV*L+2*L**2))
V_sum_r += np.sum(M_V_list*(3*a_MV**2-L**2))
d_l = 1e3*(((32*FS)/
(3*np.pi*E*L*theta_max)
)*np.sqrt(H_sum_l**2+V_sum_l**2)
)**0.25
d_r = 1e3*(((32*FS)/
(3*np.pi*E*L*theta_max)
)*np.sqrt(H_sum_r**2+V_sum_r**2)
)**0.25
return d_l,d_r
def tensao_cisalhante(K_fs,T_a,T_m,d): #Shigley Ch. 7-4 eq. 7-4 tau_a = K_fs * (16T_a)/(np.pid3) tau_m = K_fs * (16T_m)/(np.pid3) return tau_a,tau_m def tensao_normal(K_f,M_a,M_m,d): #Shigley Ch. 7-4 eq. 7-3 sigma_a = K_f * (32M_a)/(np.pid3) sigma_m = K_f * (32M_m)/(np.pid3) return sigma_a,sigma_m def tensao_vm(K_f,K_fs,M_a,M_m,T_a,T_m,d,full_output = True): #Shigley Ch. 7-4 eq. 7-5, 7-6 tau_a,tau_m = tensao_cisalhante(K_fs,T_a,T_m,d) sig_a,sig_m = tensao_normal(K_f,M_a,M_m,d)
sig_VMa = (sig_a**2+3*tau_a**2)**0.5
sig_VMm = (sig_m**2+3*tau_m**2)**0.5
if full_output == True:
tension_state_a = [sig_a,tau_a]
tension_state_m = [sig_m,tau_m]
return sig_VMa,sig_VMm,tension_state_a,tension_state_m
else:
return sig_VMa,sig_VMm
def fatigue_nf(K_f,K_fs,T_a,T_m,M_a,M_m,d,S_y,S_ut,S_e,criteria = 'gerber',full_output = True): #Shigley Ch. 7-4 eq. 7-7 a 7-13
if full_output == True:
sig_a,sig_m,tension_state_a,tension_state_m = tensao_vm(K_f,K_fs,M_a,M_m,T_a,T_m,d,full_output=True)
else:
sig_a,sig_m,tension_state_a,tension_state_m = tensao_vm(K_f,K_fs,M_a,M_m,T_a,T_m,d,full_output=True)
crit_dic = {"goodman" : fatigue.goodman_mod(S_ut = S_ut, S_e = S_e, mode ='n', sig_a = sig_a, sig_m = sig_m),
"gerber" : fatigue.gerber(sig_a = sig_a, sig_m = sig_m, S_e = S_e, S_ut = S_ut),
"asme" : fatigue.ASME(sig_a = sig_a, sig_m = sig_m, S_e = S_e, S_y = S_y),
"soderberg" : fatigue.soderberg(S_y = S_y,S_e = S_e, mode='n', sig_a = sig_a, sig_m = sig_m)}
sig_max = np.sqrt((tension_state_a[0]+tension_state_m[0])**2+3*(tension_state_a[1]+tension_state_m[1])**2)
n_y = S_y/sig_max #Shigley Ch. 7-4 eq. 7-16
if full_output == True:
return {"n_f":crit_dic.get(criteria.lower()),'n_yeld' : n_y,
'sig_vm_a' : sig_a, 'sig_vm_m' : sig_m, 'sig_vm_max' : sig_max,
'sig_a, tau_a' : tension_state_a, 'sig_m, tau_m' : tension_state_m}
else:
return crit_dic.get(criteria.lower()),n_y
def fatigue_d(K_f,K_fs,T_a,T_m,M_a,M_m,n,S_y,S_ut,S_e,criteria = 'gerber',full_output = True):
crit_dic = {"goodman" : ((16*n/np.pi)*((1/S_e)*((4*(K_f*M_a)**2+3*(K_fs*T_a)**2))**0.5
+(1/S_ut)*(4*(K_f*M_m)**2+3*(K_f*T_m)**2)**0.5))**(1/3),
"gerber" : (((8*n*np.sqrt(4*(K_f*M_a)**2+3*(K_fs*T_a)**2))/(np.pi*S_e))*
( 1 + (1+((2*np.sqrt(4*(K_f*M_m)**2+3*(K_fs*T_m)**2)*S_e)/
(np.sqrt(4*(K_f*M_a)**2+3*(K_fs*T_a)**2)*S_ut)
)**2
)**0.5
)
)**(1/3),
"asme" : ((16*n/np.pi)*(4*(K_f*M_a/S_e)**2+3*(K_fs*T_a/S_e)**2
+4*(K_f*M_m/S_y)**2+3*(K_fs*T_m/S_y)**2)**0.5
)**(1/3),
"soderberg" : ((16*n/np.pi)*((1/S_e)*(4*(K_f*M_a)**2+3*(K_fs*T_a)**2)**0.5
+(1/S_y)*(4*(K_f*M_m)**2+3*(K_fs*T_m)**2)**0.5)
)**(1/3)
}
return crit_dic.get(criteria.lower())
class Fatigue():
def init(self): return def resitencia_fadiga(Sut, Se_cfg, Load, SecType, SecDim, Finish, Trust, Temp=20, Other=1, print_tables = True, full_output = False ): """
Parameters
----------
Sut : float
Limite de resitência à tração em MPa.
Se_cfg : float ou string
Configura o valor de Se'. Caso um float seja entrado, representa
o valor de Se' em MPa. Caso seja uma string, representa o material
utilizado para cálculo de Se' a partir de Sut. Se a string for 'aço',
utiliza-se os valores para o aço. Caso contrário, assume-se alumínio
Load : str ou int
Tipo de carregamento sofrido pelo componente. opções:
-0/'flexao': cargas flexionais
-1/'axial': cargas axiais
-3/'torção': cargas torcionais
-4/'misto': comninação de cargas
SecType : str ou int
Formato da seção transversal. opções:
-0/'retangular'
-1/'circular': Seção circular sem rotação
-2/'circular rodando': seção circualr em rotação
SecDim : tuple
Dimensões da seção. Para retangulos: (a,b) com "a" largura e "b' a
largura. Para circulos (d) com "d" o diâmetro em mm.
Finish : str ou int
Acabamento superficial. opções:
-0/'retificado'
-1/'usinado'/'estirado a frio'
-2/'laminado a quente'
-3/'forjado'
Trust : float
Confiabilidade. selecionar entre 99.9999, 99.999, 99.99, 99.9, 99,
95, 90'.
Temp : float, optional
Temperatura de operação. The default is 20.
Other : float, optional
Fatores diversos. The default is 1.
print_tables : bool, optional
Imprime as tabelas contendo os valores dos modificadores. The default is True.
full_output : bool, optional
Retorna um dicionário com Se e os fatores de correção obtidos.
The default is False.
Returns
-------
Se: float
Limie de resitência à fadiga corrigido.
Se_dict: dict, optional (full_output = True)
Dicionário contendo o valor de Se, Se' e dos fatores de correção
"""
Sut = Sut*1e6
Load = str(Load)
SecDim = tuple(map(lambda x: 1e-3*x,SecDim))
if Se_cfg == "aço":
if Sut < 1400*10**6:
Se_line = 0.504*Sut
else:
Se_line = 700*1e6
elif type(Se_cfg) is int or float:
Se_line = Se_cfg*1e6
else: #Assume-se alumínio
if Sut < 400*1e6:
Se_line = 0.4*Sut
else:
Se_line = 160*1e6
#C_Load (k_c)
if Load.lower() in [0,'flexão','flexao',4,'misto']:
Cload = 1
elif Load.lower() in [1,'axial']:
Cload = 0.85
elif Load.lower() in (2,'torção','torçao','torcao','torcão'):
Cload = 0.59
#C_size (k_b)
if Load.lower() in [1,'axial']:
Csize = 1
else:
if SecType in [0,'retangular']:
A95 = 0.05*SecDim[0]*SecDim[1]
d = np.sqrt(A95/0.0766)
elif SecType in [1,'circular']:
A95 = 0.01046*(SecDim[0])**2
d = np.sqrt(A95/0.0766)
elif SecType in [2,'circular rodando','circular girando','eixo']:
d = SecDim[0]
if d < 2.79e-3 or d>254e-3:
Csize = 1
elif d<51e-3:
Csize = 1.243*(d*10**3)**(-0.107)
else:
Csize = 1.51*(d*10**3)**(-0.157)
#C_surface (k_a)
if Finish in [0,'retificado']:
a=1.58
b= -0.085
elif Finish in [1,'usinado','estirado a frio']:
a=4.51
b= -0.265
elif Finish in [2,'laminado a quente']:
a=57.7
b= -0.718
elif Finish == [3,'forjado']:
a=272
b= -0.995
Csurface = a*(Sut*1e-6)**(b)
#C_trust (k_e)
if Trust == 99.9999:
Ctrust = 0.620
elif Trust == 99.999:
Ctrust = 0.659
elif Trust == 99.99:
Ctrust = 0.702
elif Trust == 99.9:
Ctrust = 0.753
elif Trust == 99:
Ctrust = 0.814
elif Trust == 95:
Ctrust =0.868
elif Trust == 90:
Ctrust =0.897
else:
raise ValueError('Enter a valid trust value from 99.9999, 99.999, 99.99, 99.9, 99, 95, 90')
#C_temp(k_d)
T_F = 9*Temp/5+32 #temperatura em farenheit
if Temp == 20:
Ctemp=1
else:
Ctemp = 0.975+0.432e-3*T_F-0.115e-5*T_F**2+0.104e-8*T_F**3-0.595e-12*T_F**4
#C_other (k_f)
Cother = Other
#Cálculo do Limite de Resistência à Fadiga
S_e = Se_line*Cload*Csize*Csurface*Ctrust*Cother
if print_tables == True:
Cols = ['Fator de Correção','Valor','Variáveis','Valores']
InfoNames = ['Tipo de Carregamento',
'Diametro Efetivo',
'Acabamento',
'a',
'b',
'Nível de Confiabilidade',
'Temperatura [°F]',
'-']
InfoValues = [Load,
str('%.1f mm'%(d*10**3)),
Finish,
f"{a}",
f"{b}",
str('%s\%%'%(Trust)),
f'{T_F:.1f}',
"-"]
Cnames= ['$C_{carregamento} (k_c)$',
'$C_{tamanho} (k_b)$',
'$C_{superficie} (k_a)$',
'{}',
'{}',
'$C_{confiabilidade} (k_e)$',
'$C_{Temperatura} (k_d)$',
'$C_{outros} (k_f)$}']
Cvalues = [f'{Cload:.3f}',
f'{Csize:.3f}',
f'{Csurface:.3f}',
'{}',
'{}',
f'{Ctrust:.3f}',
f'{Ctemp:.3f}',
f'{Cother:.3f}']
print('Tabela de Fatores de Correção: \n\n')
pd.options.display.float_format = '{:.3f}'.format
Cdata = pd.DataFrame(data=np.transpose([Cnames,
Cvalues,
InfoNames,
InfoValues]),
columns=[Cols])
CdataLTX = Cdata.to_latex(index=False,decimal=',',escape=False,multicolumn=True)
#print(CdataLTX)
print(Cdata)
if full_output == True:
return {'S_e' : S_e*1e-6, 'Se_line' : Se_line*1e-6, 'd': d,
'C_load' : Cload, 'C_size' : Csize, 'C_surface' : Csurface, 'C_trust' : Ctrust, 'C_temp': Ctemp,'C_other' : Cother}
else:
return S_e*1e-6
def S_N(sigma,Sut,Type,Load,SecType,SecDim,Finish,Trust, print_tables = True,full_output = False,*args):
if Load=="flexão":
Sm = 0.9*Sut
else:
Sm = 0.75*Sut
Sf_dic = Fatigue.resitencia_fadiga(Sut, Type, Load, SecType, SecDim, Finish, Trust, print_tables = print_tables, full_output=True)
Se = Sf_dic['Se_line']
Sf = Sf_dic['S_e']
d = Sf_dic['d']
Cload = Sf_dic['C_load']
Csize = Sf_dic['C_size']
Csurface = Sf_dic['C_surface']
Ctrust = Sf_dic['C_trust']
b = (1/(-3))*np.log10(Sm/Sf)
a = 10**(np.log10(Sm)-3*b)
if print_tables == True:
StressDic ={}
Snames = ["$S_e'$",'$S_m$','$S_e$','$a$','$b$']
Svalues = ['%.2f'%(Se*10**(-6)),'%.2f'%(Sm*10**(-6)),'%.2f'%(Sf*10**(-6)),'%.2f'%((a*10**(-6))),'%.4f'%(b)]
Sunit = ['Mpa','Mpa','Mpa','Mpa','-']
print('Tabela de Tensões: \n\n')
StressDic['Grandeza']=Snames
StressDic['Valor']=Svalues
StressDic['Unidade']=Sunit
pd.options.display.float_format = '{:,.2f}'.format
Sdata = pd.DataFrame(StressDic)
SdataLTX = Sdata.to_latex(index=False,decimal=',',escape=False)
print(SdataLTX)
N = (sigma/a)**(1/b)
S_e = Sf
if full_output == True:
return { 'N' : N, 'a' :a, 'b' : b, 'S_e' : S_e,
'C_load' : Cload, 'C_size' : Csize, 'C_surface' : Csurface, 'C_trust' : Ctrust}
else:
return N
def goodman_mod(S_ut,S_e,mode,**kwargs): if mode == 'n': sig_a = kwargs['sig_a'] sig_m = kwargs['sig_m']
n = 1/(sig_a/S_e+sig_m/S_ut)
return n
if mode == 'sig_a':
n = kwargs['n']
sig_m = kwargs['sig_m']
sig_a = (1/n-sig_m/S_ut)*S_e
return sig_a
if mode == 'sig_m':
n = kwargs['n']
sig_a = kwargs['sig_a']
sig_m = (1/n-sig_a/S_e)*S_ut
return sig_m
def soderberg(S_y,S_e,mode,**kwargs,):
return Fatigue.goodman_mod(S_y,S_e,mode = mode,**kwargs) def gerber(sig_a,sig_m,S_e,S_ut):
return (1/2)((S_ut/sig_m)**2)(sig_a/S_e)( (-1 + np.sqrt(1+((2sig_mS_e)/(S_utsig_a))**2))) #sig_m>0 def ASME (sig_a,sig_m,S_e,S_y): return np.sqrt(1/((sig_a/S_e)**2+(sig_m/S_y)**2)) def first_cycle(sig_a,sig_m,S_y, mode = 'n'): if mode == 'n': n = S_y/(sig_a + sig_m)
return n
elif mode == 'sig_a':
sig_a = n/S_y -sig_m
return sig_a
elif mode == 'sig_m':
sig_m = n/S_y-sig_a
return sig_m
O modulo loads é responsavel por...
class Loads():
def init(self): pass class Load(): """
Parameters
----------
tag : str
Nome da variável da carga.
position : array_like.
Vetro posição em coordenadas cartesianas (x,y,z).
value : array-like ou str, optional
Vetor de intensidade da carga. Se `value` contiver uma string,
considera-se que a componente é uma variável desconhecida. se
for `None`, todas as componentes são consideradas variáveis.
The default is `None`.
Returns
-------
None.
"""
def init(self,tag, position, value=None, load_type = 'F'):
self.tag = tag
self.position = np.array(position)
self.load_type = load_type
self.isknown = ([True if type(f_i) != str
else False
for f_i in value
] if value != None
else (False,False,False)
)
if value == None:
self.value = np.ones(3)
else:
self.value = np.array([f_i if type(f_i) != str
else -1 if '-' in f_i
else 1
for f_i in value
]
)
self.value_x = self.value[0]
self.value_y = self.value[1]
self.value_z = self.value[2]
def set_a(self,a_list): """ Parameters ---------- a_list : list or tuple Lista contendo os coeficientes escalares a serem multiplicados pela magnitude de forma a gerar os momentos causados pela carga. M_x = a_list[0]*F, M_y = a_list[1]*F, M_z = a_list[2]*F.
Returns
-------
None.
"""
self.a_x = a_list[0]
self.a_y = a_list[1]
self.a_z = a_list[2]
def set_value(self,val_list): """
Parameters
----------
val_list : list or tuple
Lista contendo os valores de magnitude na forma ().
M_x = a_list[0]*F, M_y = a_list[1]*F, M_z = a_list[2]*F.
Returns
-------
None.
"""
self.isknown = ([True if type(f_i) != str
else False
for f_i in val_list
])
self.value = np.array([f_i if type(f_i) != str
else -1 if '-' in f_i
else 1
for f_i in val_list
]
)
self.value_x = val_list[0]
self.value_y = val_list[1]
self.value_z = val_list[2]
def get_values(self,axis=''): axis_dict = {'x':0, 'y':1, 'z':2 }
idx = []
for ax in axis:
if ax not in idx:
idx.append(axis_dict[ax])
values = [cp.copy(self.value[ax]) for ax in idx]
if len(values) == 1:
return values[0]
else:
return values
def get_pos(self,axis=''): axis_dict = {'x':0, 'y':1, 'z':2 }
idx = []
for ax in axis:
if ax not in idx:
idx.append(axis_dict[ax])
values = [cp.copy(self.position[ax]) for ax in idx]
if len(values) == 1:
return values[0]
else:
return values
def solve_reactions(loads:Load, load_init = None, coords='ijk', add_equations=[], print_matrix=False, update_loads=False, **kwargs): """ Parameters ---------- loads: Load Carga, conforme definida na classe Load coords : TYPE, optional Indica a orientação das coordenadas de origem através da notação de Einstein, de modo que Se
coords= ijk, temos, para a1 = 1e_x e a2 = 1e_y a1 x a2 = a1a2 e_z. Já para ikj têm-se a1 x a2 = -a1*a2 e_z O padrão é 'ijk'.
Returns
-------
Dicionário contendo as reações. Chaves são definidas pela tag de cada
objeto "Load" acrescidos de um sufixo "_x","_y","_z" a depender da
componente.
"""
F_loads = [load for load in loads if load.load_type.lower()=='f']
M_loads = [load for load in loads if load.load_type.lower()=='m']
#========================================================================
# MATRIZES DO SISTEMA
#========================================================================
F = [[],
[],
[]]
Vars = []
R = [[],
[],
[]]
M = [[],
[],
[]]
M_r = [[],
[],
[]]
#========================================================================
# OBTENÇÃO DAS DIREÇÕES E SENTIDOS DOS MOMENTOS
#========================================================================
for load in loads:
subs = (f'{coords[0]}{coords[1]}{coords[2]},{coords[1]},{coords[2]}->{coords[0]}'
)
levi_civita = np.array([[[int((i - j) * (j - k) * (k - i) / 2)
for k in range(3)
]
for j in range(3)
]
for i in range(3)
]
)
x = load.position
origin = np.ones(3)
i = np.array([1,0,0])
j = np.array([0,1,0])
k = np.array([0,0,1])
a_i = np.einsum(subs,levi_civita,x,i)
a_j = np.einsum(subs,levi_civita,x,j)
a_k = np.einsum(subs,levi_civita,x,k)
a_list = [a_i,
a_j,
a_k]
load.set_a(a_list)
tag_sufix = ['_x','_y','_z']
for n in range(3):
if load.load_type.lower() == 'f':
if load.isknown[n]:
for m in range(3):
if m==n:
F[m].append(load.value[n])
else:
F[m].append(0)
M[m].append(a_list[n][m]*load.value[n])
else:
for m in range(3):
if m==n:
Vars.append(load.tag+tag_sufix[n])
R[m].append(load.value[n])
else:
R[m].append(0)
M_r[m].append(a_list[n][m]*load.value[n])
if load.load_type.lower() == 'm':
if load.isknown[n]:
for m in range(3):
if m==n:
F[m].append(0)
M[m].append(load.value[n])
else:
F[m].append(0)
M[m].append(0)
else:
for m in range(3):
if m==n:
Vars.append(load.tag+tag_sufix[n])
R[m].append(0)
M_r[m].append(load.value[n])
else:
M_r[m].append(0)
R[m].append(0)
var_len = len(Vars)
#======================================================================
# MATRIZ DE FUNÇÕES
#======================================================================
#Checagem da dependencia linear
exp_matrix = [[] for n in range(6)]
for n in range(3):
exp_matrix[n] = [*R[n],sum(F[n])]
exp_matrix[n+3] = [*M_r[n],sum(M[n])]
exp_matrix = np.array(exp_matrix)
lin_dep = []
for n in range(6):
if all([exp_matrix[n,k]==0
for k in range(exp_matrix.shape[1])
]
):
lin_dep.append(n)
else:
for m in range(6):
if n != m:
inner_product = np.inner(exp_matrix[n,:],
exp_matrix[m,:]
)
norm_n = np.linalg.norm(exp_matrix[n,:])
norm_m = np.linalg.norm(exp_matrix[m,:])
if np.abs(np.abs(inner_product) - np.abs(norm_n * norm_m)) < 1E-4: #inequação de Cauchy
lin_dep.append(m)
R = [R[n]
for n in range(3)
if n not in lin_dep
]
F = [F[n]
for n in range(3)
if n not in lin_dep
]
M_r = [M_r[n]
for n in range(3)
if n+3 not in lin_dep
]
M = [M[n]
for n in range(3)
if n+3 not in lin_dep
]
def equations(R_0):
R_eval = np.matmul(np.array(R),R_0)
M_reval = np.matmul(np.array(M_r),R_0)
F_eq = [R_eval[n]+sum(F[n]) for n in range(len(R_eval))]
M_eq = [M_reval[n]+sum(M[n]) for n in range(len(M_reval))]
add_eval = [func(R_0) for func in add_equations]
eq_list = [*F_eq,
*M_eq]
if add_eval != []:
for eq_eval in add_eval:
eq_list.append(eq_eval)
return eq_list
R_0 = (np.ones(var_len)
if load_init == None
else load_init
)
if print_matrix:
precision = kwargs.pop('precision',2)
print(f"""
Matriz do sistema:
{bmatrix(np.array([*R,*M_r]), precision=precision) }{bmatrix(np.transpose([Vars]),precision=precision) } = {bmatrix(np.transpose(*np.sum(F,axis=1),*np.sum(M,axis=1)), precision=precision)}
""")
Roots = fsolve(equations,R_0)
root_dict = dict([(Vars[n],Roots[n])
for n in range(var_len)
]
)
if update_loads == True:
for root in list(root_dict.keys()):
axis = {'x':0,
'y':1,
'z':2}
tag,ax = root.split('_')
idx = axis[ax]
update_val = [0,0,0]
for load in loads:
if tag == load.tag:
for i in range(3):
if i==idx:
update_val[i] = root_dict[f'{tag}_{ax}']
else:
update_val[i] = load.value[i]
load.set_value(update_val)
return root_dict
def solve_internal(*loads:Load, axis='x', pos_shift = (0,0), l_divs=500, **graph_kwargs ): """
Parameters
----------
*loads : Load
Cargas externas.
axis : TYPE, optional
DESCRIPTION. The default is 'x'.
pos_shift : TYPE, optional
DESCRIPTION. The default is (0,0).
#axis : TYPE, optional
axis=x -> pos=(y,z), axis=y -> pos=(z,x), axis=z -> pos=(x,y). The default is (0,0).
axis : TYPE, optional
DESCRIPTION. The default is y -> pos=(z,x).
axis : TYPE, optional
DESCRIPTION. The default is z -> pos=(x,y) l_divs=500.
**graph_kwargs : keyword arguments
Argumentos adicionais para criação de gráficos e impressão de resultados.
-F_graphs: str
string contendo "x", "y" e/ou "z". Gráficos dos esforços internos serão plotados.
-M_graphs: str
string contendo "x", "y" e/ou "z". Gráficos dos momentos internos serão plotados.
-print_reactions: bool
Imprime no console as reações em cada ponto de aplicação das forças
-pckl: str
Salva os gráficos como arquivos editáveis. pckl deve conter o caminho com nome e
extensão do arquivo
Returns
-------
dict
Dicionário contendo as forças internas em cada seção.
dict
Dicionário contendo os momentos internos em cada seção
list
Lista de indices das repostas internas nos pontos de aplicação das forças
"""
axis_dict = {'x':0,
'y':1,
'z':2}
ax = axis_dict[axis]
n_load = len(loads)
sort_loads = sorted(loads,key = lambda load: load.position[ax])
l_section = [load.position[ax] for load in sort_loads]
l_range = []
for k in range(n_load):
if l_section[k] != l_section[-1]:
l_inner = np.linspace(l_section[k],
l_section[k+1],
l_divs
)
for l in l_inner:
l_range.append(l)
else:
l_range.append(l_section[k])
def remove_dups(List):
return list(map(float,
list(dict.fromkeys(map(str,
List)
)
)
)
)
l_range = np.array(remove_dups(l_range))
F_roots = {axis: [],
'R_x': [],
'R_y': [],
'R_z': []
}
M_roots = {axis: [],
'Mr_x': [],
'Mr_y': [],
'Mr_z': []
}
for k in range(len(l_range)):
pos = [0,0,0]
pos[ax] = l_range[k]
if ax == 0:
pos[1] = pos_shift[0]
pos[2] = pos_shift[1]
elif ax == 1:
pos[2] = pos_shift[0]
pos[0] = pos_shift[1]
else:
pos[0] = pos_shift[0]
pos[1] = pos_shift[1]
R_int = Loads.Load(f'R{k}',
position=pos)
M_int = Loads.Load(f'Mr{k}',
position=pos,
load_type='M')
load_list = [*[load
for load in loads
if load.position[ax] <= l_range[k]
],
R_int,
M_int
]
node_solution = Loads.solve_reactions(*load_list)
F_roots[axis].append(l_range[k])
F_roots['R_x'].append(node_solution[f'R{k}_x'])
F_roots['R_y'].append(node_solution[f'R{k}_y'])
F_roots['R_z'].append(node_solution[f'R{k}_z'])
M_roots[axis].append(l_range[k])
M_roots['Mr_x'].append(node_solution[f'Mr{k}_x'])
M_roots['Mr_y'].append(node_solution[f'Mr{k}_y'])
M_roots['Mr_z'].append(node_solution[f'Mr{k}_z'])
#==================================================================
# PLOTAGEM DE DIAGRAMAS
#==================================================================
F_graphs = graph_kwargs.pop('F_graphs','')
units = graph_kwargs.pop('units',{'distance':'m',
'force':'N',
'torque':'Nm'})
pckl_dict = graph_kwargs.pop('pckl',None)
if pckl_dict is not None:
pckl_title = pckl_dict['title']
pckl_path = pckl_dict['path']
pckl_tag = pckl_dict.pop('tag','')
F_idx = []
for graph_axis in ['x','y','z']:
graph_label = ('$N$'
if graph_axis == axis
else f'$V_{graph_axis}$'
)
x_label = f'{graph_axis} [{units["distance"]}]'
y_label = (f'N: Esforço normal [{units["force"]}]'
if graph_axis == axis
else f'$V_{graph_axis}$: Esforço Cortante em {graph_axis}'
)
l = np.array(F_roots[axis])
F = np.array(F_roots[f'R_{graph_axis}'])
l_ticks = l_section
f_indexes = np.where([l_value in l_ticks for l_value in l])[0]
f_ticks = [F[i] for i in f_indexes]
F_idx.append(f_indexes)
if graph_axis in F_graphs:
fig = plt.figure(figsize=(9,6))
plt.rc('font',**{'family':'serif','serif':['Times New Roman']})
ax = fig.gca()
ax.plot(l,F,'b-.',label=graph_label)
ax.legend([graph_label])
plt.fill_between(l,F,color='blue',**{'alpha':0.2})
ax.set_xlim(0,np.max(l)+0.005*np.max(l))
ax.set_xlabel(x_label)
ax.set_ylabel(y_label)
plt.xticks(l_ticks,[f'{tick:.2f}' for tick in l_ticks])
plt.yticks(f_ticks,[f'{tick:.2f}' for tick in f_ticks])
plt.grid()
if pckl_dict is None:
plt.show()
else:
pckl_file = f'{pckl_path}/{pckl_title}_{graph_label}_{pckl_tag}.txt'
with open(pckl_file,'wb') as file:
pc.dump(fig,file)
M_graphs = graph_kwargs.pop('M_graphs','')
M_idx = []
for graph_axis in ['x','y','z']:
graph_label = ('$T$'
if graph_axis == axis
else f'$Mf_{graph_axis}$'
)
x_label = f'{graph_axis} [{units["distance"]}]'
y_label = (f'T: Torque [{units["torque"]}]'
if graph_axis == axis
else f'$Mf_{graph_axis}$: Momento fletor em {graph_axis}'
)
l = np.array(M_roots[axis])
M = np.array(M_roots[f'Mr_{graph_axis}'])
l_ticks = l_section
m_indexes = np.where([l_value in l_ticks for l_value in l])[0]
m_ticks = [M[i] for i in m_indexes]
M_idx.append(m_indexes)
if graph_axis in M_graphs:
fig = plt.figure(figsize=(9,6))
plt.rc('font',**{'family':'serif','serif':['Times New Roman']})
ax = fig.gca()
ax.plot(l,M,'b-.',label=graph_label)
ax.legend([graph_label])
plt.fill_between(l,M,color='blue',**{'alpha':0.2})
ax.set_xlim(0,np.max(l)+0.005*np.max(l))
ax.set_xlabel(x_label)
ax.set_ylabel(y_label)
plt.xticks(l_ticks,[f'{tick:.2f}' for tick in l_ticks])
plt.yticks(m_ticks,[f'{tick:.2f}' for tick in m_ticks])
plt.grid()
if pckl_dict is None:
plt.show()
else:
pckl_file = f'{pckl_path}/{pckl_title}_{graph_label}_{pckl_tag}.txt'
with open(pckl_file,'wb') as file:
pc.dump(fig,file)
indexes = {'F_idx': list(map(int,F_idx[0])),
'M_idx': list(map(int,M_idx[0]))
}
print_reactions = graph_kwargs.pop('print_reactions',False)
if print_reactions == True:
print('\nEsforços Internos')
for R in ['R_x','R_y','R_z']:
if R.split('_')[1] in F_graphs:
print('\n')
for i in indexes['F_idx']:
x = F_roots[axis][i]
if i!=0:
print(f'{R}({axis}={x} "->") = {F_roots[R][i-1]:.3f} {units["force"]}')
print(f'{R}({axis}={x} "<-") = {F_roots[R][i]:.3f} {units["force"]}')
for Mr in ['Mr_x','Mr_y','Mr_z']:
if Mr.split('_')[1] in M_graphs:
print('\n')
for i in indexes['M_idx']:
x = M_roots[axis][i]
if i!=0:
print(f'{Mr}({axis}={x} "->") = {M_roots[Mr][i-1]:.3f} {units["torque"]}')
print(f'{Mr}({axis}={x} "<-") = {M_roots[Mr][i]:.3f} {units["torque"]}')
return F_roots,M_roots,indexes
O modulo Stress é responsável por...
class Stress():
def init(self): return class Section():
def init(self,section_type,*dims): self.type = section_type self.dims = list(dims)
def rectangle(b,h): return {'A': bh, 'I_x': (bh3)/12, 'I_y': (b3*h)/12, 'I_xy': 0 }
def circle(D): return {'A': np.piD**2/4, 'I_x': np.piD4/64, 'I_y': np.pi*D4/64, 'I_xy': 0, 'J': np.pi*D**4/32 }
def hollow_circle(D,d): return {'A': np.pi*(D2-d2)/4, 'I_x': np.pi*(D4-d4)/64, 'I_y': np.pi*(D4-d4)/64, 'I_xy': 0, 'J': np .pi*(D4-d4)/32 }
if len(dims) == 1:
self.dims.append(0)
self.property_dict = {'rectangle': rectangle(self.dims[0],self.dims[1]),
'circle': circle(self.dims[0]),
'hollow_circle': hollow_circle(self.dims[0],self.dims[1])
}
def properties(self): match_key = ('rectangle' if self.type in (1,'1','square','r','rectangle') else 'circle' if self.type in (2,'2','circle','round','r','c') else 'hollow_circle' if self.type in (3,'3','hollow_circle','hc') else 'circle' )
return self.property_dict[match_key]
def get_stress(section:Section, pos, normal='x', full_output = False, **loads): """
Parameters
----------
section : Section
DESCRIPTION.
pos : TYPE
DESCRIPTION.
normal : TYPE, optional
DESCRIPTION. The default is 'x'.
**loads : keyword arguments
Cargas internas na seção:
- N: Normal
- V_y: Cisalhante no sentido y
- V_z: Cisalhante no sentido z
- T: Torque normal
- Mf_y: Momento fletor no sentido y
- Mf_z: Momento fletor no sentido y
Returns
-------
S : TYPE
Tensor das tensões. Nunca considera tensões no plano yz, apenas xy e xz.
"""
axis_dict = {'x':0,
'y':1,
'z':2}
local_axis = {'x': {'x_0': 'x',
'y_0': 'y',
'z_0': 'z'},
'y': {'x_0': 'y',
'y_0': 'z',
'z_0': 'x'},
'z': {'x_0': 'z',
'y_0': 'y',
'z_0': 'x'},
}
pos_y = pos[0]
pos_z = pos[1]
x = axis_dict[local_axis[normal]['x_0']] #x indica a orientação *local*
y = axis_dict[local_axis[normal]['y_0']] #y indica a orientação *local*
z = axis_dict[local_axis[normal]['z_0']] #z indica a orientação *local*
sect_props = section.properties()
A = sect_props['A']
I_z = sect_props['I_x']
I_y = sect_props['I_y']
I_zy = sect_props['I_xy']
J = sect_props['J']
for key,val in loads.items():
if type(val) not in [tuple,list,np.array]:
loads[key] = [0,0,0]
if key in ['N','T']:
loads[key][x] = val
elif key in ['V_y','Mf_y']:
loads[key][y] = val
elif key in ['V_z','Mf_z']:
loads[key][z] = val
N = loads.pop('N',[0,0,0])
V_y = loads.pop('V_y',[0,0,0])
V_z = loads.pop('V_x',[0,0,0])
T = loads.pop('T',[0,0,0])
Mf_y = loads.pop('Mf_y',[0,0,0])
Mf_z = loads.pop('Mf_z',[0,0,0])
sig_tension = N[x]/A
sig_flex_y = -Mf_z[z]*pos_y/I_y
sig_flex_z = Mf_y[y]*pos_z/I_z
sig_xx = sig_tension + sig_flex_y + sig_flex_z
rho = np.sqrt(pos_z**2+pos_y**2)
theta = (np.arctan(pos_y/pos_z) if pos_z != 0
else 0 if pos_y == 0
else np.pi/2 if pos_y//pos_y == 1
else 3*np.pi/2
)
rho_dir = np.array((0,np.cos(theta),np.sin(theta)))
T_dir = np.zeros(3)
T_dir[x] = (T[x]//T[x] if T[x] != 0
else 1)
tau_dir = np.cross(T_dir,rho_dir)
tau_torsion = -T[x]*rho/J
tau_torsion_xy = tau_dir[y]*tau_torsion
tau_torsion_xz = tau_dir[z]*tau_torsion
if section.type in (2,'2','circle','round','c'):
R = section.dims[0]/2
tau_shear_xy = 4*(V_y[y]*(R**2-pos_y**2))/(3*np.pi*R**4)
tau_shear_xz = 4*(V_z[z]*(R**2-pos_z**2))/(3*np.pi*R**4)
elif section.type in (3,'3','hollow_circle','hc'):
R = section.dims[0]/2
tau_shear_xy = (2*V_y[y]/A if pos_y==0
else 0 if pos_y==R
else V_y[y]/A)
tau_shear_xz = (2*V_z[z]/A if pos_z==0
else 0 if pos_z==R
else V_z[z]/A)
else:
a,b = section.dims[0:2]
tau_shear_xy = V_y[y]/(2*I_y)*(b**2-pos_y**2)
tau_shear_xz = V_z[z]/(2*I_z)*(a**2-pos_z**2)
tau_xy = tau_torsion_xy+tau_shear_xy
tau_xz = tau_torsion_xz+tau_shear_xz
S = np.zeros((3,3))
S[x,x] = sig_xx
S[x,y] = tau_xy
S[y,x] = tau_xy
S[x,z] = tau_xz
S[z,x] = tau_xz
stress_dict = {'sig_normal': sig_xx,
'sig_flex': (sig_flex_y,sig_flex_z),
'tau_torsion': (tau_torsion_xy,tau_shear_xz),
'tau_shear': (tau_shear_xy,tau_shear_xz)
}
if full_output == True:
return S,stress_dict
else:
return S
def VonMisses(S):
sig_x = S[0,0]
sig_y = S[1,1]
sig_z = S[2,2]
tau_xy = S[0,1]
tau_xz = S[0,2]
tau_yz = S[1,2]
sig_vm = (1/np.sqrt(2))*np.sqrt((sig_x-sig_y)**2
+(sig_y-sig_z)**2
+(sig_z-sig_x)**2
+6*(tau_xy**2+tau_xz**2+tau_yz**2)
)
return sig_vm
def SI(value:float, input_unit:str, output_unit:str): """ Converte unidades do SI
Parameters
----------
value : float
Valor a ser convertido.
input_unit : str
Unidade da entrada. Ex: mm2, GPa, cm3.
output_unit : str
Unidade da saída.
Returns
-------
float
Valor convertido da unidade de entrada para a unidade de saída.
"""
if input_unit=='mm' or output_unit=='mm':
si_unit = 'm'
else:
si_unit=''
for char in input_unit:
if char in output_unit:
si_unit+=char
if input_unit != si_unit:
if 'mm' in input_unit:
input_split = input_unit.split('mm')
input_prefix = 'm'
input_power = (1 if input_split[1] == ''
else float(input_split[1])
)
else:
input_split = input_unit.split(si_unit)
if len(input_split) < 2:
input_prefix = input_split[0]
input_power = 1
else:
print(input_split)
input_prefix = input_split[0]
input_power = (1 if input_split[1] == ''
else float(input_split[1])
)
input_rate = prefix[input_prefix]**input_power
else:
input_rate = 1
if output_unit != si_unit:
if 'mm' in output_unit:
output_split = output_unit.split('mm')
output_prefix = 'm'
output_power = (1 if output_split[1] == ''
else float(output_split[1])
)
else:
output_split = output_unit.split(si_unit)
if len(output_split) < 2:
output_prefix = output_split[0]
output_power = 1
else:
output_prefix = output_split[0]
output_power = (1 if output_split[1] == ''
else float(output_split[1])
)
output_rate = prefix[output_prefix]**output_power
else:
output_rate = 1
rate = input_rate/output_rate
return rate*value
def rad_velocity(n:float,input_unit:str,output_unit:str): """ Converte velocidades radiais de RPM para rad/s e vice versa
Parameters
----------
n : float
velocidade radial.
input_unit : str
unidade de entrada, pode ser 'RPM' ou 'rad/s'.
output_unit : str
unidade de saída, pode ser 'RPM' ou 'rad/s'.
Returns
-------
float
velocidade radial convertida.
"""
if input_unit == output_unit:
return n
elif input_unit.lower() == "rpm" and output_unit=='rad/s':
omega = n*2*np.pi/60
elif input_unit == "rad/s" and output_unit.lower() == "rpm":
omega = 60*n/(2*np.pi)
return omega
def m2ft(x:float,metric_unit:str='m', imperial_unit:str='ft'): """ Converte comprimento métrico para pés.
Parameters
----------
x : float
valor a ser convertido.
metric_unit : str, optional
Unidade métrica adotada. permite utilizar valores diretamente em
unidades como mm, dm, km e outras. The default is 'm'.
Returns
-------
float
Valor convertido para unidade imperial especificada.
"""
x = SI(x,metric_unit,'m')
imp_rate = 3.28084/imperial[imperial_unit]
return x * imp_rate
def ft2m(x:float, metric_unit:str='m', imperial_unit:str='ft'): """ Converte pés para comprimento métrico.
Parameters
----------
x : float
valor a ser convertido.
metric_unit : str, optional
Unidade métrica adotada. permite utilizar valores diretamente em
unidades como mm, dm, km e outras. The default is 'm'.
Returns
-------
float
Valor convertido para unidade métrica específicada.
"""
imp_rate = 3.28084*imperial[imperial_unit]
m = x/imp_rate
return SI(m,'m',metric_unit)
def N2lbf(x:float, metric_unit:str='N'):
x = SI(x,metric_unit,'N')
imp_rate = 1/4.448
return x*imp_rate