Uma biblioteca para Python 2 e Python 3 para propagação de erro e conversão de unidades utilizando os métodos (um tanto insólitos) que os professores de lab de física do IFSC-USP insistem.
Desenvolvimento
Atualmente essa biblioteca não está mais em desenvolvimento pelos mantenedores do fork, brenopelegrin e viniciusdutra314. Se você quiser uma versão mais atualizada, dê uma olhada no projeto LabIFSC2 de viniciusdutra314.
Todavia, se você tiver alguma dúvida ou quiser reportar um problema, sinta-se livre para abrir uma issue. Ela será respondida assim que possível.
Features diferentes da biblioteca original
☑️ Adicionado suporte à arrays do numpy (numpy.ndarray) na função M(). Agora, quando é passado um numpy.ndarray para M(), ela retornará um numpy.ndarray tendo objetos LabIFSC.Medida.medida como seus elementos. As operações entre arrays do numpy que multiplicam elemento-elemento estão funcionando, pois as operações elemento-elemento são definidas na classe Medida.
☑️ Adicionado suporte à criação de tabelas
☑️ A formatação {:latex,ifsc} é ligeiramente diferente da original. Ao printar uma medida com {:latex,ifsc}, será feito da seguinte maneira: (45,4 \pm 0,01)\textrm{ m} ou (19,4 \pm 0,03)\times10^{-3}\textrm{ m³}.
Explicação mais extensa e exemplos da função em um google colab
A partir das medidas
É possível visualizar um histograma através da instalação da biblioteca matplotlib com o parâmetro hist=True. Além disso, é possível controlar a quantidade de bins bins=numero_de_bins. Recomenda-se a instalação da biblioteca numpy para que os cálculos sejam realizados mais rapidamente, embora não seja obrigatório.
A probabilidade que uma certa medida esteja entre
O cálculo de uma exponencial
a=Medida((1,0.5))
montecarlo(lambda x: math.exp(x),a,hist=True)
Exemplo da famosa regra 68-95-99.7, uma variável com distribuição gaussiana com
a=Medida((1,0.1))
montecarlo(lambda x:x,a,probabilidade=[0.8,1.2],hist=True)
- É importante destacar que o cálculo de incertezas muitos grandes não funciona com aproximações lineares, o que enfatiza a importância da utilização de simulações de Monte Carlo para essas situações.
- O método estatístico adicionado a biblioteca pode ser aplicado em qualquer função cujas variáveis aleatórias X pertençam ao seu domínio, expandindo significativamente as possibilidades de funções que podem ser utilizadas na biblioteca.
- A probabilidade que um resultado esteja em um certo intervalo pode ser calculada
Instale a biblioteca usando o comando:
!pip install git+https://github.com/brenopelegrin/LabIFSC
Caso o PIP não esteja disponível ou não funcione, é possível utilizar a LabIFSC simplesmente colocando a pasta LabIFSC
dentro da pasta em que o seu script está. Exemplo:
─┬ Minha pasta qualquer
├─ Relatório.tex
├─ Relatório.pdf
├─ Foto1.jpg
┊
├─ meu script.py
└┬ LabIFSC
├─ __init__.py
├─ geral.py
├─ lista_de_unidades.py
├─ matematica.py
├─ medida.py
├─ tabela.py
└─ unidade.py
Download da Última Versão (.zip)
Para utilizar essa biblioteca:
from LabIFSC import *
A principal classe é a Medida
. Ela pode ser inicializada de diversas formas como mostrado abaixo.
(Note que todas essas medidas são iguais, o que muda é a apenas o formato)
# A unidade é sempre opcional
m = Medida((130, 27), "m") # Medida((valor nominal, erro), unidade)
m = Medida("130+-27", "m") # Medida(valor+-erro, unidade)
m = Medida("130+/-27", "m") # Medida(valor+/-erro, unidade)
m = Medida("130±27", "m") # Medida(valor±erro, unidade)
m = Medida("130(27)", "m") # Medida(valor(erro), unidade)
Também podemos usar a abreviatura M()
, a qual funciona de forma bem parecida:
m = M((130, 27), "m") # Medida((valor nominal, erro), unidade)
m = M("130+-27", "m") # Medida(valor+-erro, unidade)
m = M("130+/-27", "m") # Medida(valor+/-erro, unidade)
m = M("130±27", "m") # Medida(valor±erro, unidade)
m = M("130(27)", "m") # Medida(valor(erro), unidade)
No entanto, M()
também nos permite criar listas de medidas com facilidade:
w = M(np.array([1, 40, 22, 11]), incerteza=1, unidade="m")
x = M([7, 15, 28, 42, 49, 61], incerteza=1, unidade="cm")
y = M(["1", "2", "3", "4", "4", "6"], incerteza=0.01, unidade="s")
z = M(["7+-1", "15+/-0.1", "28±10", "42(3)", 49, 61], unidade="kg", incerteza=0.01)
Uma instância de Medida
tem os seguintes atributos:
m = Medida("130±27", "ft")
print(m.nominal) # 130.0
print(m.incerteza) # 27.0
print(m.si_nominal) # 39.64
print(m.si_incerteza) # 8.2296
Os valores prefixados com si_
estão em unidades do MKS, ou seja: metro, radiano, quilograma, segundo, Kelvin, Ampère e mol. As dimensões físicas são, respectivamente: comprimento (L), ângulo (A), massa (M), tempo (T), temperatura (K), corrente (I) e "número" (N). Quando uma medida é adimensional, usa-se ∅ como mostrado no excerto abaixo:
# Lembre-se que lb é o símbolo para libras/pounds
M("1") # <1.0±0.0 = 1.0±0.0 ∅>
M("1", "lb/kg") # <1.0±0.0 lb kg⁻¹ = 0.45359237±0.0 ∅>
Também é possível converter uma medida para sua equivalente no SI usando o método .SI()
como no exemplo abaixo:
M("1+-0.1", "ft").SI() # <0.3048±0.03048 m = 0.3048±0.03048 L1>
As comparações entre medidas não comparam os valores em si, mas sim verificam se as medidas são estatisticamente equivalentes.
A equação que determina se duas medidas são equivalentes é: |x₁ - x₂| ≤ 2(σ₁ + σ₂)
. Já a equação~que determina não equivalência é |x₁ - x₂| > 3(σ₁ + σ₂)
.
Cuidado deve ser tomado já que duas medidas podem não ser iguais nem diferentes ao mesmo tempo.
m1 = Medida("100+/-7")
m2 = Medida("110+/-3")
m1 == m2 # True
m1 != m2 # False
m1 = Medida("100+/-7")
m2 = Medida("125+/-3")
m1 == m2 # False
m1 != m2 # False
m1 = Medida("100+/-7")
m2 = Medida("131+/-3")
m1 == m2 # False
m1 != m2 # True
A propagação de erro é feita automaticamente nas seguintes operções: +
, -
, *
, /
, **
.
m1 = Medida("20+/-1")
m2 = Medida("4+/-2")
print(m1+m2) # 24±3
print(m1-m2) # 16±3
print(m1*m2) # 80±40
print(m1/m2) # 5±3
print(m1**4) # 160000±30000
print(3**m2) # 81±200
print(m1**m2) # Erro
Infelizmente, não há propagação de erro automática nas funções da biblioteca math
, porém, a LabIFSC provê as seguintes funções com propagação de erro:
m1 = Medida("20+/-1.5")
print(cos(m1)) # 0±1
print(sin(m1)) # 0.9±0.6
print(tan(m1)) # 2±9
print(cot(m1)) # 0±2
print(sec(m1)) # 2±8
print(csc(m1)) # 2.2±0.7
print(arc_cos(m1)) # 0.8±0.1 rad
print(arc_sin(m1)) # 0.8±0.1 rad
print(arc_tan(m1)) # 0.6±0.1 rad
print(log(m1)) # 2.73±0.07
print(log10(m1)) # 1.30±0.03
print(log2(m1)) # 4.3±0.1
print(ln(m1)) # 3±0.08
print(sqrt(m1)) # 4.5±0.2
print(cbr(m1)) # 2.71±0.0
Com a função monte carlo é possível calcular a incerteza de virtualmente qualquer função, para saber mais leia Monte Carlo
Todas as medidas podem ter um parâmetro adicional de unidade após o valor. Por exemplo:
m1 = Medida("1+/-0.001", "m")
m2 = Medida("1+/-0.001", "ft")
m3 = Medida("1+/-0.02", "s")
(O arquivo LabIFSC/lista_de_unidades.py
contém todas as unidades suportadas por esta biblioteca.)
As contas de soma e subtração sempre ficam nas unidades do primeiro argumento nas operações, exceto quando o primeiro argumento for adimensional. Neste caso, as unidades serão as do segundo argumento.
Já as contas de multiplicação e divisão simplesmente combinam as unidades.
# Lembre-se que ft é o símbolo para pés
print(m1+m2) # 2.610±0.001 m
print(m2+m1) # 5.586±0.004 ft
print(m1-m2) # -0.610±0.001 m
print(m2-m1) # -3.586±0.004 ft
print(m1*m2) # 1.000±0.002 ft m
print(m2*m1) # 1.000±0.002 ft m
print(m1/m2) # 1.000±0.002 m ft⁻¹
print(m2/m1) # 1.000±0.002 ft m⁻¹
print(m1*m3) # 1.00±0.02 m s
print(m1/m3) # 1.00±0.02 m s⁻¹
Para converter as unidades:
m4 = m1*m2/m3
print(m4.converta("m^2 s^-1")) # 1.610±0.007 m² s⁻¹
print(m4.converta("m^2/s")) # 1.610±0.007 m² s⁻¹
Uma mesma Medida
pode ser impressa de diferentes formas:
m1 = Medida("1.23456789+/-0.015", "m lb/s")
# Formatação padrão, do jeito que os profs de lab gostam
print(m1) # 1.23±0.02 m lb s⁻¹
print(str(m1)) # 1.23±0.02 m lb s⁻¹
print("{}".format(m1)) # 1.23±0.02 m lb s⁻¹
# Representação do objeto Medida. Temos o valor original à esquerda e o valor no SI, bem como a dimensão física, à direita
print(m1.__repr__()) # <1.23456789±0.015 m lb s⁻¹ = 0.5599905751509993±0.00680388555 L1M1T-1>
print("{:repr}".format(m1)) # <1.23456789±0.015 m lb s⁻¹ = 0.5599905751509993±0.00680388555 L1M1T-1>
# Diferentes estilos de representação com o arredondamento padrão (arredondamento ifsc)
print("{}".format(m1)) # 1.23±0.02 m lb s⁻¹
print("{:-}".format(m1)) # 1.23±0.02 m lb s⁻¹
print("{:latex}".format(m1)) # 1.23\pm0.02\textrm{ m lb s^-1}
print("{:siunitex}".format(m1)) # 1.23±0.02 m lb s⁻¹
print("{:txt}".format(m1)) # 1.23+/-0.02 m lb s^-1
# Diferentes estilos de representação com o arredondamento do ifsc
print("{}".format(m1)) # 1.23±0.02 m lb s⁻¹
print("{:-,ifsc}".format(m1)) # 1.23±0.02 m lb s⁻¹
print("{:latex,ifsc}".format(m1)) # (1.23 \\pm 0.02) \\textrm{ m lb s^-1}
print("{:siunitex,ifsc}".format(m1)) # 1.23±0.02 m lb s⁻¹
print("{:txt,ifsc}".format(m1)) # 1.23+/-0.02 m lb s^-1
# Diferentes estilos de representação sem arredondamento
print("{:-,full}".format(m1)) # 1.23456789±0.015 m lb s⁻¹
print("{:latex,full}".format(m1)) # 1.23456789\\pm0.015\\textrm{ m lb s^-1}
print("{:siunitex,full}".format(m1)) # 1.23456789±0.015 m lb s⁻¹
print("{:txt,full}".format(m1)) # 1.23456789+/-0.015 m lb s^-1
# Diferentes estilos de representação com o arredondamento do ifsc usando 10^-2 como base
print("{:-,ifsc,-2}".format(m1)) # (123±2)×10⁻² m lb s⁻¹
print("{:latex,ifsc,-2}".format(m1)) # (123\pm2)\cdot10^{-2}\textrm{ m lb s^-1}
print("{:siunitex,ifsc,-2}".format(m1)) # (123±2)×10⁻² m lb s⁻¹
print("{:txt,ifsc,-2}".format(m1)) # (123+/-2)*10^-2 m lb s^-1
# Diferentes estilos de representação sem arredondamento usando 10^-2 como base
print("{:-,full,-2}".format(m1)) # (123.45678899999999±1.5)×10⁻² m lb s⁻¹
print("{:latex,full,-2}".format(m1)) # (123.45678899999999\pm1.5)\cdot10^{-2}\textrm{ m lb s^-1}
print("{:siunitex,full,-2}".format(m1)) # (123.45678899999999±1.5)×10⁻² m lb s⁻¹
print("{:txt,full,-2}".format(m1)) # (123.45678899999999+/-1.5)*10^-2 m lb s^-1
Essa biblioteca provê funções para calcular média, desvio padrão e linearização de dados. Mais detalhes estão no exemplo abaixo:
x = M(["147.0", "161.8", "174.6", "161.01", "175.6", "166.0"], incerteza=0.1, unidade="cm")
print(media(x)) # 160±10 cm
print(media(x, incerteza="desvio padrão")) # 160±10 cm
print(media(x, incerteza="propagação")) # 164.3±0.1 cm
print(desvio_padrao(x)) # 10.516907815513074
x = M(["7", "15", "28", "42", "49", "61"], incerteza=1, unidade="cm")
y = M(["1", "2", "3", "4", "4", "6"], incerteza=0.01, unidade="s")
linearize(x, y, imprimir=True)
x[1] = x[1].converta("m")
x[2] = x[2].converta("km")
linearize(x, y, imprimir=True)
# Note que, mesmo com unidades diferentes, as linearizações tem o mesmo resultado
Além da implementação original da biblioteca, foi adicionada uma classe que permite manipular tabelas e obter o resultado em LaTeX e uma função para ajudar a criar tabelas com arrays de medidas.
A classe Tabela
possui os seguintes métodos:
Método | Descrição |
---|---|
addColuna(array , titulo ) |
Adiciona uma coluna de medidas a partir de um array e define o título da coluna |
delColuna(index ) |
Deleta a coluna de acordo com o índice |
gerarLatex() | Retorna uma string contendo o código em LaTeX |
Ao adicionar a primeira coluna, você define o número de elementos máximo de cada coluna da tabela. Todas as próximas colunas precisam ter o mesmo número de linhas.
A biblioteca cuidará da formatação das unidades e incertezas:
- Se você passar um array com medidas com a mesma incerteza, a incerteza e unidade será colocada no título e removida das linhas
- Se você passar um array com medidas de incertezas diferentes, elas serão colocadas em cada linha da tabela e apenas a unidade será colocada no título
- Não é possível criar uma coluna passando um array com medidas com unidades diferentes
Exemplo de como utilizar:
import LabIFSC as lab
import numpy as np
m_1 = lab.M(np.array([1.001, 2.034, 5.394]), incerteza=0.001, unidade='m')
m_2 = lab.M(np.array([1.201, 6.034, 1.694]), incerteza=0.005, unidade='kg')
# Criando um array de medidas com unidades diferentes utilizando a função M()
# Nesse caso, como um array numpy foi passado, será retornado um array numpy.
m_3 = lab.M(np.array([lab.Medida(0.5, incerteza=0.1, unidade="s"), lab.Medida(0.3, incerteza=0.05, unidade="s"), lab.Medida(0.2, incerteza=0.2, unidade="s")]))
# Criando um array de medidas com unidades diferentes utilizando a função arrayM()
# Nesse caso, a função irá retornar um array numpy pois utilizou-se um transformer np.array
m_4 = lab.arrayM(arrayNominal=np.array([0.44354, 0.12, 1.223]), incertezas=np.array([0.001, 0.1, 0.05]), unidades='ºC', transformer=np.array)
# Criando um array de medidas com unidades diferentes utilizando a função arrayM()
# Nesse caso, a função irá retornar uma lista pois utilizou-se um transformer list
m_5 = lab.arrayM(arrayNominal=[1.54, 0.123, 5.223], incertezas=0.0037, unidades='C', transformer=list)
tab = lab.Tabela(titulo='Meu titulo')
tab.addColuna(m_1, 'Distancias')
tab.addColuna(m_2, 'Massas')
tab.addColuna(m_3, 'Tempos')
tab.addColuna(m_4, 'Temperaturas')
tab.addColuna(m_5, 'Cargas')
tab.delColuna(0)
tabLatex = tab.gerarLatex()
print(tabLatex)
Output:
\begin{table}[H]
\centering
\caption{Meu titulo}
\label{yourLabelHere}
\begin{tabular}{|c|c|c|c|}
\hline
\textbf{Massas (kg) $\pm$ 0,005 (kg)}&\textbf{Tempos (s)}&\textbf{Temperaturas (ºC)}&\textbf{Cargas (C) $\pm$ 0,004 (C)}\\ \hline
1,201&0,5 \pm 0,1&0,444 \pm 0,001&1,540\\ \hline
6,034&0,30 \pm 0,05&0,1 \pm 0,1&0,123\\ \hline
1,694&0,2 \pm 0,2&1,22 \pm 0,05&5,223\\ \hline
\end{tabular}
\caption*{Fonte: Autoria própria}
\end{table}
A função arrayM()
foi criada para ajudar à criar tabelas facilmente.
-
Ela recebe um array dos valores nominais das medidas, um array de incertezas ou uma única incerteza, um array de unidades ou uma única unidade.
-
Se ela receber apenas uma unidade ou incerteza, essa unidade ou incerteza será adotada para todo o array de valores nominais.
-
No caso de uma unidade para todos os nominais, a unidade precisa ser um
str
. -
No caso de uma incerteza para todos os nominais, a incerteza precisa ser um
float
oustr
. -
No caso de arrays de incertezas e unidades, eles precisam ter o mesmo length do array de nominais.
A função funciona da seguinte forma:
# Cria um array com os valores nominais, suas incertezas e unidades
# O transformer padrão é o list, então essa chamada irá retornar uma lista
nominais = [1.0, 2.1, 3.4, 0.2]
incertezas = [0.3, 0.2, 0.1, 0.1]
unidades = ['m', 'kg', 'C', 's']
medidas = lab.arrayM(nominais, incertezas, unidades)
# Cria um array com os valores nominais, suas incertezas e apenas uma unidade para todos
# Aqui, foi utilizado um transformer np.array, então irá retornar um array numpy
nominais = [1.0, 2.1, 3.4, 0.2]
incertezas = np.array([0.3, 0.2, 0.1, 0.1])
unidades = 'm'
medidas = lab.arrayM(nominais, incertezas, unidades, transformer=np.array)
# Cria um array com os valores nominais, uma incerteza para todos, e apenas uma unidade para todos
# Aqui, foi utilizado um transformer list, então irá retornar uma lista
nominais = np.array([1.0, 2.1, 3.4, 0.2])
incertezas = 0.1
unidades = 'm'
medidas = lab.arrayM(nominais, incertezas, unidades, transformer=list)
# Os inputs nominais, incertezas e unidades podem ser list ou ndarray