Skip to content

Commit

Permalink
Updated to use Python instead of Matlab
Browse files Browse the repository at this point in the history
  • Loading branch information
juangburgos committed Mar 7, 2024
1 parent a69f474 commit 7288dbc
Show file tree
Hide file tree
Showing 1,818 changed files with 134,646 additions and 44 deletions.
59 changes: 15 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,27 @@
# Fit Sum of Exponentials

Repo to license code for fitting a sum of exponentials as described in:

https://math.stackexchange.com/questions/1428566/fit-sum-of-exponentials/3808325#3808325

It applies for `n` exponentials and variations as described in the link above.

For example, a 4 exponential fit:

```matlab
clear all;
clc;
% get data
dx = 0.02;
x = (dx:dx:1.5)';
y = 5*exp(0.5*x) + 4*exp(-3*x) + 2*exp(-2*x) - 3*exp(0.15*x);
% calculate integrals
iy1 = cumtrapz(x, y);
iy2 = cumtrapz(x, iy1);
iy3 = cumtrapz(x, iy2);
iy4 = cumtrapz(x, iy3);
% get exponentials lambdas
Y = [iy1, iy2, iy3, iy4, x.^3, x.^2, x, ones(size(x))];
A = pinv(Y)*y;
lambdas = eig([A(1), A(2), A(3), A(4); 1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0]);
lambdas
%lambdas =
% -2.9991
% -1.9997
% 0.5000
% 0.1500
% get exponentials multipliers
X = [exp(lambdas(1)*x), exp(lambdas(2)*x), exp(lambdas(3)*x), exp(lambdas(4)*x)];
P = pinv(X)*y;
P
%P =
% 4.0042
% 1.9955
% 4.9998
% -2.9996
```
The [files](./site/files) directory contains a collection of **Python** scripts that implement the method proposed in this [stackexchange answer](https://math.stackexchange.com/questions/1428566/fit-sum-of-exponentials/3808325#3808325) to fit data to a sum of exponentials with an arbitrary number of exponential terms.

This repo also contains a static [jupyterlite](https://jupyterlite.readthedocs.io) website with a custom [pyodide](https://pyodide.org) kernel and the [PyArma](https://pyarma.sourceforge.io) Python module compiled for [webassembly](https://webassembly.org).

The website available at [**juangburgos.github.io/FitSumExponentials**](http://juangburgos.github.io/FitSumExponentials) allows to run the Python scripts in an _interactive_ Python environment that requires zero installation and no backend server, and it runs in almost all modern web browsers and devices.

Kudos to the _jupyterlite_, _pyodide_ and _PyArma_ guys for making this possible.

## Old Matlab Code

Before using Python and PyArma for exponentials the fit method implementation, there was a Matlab version, which was was available in an interactive online environment provided by [OctaveOnline](https://octave-online.net). Sadly, OctaveOnline decided to delete all my saved and shared scripts without any notification, which motivated me to create this static wbesite.

The old Matlab scripts can be accessed in the [matlab](./matlab) directory.

---

# License

MIT license.

Only for the files in the [files](./site/files) and [matlab](./matlab) directories, the rest of the site files have licenses that belong to their own projects (_jupyterlite_, _pyodide_ and _PyArma_).

Copyright (c) 2020 - forever Juan Gonzalez Burgos

---
Expand Down
113 changes: 113 additions & 0 deletions docs/api/contents/all.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{
"content": [
{
"content": null,
"created": "2024-03-07T11:11:36.521000Z",
"format": null,
"hash": null,
"hash_algorithm": null,
"last_modified": "2024-03-06T14:45:36.457000Z",
"mimetype": null,
"name": "05_Unknown_Number_Of_Exponentials.ipynb",
"path": "05_Unknown_Number_Of_Exponentials.ipynb",
"size": 4633,
"type": "notebook",
"writable": true
},
{
"content": null,
"created": "2024-03-07T11:11:36.525000Z",
"format": null,
"hash": null,
"hash_algorithm": null,
"last_modified": "2024-03-06T14:45:36.457000Z",
"mimetype": null,
"name": "06_With_Two_Independent_Variables.ipynb",
"path": "06_With_Two_Independent_Variables.ipynb",
"size": 6852,
"type": "notebook",
"writable": true
},
{
"content": null,
"created": "2024-03-07T11:11:36.517000Z",
"format": null,
"hash": null,
"hash_algorithm": null,
"last_modified": "2024-03-06T14:45:36.481000Z",
"mimetype": null,
"name": "01_Fit_Data_To_N_Exponentials.ipynb",
"path": "01_Fit_Data_To_N_Exponentials.ipynb",
"size": 5094,
"type": "notebook",
"writable": true
},
{
"content": null,
"created": "2024-03-07T11:11:36.525000Z",
"format": null,
"hash": null,
"hash_algorithm": null,
"last_modified": "2024-03-06T14:45:44.757000Z",
"mimetype": "text/x-python",
"name": "pyarma_utils.py",
"path": "pyarma_utils.py",
"size": 347,
"type": "file",
"writable": true
},
{
"content": null,
"created": "2024-03-07T11:11:36.521000Z",
"format": null,
"hash": null,
"hash_algorithm": null,
"last_modified": "2024-03-06T14:45:36.437000Z",
"mimetype": null,
"name": "04_With_Exp_Multiplied_By_X.ipynb",
"path": "04_With_Exp_Multiplied_By_X.ipynb",
"size": 3260,
"type": "notebook",
"writable": true
},
{
"content": null,
"created": "2024-03-07T11:11:36.521000Z",
"format": null,
"hash": null,
"hash_algorithm": null,
"last_modified": "2024-03-06T14:45:36.417000Z",
"mimetype": null,
"name": "03_With_Sine_Cosine_Terms.ipynb",
"path": "03_With_Sine_Cosine_Terms.ipynb",
"size": 3754,
"type": "notebook",
"writable": true
},
{
"content": null,
"created": "2024-03-07T11:11:36.517000Z",
"format": null,
"hash": null,
"hash_algorithm": null,
"last_modified": "2024-03-06T14:45:36.481000Z",
"mimetype": null,
"name": "02_With_Additive_Constant_Term.ipynb",
"path": "02_With_Additive_Constant_Term.ipynb",
"size": 3265,
"type": "notebook",
"writable": true
}
],
"created": "2024-03-07T11:11:36.525000Z",
"format": "json",
"hash": null,
"hash_algorithm": null,
"last_modified": "2024-03-07T11:11:36.525000Z",
"mimetype": null,
"name": "",
"path": "",
"size": null,
"type": "directory",
"writable": true
}
9 changes: 9 additions & 0 deletions docs/api/translations/all.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"data": {
"en": {
"displayName": "English",
"nativeName": "English"
}
},
"message": ""
}
4 changes: 4 additions & 0 deletions docs/api/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"data": {},
"message": ""
}
93 changes: 93 additions & 0 deletions docs/bootstrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*-----------------------------------------------------------------------------
| Copyright (c) Jupyter Development Team.
| Distributed under the terms of the Modified BSD License.
|----------------------------------------------------------------------------*/

// We copy some of the pageconfig parsing logic in @jupyterlab/coreutils
// below, since this must run before any other files are loaded (including
// @jupyterlab/coreutils).

/**
* Get global configuration data for the Jupyter application.
*
* @param name - The name of the configuration option.
*
* @returns The config value or an empty string if not found.
*
* #### Notes
* All values are treated as strings. For browser based applications, it is
* assumed that the page HTML includes a script tag with the id
* `jupyter-config-data` containing the configuration as valid JSON.
*/

let _CONFIG_DATA = null;
function getOption(name) {
if (_CONFIG_DATA === null) {
let configData = {};
// Use script tag if available.
if (typeof document !== 'undefined' && document) {
const el = document.getElementById('jupyter-config-data');

if (el) {
configData = JSON.parse(el.textContent || '{}');
}
}
_CONFIG_DATA = configData;
}

return _CONFIG_DATA[name] || '';
}

// eslint-disable-next-line no-undef
__webpack_public_path__ = getOption('fullStaticUrl') + '/';

function loadScript(url) {
return new Promise((resolve, reject) => {
const newScript = document.createElement('script');
newScript.onerror = reject;
newScript.onload = resolve;
newScript.async = true;
document.head.appendChild(newScript);
newScript.src = url;
});
}

async function loadComponent(url, scope) {
await loadScript(url);

// From https://webpack.js.org/concepts/module-federation/#dynamic-remote-containers
await __webpack_init_sharing__('default');
const container = window._JUPYTERLAB[scope];
// Initialize the container, it may provide shared modules and may need ours
await container.init(__webpack_share_scopes__.default);
}

void (async function bootstrap() {
// This is all the data needed to load and activate plugins. This should be
// gathered by the server and put onto the initial page template.
const extension_data = getOption('federated_extensions');

// We first load all federated components so that the shared module
// deduplication can run and figure out which shared modules from all
// components should be actually used. We have to do this before importing
// and using the module that actually uses these components so that all
// dependencies are initialized.
let labExtensionUrl = getOption('fullLabextensionsUrl');
const extensions = await Promise.allSettled(
extension_data.map(async data => {
await loadComponent(`${labExtensionUrl}/${data.name}/${data.load}`, data.name);
})
);

extensions.forEach(p => {
if (p.status === 'rejected') {
// There was an error loading the component
console.error(p.reason);
}
});

// Now that all federated containers are initialized with the main
// container, we can import the main function.
let main = (await import('./index.js')).main;
void main();
})();
2 changes: 2 additions & 0 deletions docs/build/1053.7a56130.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/build/1053.7a56130.js.map

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docs/build/1088.33c6076.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 7288dbc

Please sign in to comment.