From a9076aeee4ea04ad62138c34dc96ddc98ebd1ea3 Mon Sep 17 00:00:00 2001 From: viniciusdutra314 Date: Tue, 21 Jan 2025 22:18:43 +0000 Subject: [PATCH] =?UTF-8?q?seccao=20de=20propaga=C3=A7=C3=A3o=20de=20erros?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 ++ LabIFSC2/__init__.py | 2 +- LabIFSC2/_arrays.py | 2 +- LabIFSC2/_medida.py | 5 +- docs/Arrays/linspace.md | 2 - docs/arrays.md | 7 +-- docs/funcoes_matematicas.md | 26 ++-------- docs/graficos.md | 28 +++++++++-- docs/index.md | 1 - docs/propagacao_de_erros.md | 68 ++++++++++++++++++++++++++ mkdocs.yml | 6 ++- tests/test_arrayM.py | 8 +-- tests/test_classe_para_regressoes.py | 8 +-- tests/test_doc_grafico_fitting.py | 28 +++++++---- tests/test_doc_grafico_scatter.py | 12 +++-- tests/test_doc_gravidade_histograma.py | 52 ++++++++++++++++++++ tests/test_doc_linspace.py | 2 +- tests/test_funcoes_vetorizadas.py | 8 +-- tests/test_regressao_unidades.py | 6 +-- tests/test_regressoes_exponenciais.py | 8 +-- tests/test_regressoes_potencia.py | 6 +-- tests/test_tipagem_forte.py | 8 +-- 22 files changed, 217 insertions(+), 80 deletions(-) create mode 100644 docs/propagacao_de_erros.md create mode 100644 tests/test_doc_gravidade_histograma.py diff --git a/.gitignore b/.gitignore index 046aac1..38a3927 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +#temporario +*.jpg +*.png + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/LabIFSC2/__init__.py b/LabIFSC2/__init__.py index 03fe037..0c98453 100644 --- a/LabIFSC2/__init__.py +++ b/LabIFSC2/__init__.py @@ -6,7 +6,7 @@ ''' -from ._arrays import (arrayM, curva_max, curva_min, incertezas, linspace, +from ._arrays import (arrayM, curva_max, curva_min, incertezas, linspaceM, nominais) from ._medida import Comparacao, Medida, comparar_medidas, montecarlo from ._regressões import (MExponencial, MPolinomio, regressao_exponencial, diff --git a/LabIFSC2/_arrays.py b/LabIFSC2/_arrays.py index 4803d10..ebf92d8 100644 --- a/LabIFSC2/_arrays.py +++ b/LabIFSC2/_arrays.py @@ -103,7 +103,7 @@ def curva_max(arrayMedidas : np.ndarray,unidade:str,sigma:float | int=2)-> np.nd @obrigar_tipos -def linspace(a:Real,b:Real,n : int, +def linspaceM(a:Real,b:Real,n : int, incertezas : Real ,unidade : str) -> np.ndarray: """Gera um array com N Medidas de valor nominal [a,b] A incerteza será constante caso 'incertezas' for um número, diff --git a/LabIFSC2/_medida.py b/LabIFSC2/_medida.py index b10d22c..066dc57 100644 --- a/LabIFSC2/_medida.py +++ b/LabIFSC2/_medida.py @@ -184,9 +184,8 @@ def __getattr__(self, func_name:str) -> Any: raise AttributeError else: func=getattr(np,func_name) - def FuncaoComMedida() -> Any: return montecarlo(func, self) - return FuncaoComMedida - + def funcao_recebe_medida() -> Any: return montecarlo(func, self) + return funcao_recebe_medida def _adicao_subtracao(self,outro: 'Medida',positivo:bool) -> 'Medida': if not (isinstance(outro,Medida) or isinstance(outro,Real)): return NotImplemented diff --git a/docs/Arrays/linspace.md b/docs/Arrays/linspace.md index 4cdae25..e69de29 100644 --- a/docs/Arrays/linspace.md +++ b/docs/Arrays/linspace.md @@ -1,2 +0,0 @@ -:::LabIFSC2._arrays.linspace - diff --git a/docs/arrays.md b/docs/arrays.md index a8fc30a..2efcaee 100644 --- a/docs/arrays.md +++ b/docs/arrays.md @@ -13,14 +13,13 @@ entre arrays, o resultado disso são operações elemento a elemento ``` ## Operações matemáticas -Como discutido na secção de [Funçõs matemáticas](funcoes_matematicas.md), as funções -matemáticas da biblioteca (lab.exp,lab.cos,lab.sinh), podem atuar diretamente em arrays +Como discutido na secção de [Funçõs matemáticas](funcoes_matematicas.md), as funções do numpy podem atuar diretamente na classe Medida. ```py --8<-- "tests/test_doc_sqrt_vetorizado.py:1:8" ``` -## linspace +## linspaceM Em muitas medidas experimentais nós fazemos medições igualmente espaçadas, imagine que você está medindo o campo magnético de um fio em função da sua distância \(\vec{B}(distância)\), você realiza uma medição a cada 1cm por exemplo, o lab.linspace recebe o valor da primeira medição, @@ -33,6 +32,8 @@ No exemplo abaixo nós fizemos 10 medições entre [1cm,10cm], com precisão de A função é o análogo do [np.linspace](https://numpy.org/doc/stable/reference/generated/numpy.linspace.html#numpy-linspace) que recebe medidas +## + ## arrayM Agora que temos as distâncias nós medimos o campo magnético pra cada distância, como registramos esses campos? teríamos que criar 10 objetos `Medida` diretamente? Não, a solução é o lab.arrayM, ele recebe uma lista/array diff --git a/docs/funcoes_matematicas.md b/docs/funcoes_matematicas.md index ccde0a4..4a8b903 100644 --- a/docs/funcoes_matematicas.md +++ b/docs/funcoes_matematicas.md @@ -6,31 +6,15 @@ portanto, operações entre Medidas são idênticas a operações entre números --8<-- "tests/test_doc_operacoes_basicas.py:1:10" ``` -## Decorador Aceita Medida -Pela generalidade do método de propagação de erros usando monte carlo, o LabIFSC2 possui uma decorador -que consegue fazer com que uma função matemática **qualquer do numpy** aceite uma `Medida` e faça propagação de erros, -essa é a magia do `aceitamedida` +## Funções Numpy +O LabIFSC2 implementa uma compatibilidade direta com as funções do Numpy (tecnicamente chamadas de [ufunc](https://numpy.org/doc/stable/reference/ufuncs.html)), então você aplicar funções como np.sin, np.sqrt, np.arctanh naturalmente[^1] -```py ---8<-- "tests/test_doc_aceitamedida.py:1:11" -``` - -Perceba que pegamos a função do numpy (np.sin) e transformamos ela em uma função que aceita medidas, -temos ainda integrações bonitas com o sistema de unidades, conseguimos usar um ângulo diretamente em **graus** -sem converter para radianos. - -## Operando em arrays -As funções além de aceitarem medidas também aceitam arrays numpy, podemos fazer então operações -vetorizadas -```py +```py --8<-- "tests/test_doc_sqrt_vetorizado.py:1:8" ``` -## Todas funções suportadas -Caso queira uma lista de todas as funções matemáticas que estão no LabIFSC2, eis o código fonte com todas elas e seus apelidos (sin=seno, tan=tg) -```py {title=_matematica.py} ---8<-- "LabIFSC2/_matematica.py:39" -``` +[^1]: + Para os curiosos, isso é feito implementado métodos específicos na classe Medida, por exemplo, a função np.sqrt(x) verifica se o tipo de x tem o método x.sqrt,se tiver, ele chama x.sqrt, a classe `Medida` possui uma simulação monte carlo de sqrt e todas as funções matemáticas (isso é feito criando-se dinamicamente os métodos com [__getattr__](https://docs.python.org/3/reference/datamodel.html#object.__getattr__)) \ No newline at end of file diff --git a/docs/graficos.md b/docs/graficos.md index 47db4e0..82160ce 100644 --- a/docs/graficos.md +++ b/docs/graficos.md @@ -18,11 +18,29 @@ De maneira análogo podemos também pegar as incertezas com `incertezas(array_me Eis um exemplo simples de como fazer um gráfico de dispersão com erros tanto em x quanto em y, basta usar a função do matplotlib [`plt.errorbar`](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.errorbar.html), `nominais` e `incertezas`. -```py ---8<-- "tests/test_doc_grafico_scatter.py:1:16" + + + +```py hl_lines="12-16" +--8<-- "tests/test_doc_grafico_scatter.py:1:19" +``` + +Repare que as unidade são variáveis no código que podem ser modificadas rapidamente. + + + +## Curva Min/Max + +As funções `curva_min` e `curva_max` são utilizadas para calcular a curva teórica considerando as incertezas nos parâmetros encontrados durante a regressão dos dados (chamados de [Confidence and prediction bands]([Confidence and prediction bands)](https://en.wikipedia.org/wiki/Confidence_and_prediction_bands)) + +## Curva teórica com erro +Regressões de dados inevitavelmente apresentam incertezas nos parâmetros encontrados, podemos representa-las usando as funções `curva_min` e `curva_max` que calculam a curva teórica \(\pm \, \, 2\sigma \) + + + +```py hl_lines="20-29" +--8<-- "tests/test_doc_grafico_fitting.py:1:30" ``` -Repare que as unidade são variáveis no código que podem ser modificadas rapidamente, o resultado é esse: - +Perceba que para lidar com as unidades acaba que a sintaxe fica infelizmente verbosa, isso é algo pessoal mas nesse caso eu recomendo usar um tipo de indentação chamada `Hanging indentation ` em cada argumento ocupa uma linha de código, assim o código fica mais legível (na minha opinião) e menos horizontal. -## \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index f43115e..b8bdfbc 100644 --- a/docs/index.md +++ b/docs/index.md @@ -51,7 +51,6 @@ Mesmo que a interface seja intencionalmente parecida a implementação é totalm | Unidades | Implementação autoral | Baseado no famoso [pint](https://pint.readthedocs.io/) | Constantes da natureza| ❌ | +350 definidas pela [CODATA(2022)](https://codata.org/initiatives/data-science-and-stewardship/fundamental-physical-constants/) | Operações com arrays| ❌ | Suportadas pelo [Numpy](numpy.org) -| Tabelas em LaTeX | ❌| ✅ | Segurança de tipos (mypy)| ❌ | ✅ | Docstrings em funções | ❌ | ✅ | Suporte | ❌ | Ativo | diff --git a/docs/propagacao_de_erros.md b/docs/propagacao_de_erros.md new file mode 100644 index 0000000..fcf1bda --- /dev/null +++ b/docs/propagacao_de_erros.md @@ -0,0 +1,68 @@ +Nesta seção, explicarei em mais detalhes como a biblioteca propaga incertezas, o método usado é mais geral, mas ainda assim compatível com o da apostila. Nos testes unitários da biblioteca, comparamos os erros calculados pelo LabIFSC2 com as bibliotecas [uncertainties](https://pythonhosted.org/uncertainties/) e [LabIFSC](https://github.com/gjvnq/LabIFSC), chegando a um acordo geralmente de \(10^{-3}\) para erros pequenos, onde os métodos devem ser equivalentes. + +## Apostila +A apostila se baseia principalmente no GUM (Guide to the Expression of Uncertainty in Measurement)[^1]. O método é uma propagação linear baseada em uma série de Taylor. + +Começamos com uma série de Taylor de uma função de \(N\) variáveis, ou seja, uma boa aproximação para **pequenas variações da função**: + +$$f(\mathbf{x}+\Delta \mathbf{x})\approx f(\mathbf{x})+\sum_{i} \frac{\partial f}{\partial x_{i}}\Delta x_{i}$$ + +$$(f(\mathbf{x}+\Delta \mathbf{x})-f(\mathbf{x}))²\approx (\sum_{i} \frac{\partial f}{\partial x_{i}}\Delta x_{i})²$$ + +Note que o lado esquerdo nada mais é que a variação da função \(\Delta f\). Se pegarmos o valor esperado, teremos a variância de \(f\) (\(\sigma²_{f}\)): + +$$\mathbb{E}[(f(\mathbf{x}+\Delta \mathbf{x})-f(\mathbf{x}))²]\approx \mathbb{E}[(\sum_{i} \frac{\partial f}{\partial x_{i}}\Delta x_{i})²]$$ + +Supondo que \(\Delta x_i\) tenha uma distribuição simétrica \(\mathbb{E}(\Delta x_{i})=0\), os termos cruzados \(\mathbb{E}(\Delta x_{i}\Delta x_{j})=\mathbb{E}(\Delta x_{i})\mathbb{E}(\Delta x_{j})=0\) desaparecem (se supormos que são totalmente independentes). + +Logo: + +$$\sigma²_{f}=\sum_{i} \left(\frac{\partial f}{\partial x_{i}}\sigma_{x_{i}}\right)²$$ + +Se quisermos em termos do desvio padrão e não da variância, temos: + +$$\sigma_{f}=\sqrt{\sum_{i} \left(\frac{\partial f}{\partial x_{i}}\sigma_{x_{i}}\right)²}$$ + +Essa é essencialmente a fórmula usada na apostila. Para o caso de uma variável, se reduz a \(\sigma_{f}=|\frac{\partial f}{\partial x}\sigma_{x}|\). A diferença é que a apostila ignora a raiz quadrada na expressão de incertezas com mais de uma variável, superestimando assim o erro. + +Pensando intuitivamente, erros não podem simplesmente se somar, visto que, pela sua natureza aleatória, é esperado que existam erros que acabem "compensando" outros. + +## Monte Carlo +Imagine que temos uma medida indireta \(y\) que depende de um conjunto de \(N\) medidas: + +$$y=f(x_1,x_2,\dots,x_n)$$ + +Cada variável \(x_i\) tem sua PDF ([probability density function](https://en.wikipedia.org/wiki/Probability_density_function)), que é uma forma matemática de dizer que não temos certeza sobre seus valores. Por simplicidade, assumimos que medidas diretas têm distribuições gaussianas (centradas em uma média \(\mu\) e uma variância \(\sigma²\)). + +O Método Monte Carlo consiste em simular diversas medidas experimentais no computador (usando um gerador de números aleatórios com as respectivas PDFs). Dessa forma, geramos um histograma de possíveis valores de \(y\); esse histograma é a PDF de \(y\). + +O interessante desse método é que o histograma de \(y\) não necessariamente é analítico (geralmente com formatos bem estranhos para incertezas grandes). Esse histograma é utilizado para diversas coisas na biblioteca: + +- Ser usado como PDF para outra propagação de incerteza +- Cálculo do intervalo de confiança +- A média e o desvio padrão da PDF são usados no `print(medida)` + +### Exemplo com a gravidade +Retornando ao exemplo da estimativa da gravidade usando um pêndulo, mas agora com incertezas maiores em \(T\) e \(L\) (para que os efeitos fiquem mais visíveis). + +A classe `Medida` possui um atributo chamado `histograma`, onde estão guardados os histogramas. No dia a dia, esse atributo deve ser raramente acessado, mas para fins didáticos ele é interessante. + +```py +--8<-- "tests/test_doc_gravidade_histograma.py:8:15" +``` + +Repare como \(T\) e \(L\) são gaussianas (\(\mu_L=15cm\), \(\sigma_L=1cm\)) e (\(\mu_T=780ms\), \(\sigma_T=80ms\)). + + + +Já o histograma de \(g\) é centralizado em \(10m/s²\), mas observe que ele possui uma cauda para a direita. A distribuição não é simétrica, logo, não é gaussiana. Se usássemos \(g\) para outros cálculos, esse desvio de uma gaussiana provavelmente iria se amplificando. Esse fato não é observado no método GUM, que assume linearidade e basicamente tudo é uma gaussiana. + + + +[^1]: O método GUM é amplamente utilizado em metrologia e calibragem de equipamentos. Existem diversas referências para quem quiser aprender mais. Eu, pessoalmente, achei um material introdutório e interessante em: + + Kirkup, L., Frenkel, R. B. (2006). An Introduction to Uncertainty in Measurement: Using the GUM (Guide to the Expression of Uncertainty in Measurement). Reino Unido: Cambridge University Press. + +[^2]: O principal material usado na implementação do Monte Carlo foi o próprio material suplementar do GUM sobre Monte Carlo. É interessante notar que esse material explicitamente considera o método Monte Carlo como uma forma mais precisa de calcular incertezas: + + “Evaluation of Measurement Data — Supplement 1 to the ‘Guide to the Expression of Uncertainty in Measurement’ — Propagation of Distributions Using a Monte Carlo Method,” 2008. https://doi.org/10.59161/JCGM101-2008. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 8493ac4..cf924af 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,9 +5,10 @@ nav: - Constantes: Constantes/constantes da natureza.md - Funções Matemáticas: funcoes_matematicas.md - Arrays: arrays.md - - Gráficos: graficos.md - Regressões (Fitting): Regressões (fitting)/linear.md + - Gráficos: graficos.md - Formataçõs/LaTeX: formatacoes_latex.md + - Como erros são propagados?: propagacao_de_erros.md - API Completa: api.md - Como contribuir: contribuir.md @@ -49,4 +50,5 @@ markdown_extensions: - pymdownx.inlinehilite - pymdownx.snippets - pymdownx.superfences - - mdx_math \ No newline at end of file + - mdx_math + - footnotes \ No newline at end of file diff --git a/tests/test_arrayM.py b/tests/test_arrayM.py index 2e35171..fd8937d 100644 --- a/tests/test_arrayM.py +++ b/tests/test_arrayM.py @@ -2,7 +2,7 @@ import pytest from LabIFSC2 import (Medida, arrayM, curva_max, curva_min, incertezas, - linspace, nominais) + linspaceM, nominais) def test_nominal(): @@ -44,19 +44,19 @@ def test_curvamax(): def test_linspace(): a=1 ; b=20 ; N=20 - x=linspace(a,b,N,0.1,'') + x=linspaceM(a,b,N,0.1,'') assert np.all(nominais(x,"")==np.linspace(a,b,N)) assert np.all(incertezas(x,"")==0.1) def test_converter_array(): - x=linspace(5,10,10,0.01,'mm') + x=linspaceM(5,10,10,0.01,'mm') esperado=np.linspace(0.5,1,10) #cm for index in range(len(x)): assert np.isclose(x[index].nominal('cm'),esperado[index]) def test_converter_array_si(): - x=linspace(10,50,10,0.01,'cm') + x=linspaceM(10,50,10,0.01,'cm') esperado=np.linspace(0.1,0.5,10) #si for index in range(len(x)): assert np.isclose(x[index].nominal('si'),esperado[index]) diff --git a/tests/test_classe_para_regressoes.py b/tests/test_classe_para_regressoes.py index 7eb396d..c49abec 100644 --- a/tests/test_classe_para_regressoes.py +++ b/tests/test_classe_para_regressoes.py @@ -5,7 +5,7 @@ def test_initialization(): - coeficientes = lab.linspace(1,3,3,0,'') + coeficientes = lab.linspaceM(1,3,3,0,'') with pytest.raises(TypeError): lab.MPolinomio(np.array([1, 2, 3])) polinomio=lab.MPolinomio(coeficientes) @@ -16,11 +16,11 @@ def test_initialization(): assert polinomio.c.nominal("") == 3 def test_call(): - coeficientes = lab.linspace(1,3,3,0,'') + coeficientes = lab.linspaceM(1,3,3,0,'') polinomio=lab.MPolinomio(coeficientes) with pytest.raises(TypeError): polinomio(0) - pontos=lab.linspace(0,2,3,0,'') + pontos=lab.linspaceM(0,2,3,0,'') assert np.isclose(polinomio(pontos[0]).nominal(""), 3) assert np.isclose(polinomio(pontos[1]).nominal(""),6) assert np.isclose(polinomio(pontos[2]).nominal("") , 11) @@ -32,7 +32,7 @@ def test_call(): def test_unpacking(): - coeficientes = lab.linspace(1,3,3,0,'') + coeficientes = lab.linspaceM(1,3,3,0,'') polinomio = lab.MPolinomio(coeficientes) a, b, c = polinomio assert a.nominal("") == 1 diff --git a/tests/test_doc_grafico_fitting.py b/tests/test_doc_grafico_fitting.py index f267cd2..1b34f91 100644 --- a/tests/test_doc_grafico_fitting.py +++ b/tests/test_doc_grafico_fitting.py @@ -1,25 +1,33 @@ import matplotlib.pyplot as plt -import numpy as np from LabIFSC2 import * campo_magnético=arrayM([210,90,70,54,39,32,33,27,22,20],1,'muT') -distancias=linspace(1,10,10,0.01,'cm') +distancias=linspaceM(1,10,10,0.01,'cm') unidade_x='cm' unidade_y='muT' regressao=regressao_potencia(distancias,campo_magnético) -print(regressao) +print(regressao) +#MLeiDePotencia(a=(2,0 ± 0,1)x10² cm⁰⋅⁹⁸⁶³⁵⁵·µT, b=(-9,9 ± 0,3)x10⁻¹ ) plt.style.use('ggplot') -plt.errorbar(nominais(distancias,unidade_x),nominais(campo_magnético,unidade_y), - xerr=incertezas(distancias,unidade_x),yerr=incertezas(campo_magnético,unidade_y), +plt.errorbar(x=nominais(distancias,unidade_x), + y=nominais(campo_magnético,unidade_y), + xerr=incertezas(distancias,unidade_x), + yerr=incertezas(campo_magnético,unidade_y), fmt='o',label='Dados experimentais',color='red') -x=linspace(1,10,100,0,unidade_x) -plt.plot(nominais(x,unidade_x),nominais(regressao(x),unidade_y),color='blue', +x=linspaceM(1,10,100,0,unidade_x) +plt.plot(nominais(x,unidade_x), + nominais(regressao(x),unidade_y), + color='blue', label="Curva teórica") -plt.fill_between(nominais(x,unidade_x),curva_min(regressao(x),unidade_y), - curva_max(regressao(x),unidade_y),color='blue',alpha=0.3) + +plt.fill_between(x=nominais(x,unidade_x), + y1=curva_min(regressao(x),unidade_y), + y2=curva_max(regressao(x),unidade_y), + color='blue',alpha=0.3) plt.legend() -#plt.savefig('teste.jpg') \ No newline at end of file +plt.savefig('docs/images/graficos_fitting.jpg',dpi=300) +plt.cla() diff --git a/tests/test_doc_grafico_scatter.py b/tests/test_doc_grafico_scatter.py index 493e396..0a9de2f 100644 --- a/tests/test_doc_grafico_scatter.py +++ b/tests/test_doc_grafico_scatter.py @@ -3,15 +3,19 @@ from LabIFSC2 import * campo_magnético=arrayM([250,150,110,90,70,60,55,40,25,20],1,'muT') -distancias=linspace(1,10,10,0.5,'cm') +distancias=linspaceM(1,10,10,0.5,'cm') unidade_x='cm' unidade_y='muT' plt.style.use('ggplot') -plt.errorbar(nominais(distancias,unidade_x),nominais(campo_magnético,unidade_y), - xerr=incertezas(distancias,unidade_x),yerr=incertezas(campo_magnético,unidade_y),fmt='o') +plt.errorbar(x=nominais(distancias,unidade_x), + y=nominais(campo_magnético,unidade_y), + xerr=incertezas(distancias,unidade_x), + yerr=incertezas(campo_magnético,unidade_y), + fmt='o') plt.xlabel(f"Distancia ({unidade_x})") plt.ylabel(f"Campo magnético ({unidade_y})") -#plt.savefig("exemplo.jpg") \ No newline at end of file +plt.savefig('docs/images/graficos_scatter.jpg',dpi=300) +plt.cla() \ No newline at end of file diff --git a/tests/test_doc_gravidade_histograma.py b/tests/test_doc_gravidade_histograma.py new file mode 100644 index 0000000..91a6308 --- /dev/null +++ b/tests/test_doc_gravidade_histograma.py @@ -0,0 +1,52 @@ +import matplotlib.pyplot as plt +from matplotlib.gridspec import GridSpec + +from LabIFSC2 import * + +# Definindo as constantes e medidas +pi = constantes.pi +L = Medida(15, 1, 'cm') +T = Medida(780, 80, 'ms') +gravidade = (4 * pi**2) * L / T**2 +histograma_g = gravidade.histograma +histograma_L = L.histograma +histograma_T = T.histograma + +#(...) bastante matplotlib para ficar bonito +plt.style.use('ggplot') + +# Obtendo os histogramas + + +# Criando a grade personalizada +fig = plt.figure() +gs = GridSpec(2, 2, height_ratios=[1, 1], width_ratios=[1, 1]) + +# Adicionando os subplots à grade +ax1 = fig.add_subplot(gs[0, 0]) +ax2 = fig.add_subplot(gs[0, 1]) +ax3 = fig.add_subplot(gs[1, :]) + + + +# Histograma de L +ax1.hist(histograma_L, bins=1000, color='green', alpha=0.7) +ax1.set_title('PDF (L)') +ax1.set_xlabel('L (cm)') +ax1.set_ylabel('Frequência') + +# Histograma de T +ax2.hist(histograma_T, bins=100, color='red', alpha=0.7) +ax2.set_title('PDF (T)') +ax2.set_xlabel('T (ms)') +ax2.set_ylabel('Frequência') + +# Histograma da gravidade +ax3.hist(histograma_g.to('m/s²'), bins=1000, color='blue', alpha=0.7) +ax3.set_title(r'PDF ($g=\frac{4\pi^2L}{T^2}$)') +ax3.set_xlabel('g (m/s²)') +ax3.set_ylabel('Frequência') + +# Ajustando o layout +plt.tight_layout() +plt.savefig("docs/images/gravidade_histograma.jpg",dpi=300) \ No newline at end of file diff --git a/tests/test_doc_linspace.py b/tests/test_doc_linspace.py index c4a3aef..001716a 100644 --- a/tests/test_doc_linspace.py +++ b/tests/test_doc_linspace.py @@ -1,6 +1,6 @@ from LabIFSC2 import * -distancias=linspace(1,10,10,0.05,'cm') +distancias=linspaceM(1,10,10,0.05,'cm') print(distancias) #[(1,00 ± 0,05) cm (2,00 ± 0,05) cm (3,00 ± 0,05) cm (4,00 ± 0,05) cm #(5,00 ± 0,05) cm (6,00 ± 0,05) cm (7,00 ± 0,05) cm (8,00 ± 0,05) cm diff --git a/tests/test_funcoes_vetorizadas.py b/tests/test_funcoes_vetorizadas.py index 34156cc..06f2928 100644 --- a/tests/test_funcoes_vetorizadas.py +++ b/tests/test_funcoes_vetorizadas.py @@ -6,7 +6,7 @@ def test_array_medida_soma(): x=lab.Medida(0,0.0001,'') - x_array=lab.linspace(0,10,10,0.001,'') + x_array=lab.linspaceM(0,10,10,0.001,'') somar=x+x_array assert isinstance(somar,np.ndarray) somar=x_array+x @@ -18,7 +18,7 @@ def test_array_medida_soma(): def test_array_medida_subtracao(): x = lab.Medida(10, 0.0001, '') - x_array = lab.linspace(1, 10, 10, 0.1, '') + x_array = lab.linspaceM(1, 10, 10, 0.1, '') subtrair = x - x_array assert isinstance(subtrair, np.ndarray) subtrair = x_array - x @@ -32,7 +32,7 @@ def test_array_medida_subtracao(): def test_array_medida_multiplicacao(): x = lab.Medida(2, 0.0001, '') - x_array = lab.linspace(1, 10, 10, 0.1, '') + x_array = lab.linspaceM(1, 10, 10, 0.1, '') multiplicar = x * x_array assert isinstance(multiplicar, np.ndarray) multiplicar = x_array * x @@ -44,7 +44,7 @@ def test_array_medida_multiplicacao(): def test_array_medida_divisao(): x = lab.Medida(13, 0.001, '') - x_array = lab.linspace(1, 10, 10, 0.1, '') + x_array = lab.linspaceM(1, 10, 10, 0.1, '') dividir = x / x_array assert isinstance(dividir, np.ndarray) dividir = x_array / x diff --git a/tests/test_regressao_unidades.py b/tests/test_regressao_unidades.py index 968f1c5..46e6508 100644 --- a/tests/test_regressao_unidades.py +++ b/tests/test_regressao_unidades.py @@ -4,13 +4,13 @@ from LabIFSC2 import * campo_magnético=arrayM([210,90,70,54,39,32,33,27,22,20],1,'muT') -distancias=linspace(1,10,10,0.01,'cm') -unidade_errada=linspace(1,10,10,0.001,'kg') +distancias=linspaceM(1,10,10,0.01,'cm') +unidade_errada=linspaceM(1,10,10,0.001,'kg') def test_regressao_linear_unidades(): linha=regressao_linear(distancias,campo_magnético) linha(distancias) - unidade_errada=linspace(1,10,10,0.001,'') + unidade_errada=linspaceM(1,10,10,0.001,'') with pytest.raises(ValueError): linha(unidade_errada) comparar_medidas(linha(distancias)[0],campo_magnético[0]) diff --git a/tests/test_regressoes_exponenciais.py b/tests/test_regressoes_exponenciais.py index 1597049..4f8e539 100644 --- a/tests/test_regressoes_exponenciais.py +++ b/tests/test_regressoes_exponenciais.py @@ -21,7 +21,7 @@ def test_MExponencial_call(): exponencial=lab.MExponencial(a,k,base) x=lab.Medida(2,0.1,'') exponencial(x) - x_array=lab.linspace(0,1,10,0.1,'') + x_array=lab.linspaceM(0,1,10,0.1,'') exponencial(x_array) @pytest.mark.parametrize("a, k", [ @@ -44,7 +44,7 @@ def test_equivalencia_com_scipy(a, k): a_scipy = lab.Medida(a_scipy, perr[0], '') k_scipy = lab.Medida(k_scipy, perr[1], '') - x_dados = lab.linspace(3, 10, 100, 0.01, '') + x_dados = lab.linspaceM(3, 10, 100, 0.01, '') y_dados = exponencial_np(x_dados, a, k) * ruido exponencial_np = lab.regressao_exponencial(x_dados, y_dados) @@ -57,8 +57,8 @@ def test_equivalencia_com_scipy(a, k): def test_exceptions(): - y=lab.linspace(-3,1,10,0.1,'') - x=lab.linspace(3,1,10,0.1,'') + y=lab.linspaceM(-3,1,10,0.1,'') + x=lab.linspaceM(3,1,10,0.1,'') with pytest.raises(ValueError): lab.regressao_exponencial(x,y) diff --git a/tests/test_regressoes_potencia.py b/tests/test_regressoes_potencia.py index e03de58..bf40a1d 100644 --- a/tests/test_regressoes_potencia.py +++ b/tests/test_regressoes_potencia.py @@ -22,7 +22,7 @@ def test_lei_de_potencia(a, b): popt, pcov = curve_fit(potencia_np, x_dados, y_dados) a_scipy, b_scipy = popt - x_dados = lab.linspace(3, 10, 100, 0.01, '') + x_dados = lab.linspaceM(3, 10, 100, 0.01, '') y_dados = potencia_np(x_dados, a, b) * ruido potencia_np = lab.regressao_potencia(x_dados, y_dados) assert np.isclose(a_scipy,potencia_np.a.nominal(""),atol=(1e-2)*a) @@ -32,8 +32,8 @@ def test_lei_de_potencia(a, b): def test_exceptions(): - negativo=lab.linspace(-5,5,11,0.01,'') - positivo=lab.linspace(5,10,11,0.01,'') + negativo=lab.linspaceM(-5,5,11,0.01,'') + positivo=lab.linspaceM(5,10,11,0.01,'') with pytest.raises(ValueError): lab.regressao_potencia(negativo,positivo) diff --git a/tests/test_tipagem_forte.py b/tests/test_tipagem_forte.py index ad576a8..fca3054 100644 --- a/tests/test_tipagem_forte.py +++ b/tests/test_tipagem_forte.py @@ -67,7 +67,7 @@ def recebe_array_numpy(x:np.ndarray[Number],y:np.ndarray[Number]) -> np.ndarray[ @obrigar_tipos def recebe_array_de_medidas(x:np.ndarray[lab.Medida])-> np.ndarray[Number]: return np.array([1,2,3,4,5]) - medidas=lab.linspace(1,10,10,3,'m') + medidas=lab.linspaceM(1,10,10,3,'m') recebe_array_de_medidas(medidas) with pytest.raises(TypeError):recebe_array_de_medidas(np.array([1,2,3,4,5])) with pytest.raises(TypeError):recebe_array_de_medidas(medidas.tolist()) @@ -82,7 +82,7 @@ def multiplicacao_union(x: Number | lab.Medida, y: Number | lab.Medida) -> Numbe multiplicacao_union(1, 2) multiplicacao_union(Fraction(1, 2), 2) multiplicacao_union(Decimal('0.5'), 1) - medidas = lab.linspace(1, 10, 10, 3, 'm') + medidas = lab.linspaceM(1, 10, 10, 3, 'm') multiplicacao_union(medidas[0], medidas[1]) multiplicacao_union(1, medidas[0]) @@ -102,7 +102,7 @@ def mult_arrays_union(x: np.ndarray[Number] | np.ndarray[lab.Medida], y = np.array([4, 5, 6]) mult_arrays_union(x, y) - medidas = lab.linspace(1, 10, 10, 3, 'm') + medidas = lab.linspaceM(1, 10, 10, 3, 'm') mult_arrays_union(medidas, medidas) mult_arrays_union(3*medidas, medidas) @@ -119,7 +119,7 @@ def test_ndarray_medida_any(): def recebe_array_medida_any(x: np.ndarray[lab.Medida,Any]) -> np.ndarray[Number]: return np.array([1, 2, 3, 4, 5]) - medidas = lab.linspace(1, 10, 10, 3, 'm') + medidas = lab.linspaceM(1, 10, 10, 3, 'm') recebe_array_medida_any(medidas) with pytest.raises(TypeError): recebe_array_medida_any(np.array([1, 2, 3, 4, 5])) with pytest.raises(TypeError): recebe_array_medida_any(medidas.tolist()) \ No newline at end of file