BicycleParameters 1.1.0__tar.gz → 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0/BicycleParameters.egg-info}/PKG-INFO +11 -3
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/BicycleParameters.egg-info/SOURCES.txt +1 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/CHANGELOG.rst +24 -0
- {bicycleparameters-1.1.0/BicycleParameters.egg-info → bicycleparameters-1.2.0}/PKG-INFO +11 -3
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/README.rst +4 -1
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/RELEASE.rst +2 -2
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/com.py +1 -1
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/geometry.py +2 -2
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/inertia.py +1 -1
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/io.py +16 -16
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/main.py +21 -32
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/models.py +29 -6
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/period.py +46 -59
- bicycleparameters-1.2.0/bicycleparameters/tests/test_io.py +26 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/version.py +1 -1
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/docs/data.rst +26 -4
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/docs/examples.rst +14 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/setup.py +9 -1
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/AUTHORS +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/BicycleParameters.egg-info/dependency_links.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/BicycleParameters.egg-info/entry_points.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/BicycleParameters.egg-info/requires.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/BicycleParameters.egg-info/top_level.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/LICENSE.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/MANIFEST.in +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/__init__.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app-data/bicycles/Benchmark/Parameters/BenchmarkBenchmark.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app-data/bicycles/Browser/Parameters/BrowserBenchmark.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app-data/bicycles/Browserins/Parameters/BrowserinsBenchmark.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app-data/bicycles/Crescendo/Parameters/CrescendoBenchmark.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app-data/bicycles/Fisher/Parameters/FisherBenchmark.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app-data/bicycles/Pista/Parameters/PistaBenchmark.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app-data/bicycles/Rigid/Parameters/RigidBenchmark.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app-data/bicycles/Silver/Parameters/SilverBenchmark.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app-data/bicycles/Yellow/Parameters/YellowBenchmark.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app-data/bicycles/Yellowrev/Parameters/YellowrevBenchmark.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/app.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/assets/app-explanation.md +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/assets/styles.css +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/bicycle.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/conversions.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/parameter_dicts.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/parameter_sets.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/plot.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/rider.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tables.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/__init__.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/parameter_sets/benchmark-benchmark.yml +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/parameter_sets/benchmark-browser.yml +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/parameter_sets/benchmark-extendedoptc.yml +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/parameter_sets/benchmark-pista.yml +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/parameter_sets/benchmark-pistarider.yml +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/parameter_sets/benchmark-pistarideroptimized3ms.yml +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/parameter_sets/benchmark-realizedopttwo.yml +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/parameter_sets/principal-browserjason.yml +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/parameter_sets/principal-extendedoptf.yml +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/test_bicycle.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/test_bicycleparameters.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/test_models.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/test_parameter_sets.py +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/docs/app.rst +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/docs/bicycleparameters.rst +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/docs/description.rst +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/docs/index.rst +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/docs/installation.rst +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/requirements.txt +0 -0
- {bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/setup.cfg +0 -0
@@ -1,17 +1,22 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: BicycleParameters
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.2.0
|
4
4
|
Summary: Generates and manipulates the physical parameters of a bicycle.
|
5
5
|
Home-page: http://pypi.python.org/pypi/BicycleParameters
|
6
|
-
Author: Jason
|
6
|
+
Author: Jason K. Moore
|
7
7
|
Author-email: moorepants@gmail.com
|
8
8
|
License: LICENSE.txt
|
9
|
+
Project-URL: Web Application, https://bicycle-dynamics.onrender.com
|
10
|
+
Project-URL: Documentation, http://bicycleparameters.readthedocs.io
|
11
|
+
Project-URL: Source Code, https://github.com/moorepants/BicycleParameters
|
12
|
+
Project-URL: Issue Tracker, https://github.com/moorepants/BicycleParameters/issues
|
9
13
|
Classifier: Programming Language :: Python
|
10
14
|
Classifier: Programming Language :: Python :: 3.8
|
11
15
|
Classifier: Programming Language :: Python :: 3.9
|
12
16
|
Classifier: Programming Language :: Python :: 3.10
|
13
17
|
Classifier: Programming Language :: Python :: 3.11
|
14
18
|
Classifier: Programming Language :: Python :: 3.12
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
15
20
|
Classifier: Operating System :: OS Independent
|
16
21
|
Classifier: Development Status :: 5 - Production/Stable
|
17
22
|
Classifier: Intended Audience :: Science/Research
|
@@ -55,7 +60,7 @@ of the Whipple-Carvallo bicycle model.
|
|
55
60
|
* - CI Status
|
56
61
|
- |GHCI|
|
57
62
|
* - Render App
|
58
|
-
-
|
63
|
+
- |Render|
|
59
64
|
|
60
65
|
.. |PyPi| image:: https://img.shields.io/pypi/v/BicycleParameters.svg
|
61
66
|
:target: https://pypi.org/project/BicycleParameters/
|
@@ -69,6 +74,9 @@ of the Whipple-Carvallo bicycle model.
|
|
69
74
|
:target: https://bicycleparameters.readthedocs.io/en/latest/?badge=latest
|
70
75
|
:alt: Documentation Status
|
71
76
|
|
77
|
+
.. |Render| image:: https://img.shields.io/badge/Bicycle_Dynamics_App-Render.io-blue
|
78
|
+
:target: https://bicycle-dynamics.onrender.com
|
79
|
+
|
72
80
|
Dependencies
|
73
81
|
============
|
74
82
|
|
@@ -44,6 +44,7 @@ bicycleparameters/assets/styles.css
|
|
44
44
|
bicycleparameters/tests/__init__.py
|
45
45
|
bicycleparameters/tests/test_bicycle.py
|
46
46
|
bicycleparameters/tests/test_bicycleparameters.py
|
47
|
+
bicycleparameters/tests/test_io.py
|
47
48
|
bicycleparameters/tests/test_models.py
|
48
49
|
bicycleparameters/tests/test_parameter_sets.py
|
49
50
|
bicycleparameters/tests/parameter_sets/benchmark-benchmark.yml
|
@@ -1,6 +1,30 @@
|
|
1
1
|
Release Notes
|
2
2
|
=============
|
3
3
|
|
4
|
+
1.2.0
|
5
|
+
-----
|
6
|
+
|
7
|
+
- Support Python 3.13.
|
8
|
+
- Revert to ``unumpy.matrix`` in mass center and inertia calculations.
|
9
|
+
- Updated the raw data mat file loading to work with current Python versions.
|
10
|
+
- Support raw data pendulum measurement files with time as an array as well as
|
11
|
+
a fixed sample rate (as before).
|
12
|
+
- Remove the unnecessary ``__new__`` method from ``Bicycle``.
|
13
|
+
- Added options to show stable ranges and to hide zero eigenvalues in the
|
14
|
+
``Model`` eigenvalues parts plot.
|
15
|
+
- Skip data truncation on raw pendulum time series that have the explicit time
|
16
|
+
array (this is a hack for the Balanceassistv1 data to have valid handlebar
|
17
|
+
inertia).
|
18
|
+
- Modernized some internal plotting code.
|
19
|
+
- Added measured and calculated parameter data for the Balanceassistv1 bike we
|
20
|
+
measured in the summer of 2024. This is a Gazelle Grenoble C8 HMB electric
|
21
|
+
bicycle with a custom headtube with a steering motor.
|
22
|
+
|
23
|
+
1.1.1
|
24
|
+
-----
|
25
|
+
|
26
|
+
- Ensure that the app's data files are installed.
|
27
|
+
|
4
28
|
1.1.0
|
5
29
|
-----
|
6
30
|
|
@@ -1,17 +1,22 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: BicycleParameters
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.2.0
|
4
4
|
Summary: Generates and manipulates the physical parameters of a bicycle.
|
5
5
|
Home-page: http://pypi.python.org/pypi/BicycleParameters
|
6
|
-
Author: Jason
|
6
|
+
Author: Jason K. Moore
|
7
7
|
Author-email: moorepants@gmail.com
|
8
8
|
License: LICENSE.txt
|
9
|
+
Project-URL: Web Application, https://bicycle-dynamics.onrender.com
|
10
|
+
Project-URL: Documentation, http://bicycleparameters.readthedocs.io
|
11
|
+
Project-URL: Source Code, https://github.com/moorepants/BicycleParameters
|
12
|
+
Project-URL: Issue Tracker, https://github.com/moorepants/BicycleParameters/issues
|
9
13
|
Classifier: Programming Language :: Python
|
10
14
|
Classifier: Programming Language :: Python :: 3.8
|
11
15
|
Classifier: Programming Language :: Python :: 3.9
|
12
16
|
Classifier: Programming Language :: Python :: 3.10
|
13
17
|
Classifier: Programming Language :: Python :: 3.11
|
14
18
|
Classifier: Programming Language :: Python :: 3.12
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
15
20
|
Classifier: Operating System :: OS Independent
|
16
21
|
Classifier: Development Status :: 5 - Production/Stable
|
17
22
|
Classifier: Intended Audience :: Science/Research
|
@@ -55,7 +60,7 @@ of the Whipple-Carvallo bicycle model.
|
|
55
60
|
* - CI Status
|
56
61
|
- |GHCI|
|
57
62
|
* - Render App
|
58
|
-
-
|
63
|
+
- |Render|
|
59
64
|
|
60
65
|
.. |PyPi| image:: https://img.shields.io/pypi/v/BicycleParameters.svg
|
61
66
|
:target: https://pypi.org/project/BicycleParameters/
|
@@ -69,6 +74,9 @@ of the Whipple-Carvallo bicycle model.
|
|
69
74
|
:target: https://bicycleparameters.readthedocs.io/en/latest/?badge=latest
|
70
75
|
:alt: Documentation Status
|
71
76
|
|
77
|
+
.. |Render| image:: https://img.shields.io/badge/Bicycle_Dynamics_App-Render.io-blue
|
78
|
+
:target: https://bicycle-dynamics.onrender.com
|
79
|
+
|
72
80
|
Dependencies
|
73
81
|
============
|
74
82
|
|
@@ -16,7 +16,7 @@ of the Whipple-Carvallo bicycle model.
|
|
16
16
|
* - CI Status
|
17
17
|
- |GHCI|
|
18
18
|
* - Render App
|
19
|
-
-
|
19
|
+
- |Render|
|
20
20
|
|
21
21
|
.. |PyPi| image:: https://img.shields.io/pypi/v/BicycleParameters.svg
|
22
22
|
:target: https://pypi.org/project/BicycleParameters/
|
@@ -30,6 +30,9 @@ of the Whipple-Carvallo bicycle model.
|
|
30
30
|
:target: https://bicycleparameters.readthedocs.io/en/latest/?badge=latest
|
31
31
|
:alt: Documentation Status
|
32
32
|
|
33
|
+
.. |Render| image:: https://img.shields.io/badge/Bicycle_Dynamics_App-Render.io-blue
|
34
|
+
:target: https://bicycle-dynamics.onrender.com
|
35
|
+
|
33
36
|
Dependencies
|
34
37
|
============
|
35
38
|
|
@@ -2,11 +2,11 @@ These are the instructions for updating the package.
|
|
2
2
|
|
3
3
|
1. Merge all commits from changes.
|
4
4
|
2. Update the version info in the README
|
5
|
-
3. Update the version number in bicycleparameters.
|
5
|
+
3. Update the version number in bicycleparameters/version.py
|
6
6
|
4. Update the version number in docs/conf.py.
|
7
7
|
5. Make sure the docs build.
|
8
8
|
6. Git tag for the new version.
|
9
|
-
7. python setup.py
|
9
|
+
7. python setup.py register sdist upload
|
10
10
|
8. Upload the Documentation files.
|
11
11
|
|
12
12
|
- cd docs/_build/html
|
@@ -91,7 +91,7 @@ def center_of_mass(slopes, intercepts):
|
|
91
91
|
# for each line intersection...
|
92
92
|
for j, row in enumerate(comb):
|
93
93
|
sl = np.array([slopes[row[0]], slopes[row[1]]])
|
94
|
-
a = unumpy.
|
94
|
+
a = unumpy.matrix(np.vstack((-sl, np.ones((2)))).T)
|
95
95
|
b = np.array([intercepts[row[0]], intercepts[row[1]]])
|
96
96
|
lineX[j] = np.dot(a.I, b)
|
97
97
|
com = np.mean(lineX, axis=0)
|
@@ -82,11 +82,11 @@ def calculate_abc_geometry(h, d):
|
|
82
82
|
'''
|
83
83
|
# extract the values
|
84
84
|
h1, h2, h3, h4, h5 = h
|
85
|
-
d1, d2, d3, d4,
|
85
|
+
d1, d2, d3, d4, d_ = d
|
86
86
|
# get the perpendicular distances
|
87
87
|
a = h1 + h2 - h3 + .5 * d1 - .5 * d2
|
88
88
|
b = h4 - .5 * d3 - h5 + .5 * d4
|
89
|
-
c = umath.sqrt(-(a - b)**2 + (
|
89
|
+
c = umath.sqrt(-(a - b)**2 + (d_ + .5 * (d2 + d3))**2)
|
90
90
|
return a, b, c
|
91
91
|
|
92
92
|
|
@@ -114,7 +114,7 @@ def inertia_components(jay, beta):
|
|
114
114
|
'''
|
115
115
|
sb = unumpy.sin(beta)
|
116
116
|
cb = unumpy.cos(beta)
|
117
|
-
betaMat = unumpy.
|
117
|
+
betaMat = unumpy.matrix(np.vstack((cb**2, -2 * sb * cb, sb**2)).T)
|
118
118
|
eye = np.squeeze(np.asarray(np.dot(betaMat.I, jay)))
|
119
119
|
return eye
|
120
120
|
|
@@ -79,23 +79,23 @@ def load_pendulum_mat_file(pathToFile):
|
|
79
79
|
|
80
80
|
'''
|
81
81
|
pendDat = {}
|
82
|
-
loadmat(pathToFile, mdict=pendDat)
|
82
|
+
loadmat(pathToFile, mdict=pendDat, squeeze_me=True, chars_as_strings=True)
|
83
83
|
# clean up the matlab imports
|
84
|
-
del
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
84
|
+
del pendDat['__globals__']
|
85
|
+
del pendDat['__header__']
|
86
|
+
del pendDat['__version__']
|
87
|
+
# If notes is empty it loads like `array([], dtype='<U1')`, so make it an
|
88
|
+
# empty string.
|
89
|
+
if not isinstance(pendDat['notes'], str):
|
90
|
+
if pendDat['notes'].shape == (0,):
|
91
|
+
pendDat['notes'] = ''
|
92
|
+
# If a time array is present, it may be variable sample rate so delete the
|
93
|
+
# sampleRate and duration entries if they are there.
|
94
|
+
if 'time' in pendDat:
|
95
|
+
if 'sampleRate' in pendDat:
|
96
|
+
del pendDat['sampleRate']
|
97
|
+
if 'duration' in pendDat:
|
98
|
+
del pendDat['duration']
|
99
99
|
return pendDat
|
100
100
|
|
101
101
|
|
@@ -40,29 +40,7 @@ class Bicycle(object):
|
|
40
40
|
|
41
41
|
"""
|
42
42
|
|
43
|
-
def
|
44
|
-
forcePeriodCalc=False):
|
45
|
-
'''Returns a NoneType object if there is no directory for the
|
46
|
-
bicycle.'''
|
47
|
-
# is there a data directory for this bicycle? if not, tell the user to
|
48
|
-
# put some data in the folder so we have something to work with!
|
49
|
-
try:
|
50
|
-
pathToBicycle = os.path.join(pathToData, 'bicycles', bicycleName)
|
51
|
-
if os.path.isdir(pathToBicycle):
|
52
|
-
print("We have foundeth a directory named: " +
|
53
|
-
"{0}.".format(pathToBicycle))
|
54
|
-
return super(Bicycle, cls).__new__(cls)
|
55
|
-
else:
|
56
|
-
raise ValueError
|
57
|
-
except:
|
58
|
-
mes = """Are you nuts?! Make a directory called '{0}' with basic
|
59
|
-
data for your bicycle in this directory: '{1}'. Then I can actually create a
|
60
|
-
bicycle object. You may either need to change to the correct directory or reset
|
61
|
-
the pathToData argument.""".format(bicycleName, pathToData)
|
62
|
-
print(mes)
|
63
|
-
return None
|
64
|
-
|
65
|
-
def __init__(self, bicycleName, pathToData='.', forceRawCalc=False,
|
43
|
+
def __init__(self, bicycleName, pathToData=os.curdir, forceRawCalc=False,
|
66
44
|
forcePeriodCalc=False):
|
67
45
|
"""
|
68
46
|
Creates a bicycle object and sets the parameters based on the available
|
@@ -73,8 +51,8 @@ the pathToData argument.""".format(bicycleName, pathToData)
|
|
73
51
|
bicycleName : string
|
74
52
|
The short name of your bicicleta. It should be one word with the
|
75
53
|
first letter capitalized and all other letters lower case. You
|
76
|
-
should have a matching directory under
|
77
|
-
For example:
|
54
|
+
should have a matching directory under ``<pathToData>/bicycles/``.
|
55
|
+
For example: ``<pathToData>/bicycles/Shortname``.
|
78
56
|
pathToData : string
|
79
57
|
This is the path to the folder where the bicycle/rider parameters
|
80
58
|
and raw data are stored. The default is the current working
|
@@ -96,6 +74,7 @@ the pathToData argument.""".format(bicycleName, pathToData)
|
|
96
74
|
pathToBicycles = os.path.join(pathToData, 'bicycles')
|
97
75
|
# the directory where the files for this bicycle are stored
|
98
76
|
self.directory = os.path.join(pathToBicycles, bicycleName)
|
77
|
+
self._check_for_bicycle_directory()
|
99
78
|
|
100
79
|
# bicycles are assumed not to have a rider when initially loaded
|
101
80
|
self.hasRider = False
|
@@ -145,7 +124,7 @@ the pathToData argument.""".format(bicycleName, pathToData)
|
|
145
124
|
if conOne or conTwo:
|
146
125
|
print("Recalcuting the parameters.")
|
147
126
|
par, extras = self.calculate_from_measured(
|
148
|
-
|
127
|
+
forcePeriodCalc=forcePeriodCalc)
|
149
128
|
self.parameters['Benchmark'] = par
|
150
129
|
self.extras = extras
|
151
130
|
print("The glory of the %s parameters are upon you!"
|
@@ -160,7 +139,7 @@ the pathToData argument.""".format(bicycleName, pathToData)
|
|
160
139
|
'Measured.txt')
|
161
140
|
try:
|
162
141
|
self.parameters['Measured'] = \
|
163
|
-
|
142
|
+
io.load_parameter_text_file(pathToRawFile)
|
164
143
|
except IOError:
|
165
144
|
pass
|
166
145
|
else:
|
@@ -169,6 +148,17 @@ the pathToData argument.""".format(bicycleName, pathToData)
|
|
169
148
|
bicycle/{sn}/RawData/ with pendulum data mat files and the
|
170
149
|
{sn}Measured.txt file'''.format(sn=bicycleName))
|
171
150
|
|
151
|
+
def _check_for_bicycle_directory(self):
|
152
|
+
# is there a data directory for this bicycle? if not, tell the user to
|
153
|
+
# put some data in the folder so we have something to work with!
|
154
|
+
msg = ("Are you nuts?! Make a directory called '{0}' with basic data "
|
155
|
+
"for your bicycle in this directory: '{1}'. Then I can "
|
156
|
+
"actually create a bicycle object. You may either need to "
|
157
|
+
"change to the correct directory or reset the pathToData "
|
158
|
+
"argument.")
|
159
|
+
if not os.path.isdir(self.directory):
|
160
|
+
raise ValueError(msg.format(self.bicycleName, self.directory))
|
161
|
+
|
172
162
|
def __str__(self):
|
173
163
|
if self.hasRider:
|
174
164
|
desc = "{0} with {1} on board.".format(self.bicycleName,
|
@@ -1171,7 +1161,7 @@ the pathToData argument.""".format(bicycleName, pathToData)
|
|
1171
1161
|
|
1172
1162
|
Parameters
|
1173
1163
|
----------
|
1174
|
-
speeds :
|
1164
|
+
speeds : array_like, shape (n,) or float
|
1175
1165
|
The speed at which to calculate the eigenvalues.
|
1176
1166
|
|
1177
1167
|
Returns
|
@@ -1188,11 +1178,10 @@ the pathToData argument.""".format(bicycleName, pathToData)
|
|
1188
1178
|
model.
|
1189
1179
|
|
1190
1180
|
'''
|
1191
|
-
|
1192
|
-
try:
|
1193
|
-
speeds.shape
|
1194
|
-
except AttributeError:
|
1181
|
+
if isinstance(speeds, float):
|
1195
1182
|
speeds = np.array([speeds])
|
1183
|
+
else:
|
1184
|
+
speeds = np.asarray(speeds)
|
1196
1185
|
|
1197
1186
|
par = io.remove_uncertainties(self.parameters['Benchmark'])
|
1198
1187
|
|
@@ -20,7 +20,7 @@ class _Model(ABC):
|
|
20
20
|
|
21
21
|
|
22
22
|
class Meijaard2007Model(_Model):
|
23
|
-
"""Whipple
|
23
|
+
"""Carvallo-Whipple model presented in [Meijaard2007]_. It is both linear
|
24
24
|
and the minimal model in terms of states and coordinates that fully
|
25
25
|
describe the vehicle's dynamics: self-stability and non-minimum phase
|
26
26
|
behavior.
|
@@ -549,6 +549,7 @@ class Meijaard2007Model(_Model):
|
|
549
549
|
return axes
|
550
550
|
|
551
551
|
def plot_eigenvalue_parts(self, ax=None, colors=None,
|
552
|
+
show_stable_regions=True, hide_zeros=False,
|
552
553
|
**parameter_overrides):
|
553
554
|
"""Returns a matplotlib axis of the real and imaginary parts of the
|
554
555
|
eigenvalues plotted against the provided parameter.
|
@@ -559,6 +560,11 @@ class Meijaard2007Model(_Model):
|
|
559
560
|
Matplotlib axes.
|
560
561
|
colors : sequence, len(4)
|
561
562
|
Matplotlib colors for the 4 modes.
|
563
|
+
show_stable_regions : boolean, optional
|
564
|
+
If true, a grey shaded background will indicate stable regions.
|
565
|
+
hide_zeros : boolean or float, optional
|
566
|
+
If true, real or imaginary parts that are smaller than 1e-12 will
|
567
|
+
not be plotted. Providing a float will set the tolerance.
|
562
568
|
**parameter_overrides : dictionary
|
563
569
|
Parameter keys that map to floats or array_like of floats
|
564
570
|
shape(n,). All keys that map to array_like must be of the same
|
@@ -588,7 +594,9 @@ class Meijaard2007Model(_Model):
|
|
588
594
|
if len(evals.shape) > 1:
|
589
595
|
evals, evecs = sort_eigenmodes(evals, evecs)
|
590
596
|
else:
|
591
|
-
evals, evecs = [evals], [evecs]
|
597
|
+
evals, evecs = np.array([evals]), np.array([evecs])
|
598
|
+
|
599
|
+
tol = hide_zeros if isinstance(hide_zeros, float) else 1e-12
|
592
600
|
|
593
601
|
par, array_keys, _ = self._parse_parameter_overrides(
|
594
602
|
**parameter_overrides)
|
@@ -597,15 +605,30 @@ class Meijaard2007Model(_Model):
|
|
597
605
|
colors = ['C0', 'C1', 'C2', 'C3']
|
598
606
|
legend = ['Mode 1', 'Mode 2', 'Mode 3', 'Mode 4',
|
599
607
|
'Mode 1', 'Mode 2', 'Mode 3', 'Mode 4']
|
608
|
+
|
609
|
+
if show_stable_regions:
|
610
|
+
ax.fill_between(par[array_keys[0]],
|
611
|
+
np.min([np.min(evals.real), np.min(evals.imag)]),
|
612
|
+
np.max([np.max(evals.real), np.max(evals.imag)]),
|
613
|
+
where=np.all(evals.real < 0.0, axis=1),
|
614
|
+
color='grey',
|
615
|
+
alpha=0.25,
|
616
|
+
transform=ax.get_xaxis_transform())
|
617
|
+
|
600
618
|
# imaginary components
|
601
619
|
for eval_sequence, color, label in zip(evals.T, colors, legend):
|
602
|
-
|
603
|
-
|
620
|
+
imag_vals = np.abs(np.imag(eval_sequence))
|
621
|
+
if hide_zeros:
|
622
|
+
imag_vals[np.abs(imag_vals) < tol] = np.nan
|
623
|
+
ax.plot(par[array_keys[0]], imag_vals, color=color, label=label,
|
624
|
+
linestyle='--')
|
604
625
|
|
605
626
|
# plot the real parts of the eigenvalues
|
606
627
|
for eval_sequence, color, label in zip(evals.T, colors, legend):
|
607
|
-
|
608
|
-
|
628
|
+
real_vals = np.real(eval_sequence)
|
629
|
+
if hide_zeros:
|
630
|
+
real_vals[np.abs(real_vals) < tol] = np.nan
|
631
|
+
ax.plot(par[array_keys[0]], real_vals, color=color, label=label)
|
609
632
|
|
610
633
|
# set labels and limits
|
611
634
|
ax.set_ylabel('Real and Imaginary Parts of the Eigenvalue [1/s]')
|
@@ -87,22 +87,9 @@ def calc_periods_for_files(directory, filenames, forkIsSplit):
|
|
87
87
|
|
88
88
|
periods = {}
|
89
89
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
while True:
|
94
|
-
(path, tail) = os.path.split(path)
|
95
|
-
if tail == "":
|
96
|
-
components.reverse()
|
97
|
-
return components
|
98
|
-
components.append(tail)
|
99
|
-
|
100
|
-
pathToRawDataParts = pathParts(directory)
|
101
|
-
pathToRawDataParts.pop()
|
102
|
-
pathToBicycleDir = os.path.join(pathToRawDataParts[0],
|
103
|
-
pathToRawDataParts[1],
|
104
|
-
pathToRawDataParts[2])
|
105
|
-
pathToPlotDir = os.path.join(pathToBicycleDir, 'Plots', 'PendulumFit')
|
90
|
+
# directory is /path/to/data/bicycles/BikeName/RawData
|
91
|
+
path_to_bicycle_dir = os.sep.join(directory.split(os.sep)[:-1])
|
92
|
+
pathToPlotDir = os.path.join(path_to_bicycle_dir, 'Plots', 'PendulumFit')
|
106
93
|
|
107
94
|
# make sure there is a place to save the plots
|
108
95
|
if not os.path.exists(pathToPlotDir):
|
@@ -116,12 +103,17 @@ def calc_periods_for_files(directory, filenames, forkIsSplit):
|
|
116
103
|
# generate a variable name for this period
|
117
104
|
periodKey = get_period_key(matData, forkIsSplit)
|
118
105
|
# calculate the period
|
119
|
-
sampleRate = get_sample_rate(matData)
|
120
106
|
pathToPlotFile = os.path.join(pathToPlotDir,
|
121
107
|
os.path.splitext(f)[0] + '.png')
|
122
|
-
|
123
|
-
|
124
|
-
|
108
|
+
if 'time' in matData:
|
109
|
+
period = get_period_from_truncated(matData['data'],
|
110
|
+
matData['time'],
|
111
|
+
pathToPlotFile)
|
112
|
+
else:
|
113
|
+
sampleRate = get_sample_rate(matData)
|
114
|
+
period = get_period_from_truncated(matData['data'],
|
115
|
+
sampleRate,
|
116
|
+
pathToPlotFile)
|
125
117
|
print("The period is:", period, "\n")
|
126
118
|
# either append the the period or if it isn't there yet, then
|
127
119
|
# make a new list
|
@@ -212,16 +204,17 @@ def fit_goodness(ym, yp):
|
|
212
204
|
return rsq, SSE, SST, SSR
|
213
205
|
|
214
206
|
|
215
|
-
def get_period(data,
|
207
|
+
def get_period(data, sample_rate_or_time, pathToPlotFile):
|
216
208
|
'''Returns the period and uncertainty for data resembling a decaying
|
217
209
|
oscillation.
|
218
210
|
|
219
211
|
Parameters
|
220
212
|
----------
|
221
|
-
data :
|
213
|
+
data : array_like, shape(n,)
|
222
214
|
A time series that resembles a decaying oscillation.
|
223
|
-
|
224
|
-
|
215
|
+
sample_rate_or_time : int or array_like, shape(n,)
|
216
|
+
Either the frequency in Hertz that data was sampled at or a time array
|
217
|
+
that corresponds to ``data``.
|
225
218
|
pathToPlotFile : string
|
226
219
|
A path to the file to print the plots.
|
227
220
|
|
@@ -233,7 +226,12 @@ def get_period(data, sampleRate, pathToPlotFile):
|
|
233
226
|
'''
|
234
227
|
|
235
228
|
y = data
|
236
|
-
|
229
|
+
if isinstance(sample_rate_or_time, int):
|
230
|
+
sample_rate = sample_rate_or_time
|
231
|
+
x = np.linspace(0.0, (len(y) - 1)/float(sample_rate), num=len(y))
|
232
|
+
else:
|
233
|
+
x = sample_rate_or_time
|
234
|
+
sample_rate = int(1.0/np.mean(np.diff(x))) # approximate
|
237
235
|
|
238
236
|
def fitfunc(p, t):
|
239
237
|
'''Decaying oscillation function.'''
|
@@ -246,7 +244,7 @@ def get_period(data, sampleRate, pathToPlotFile):
|
|
246
244
|
# initial guesses
|
247
245
|
# p0 = np.array([1.35, -.5, -.75, 0.01, 3.93]) # guess from delft
|
248
246
|
# p0 = np.array([2.5, -.75, -.75, 0.001, 4.3]) # guess from ucd
|
249
|
-
p0 = make_guess(data,
|
247
|
+
p0 = make_guess(data, sample_rate) # tries to make a good guess
|
250
248
|
|
251
249
|
# create the error function
|
252
250
|
errfunc = lambda p, t, y: fitfunc(p, t) - y
|
@@ -284,9 +282,9 @@ def get_period(data, sampleRate, pathToPlotFile):
|
|
284
282
|
T = 1. / fd
|
285
283
|
|
286
284
|
# plot the data and save it to file
|
287
|
-
fig = plt.
|
285
|
+
fig, ax = plt.subplots(layout='constrained')
|
288
286
|
plot_osfit(x, y, lscurve, p1, rsq, T, m=np.max(x), fig=fig)
|
289
|
-
|
287
|
+
fig.savefig(pathToPlotFile)
|
290
288
|
plt.close()
|
291
289
|
|
292
290
|
# return the period
|
@@ -296,7 +294,15 @@ def get_period(data, sampleRate, pathToPlotFile):
|
|
296
294
|
def get_period_from_truncated(data, sampleRate, pathToPlotFile):
|
297
295
|
# dataRec = average_rectified_sections(data)
|
298
296
|
dataRec = data
|
299
|
-
|
297
|
+
# Don't truncate if the time array is provided in the measurements. This is
|
298
|
+
# present because truncating causes bad inertia values for the
|
299
|
+
# Balanceassistv1 fork. This is a bit of a hack. It would be better to have
|
300
|
+
# optional data processing steps per trials to maximize good period
|
301
|
+
# estimates. This is trying to be a catch all as designed.
|
302
|
+
if isinstance(sampleRate, np.ndarray): # time array
|
303
|
+
dataGood = dataRec
|
304
|
+
else:
|
305
|
+
dataGood = select_good_data(dataRec, 0.1)
|
300
306
|
return get_period(dataGood, sampleRate, pathToPlotFile)
|
301
307
|
|
302
308
|
|
@@ -456,7 +462,7 @@ def plot_osfit(t, ym, yf, p, rsq, T, m=None, fig=None):
|
|
456
462
|
The measured voltage
|
457
463
|
yf : ndarray (n,)
|
458
464
|
p : ndarray (5,)
|
459
|
-
The fit parameters for the decaying
|
465
|
+
The fit parameters for the decaying oscillation function.
|
460
466
|
rsq : float
|
461
467
|
The r squared value of y (the fit)
|
462
468
|
T : float
|
@@ -469,38 +475,20 @@ def plot_osfit(t, ym, yf, p, rsq, T, m=None, fig=None):
|
|
469
475
|
fig : the figure
|
470
476
|
|
471
477
|
'''
|
472
|
-
# figure properties
|
473
|
-
figwidth = 4. # in inches
|
474
|
-
goldenMean = (np.sqrt(5) - 1.0) / 2.0
|
475
|
-
figsize = [figwidth, figwidth * goldenMean]
|
476
|
-
params = {#'backend': 'ps',
|
477
|
-
'axes.labelsize': 8,
|
478
|
-
'axes.titlesize': 8,
|
479
|
-
'text.fontsize': 8,
|
480
|
-
'legend.fontsize': 8,
|
481
|
-
'xtick.labelsize': 6,
|
482
|
-
'ytick.labelsize': 6,
|
483
|
-
'text.usetex': True,
|
484
|
-
#'figure.figsize': figsize
|
485
|
-
}
|
486
478
|
if fig:
|
487
|
-
|
479
|
+
ax1 = fig.axes[0]
|
488
480
|
else:
|
489
|
-
fig = plt.
|
490
|
-
|
491
|
-
plt.rcParams.update(params)
|
492
|
-
ax1 = plt.axes([0.125, 0.125, 0.9-0.125, 0.65])
|
493
|
-
#if m == None:
|
494
|
-
#end = len(t)
|
495
|
-
#else:
|
496
|
-
#end = t[round(m/t[-1]*len(t))]
|
497
|
-
ax1.plot(t, ym, '.', markersize=2)
|
481
|
+
fig, ax1 = plt.subplots(layout='constrained')
|
482
|
+
ax1.plot(t, ym, '.', markersize=4)
|
498
483
|
plt.plot(t, yf, 'k-')
|
499
484
|
plt.xlabel('Time [s]')
|
500
485
|
plt.ylabel('Amplitude [V]')
|
501
|
-
equation = r'$f(t)={0:1.2f}+e^{{-({3:1.3f})({4:1.1f})t}}\left[{1:1.2f}
|
502
|
-
|
503
|
-
|
486
|
+
equation = (r'$f(t)={0:1.2f}+e^{{-({3:1.3f})({4:1.1f})t}}\left[{1:1.2f}'
|
487
|
+
r'\sin{{\sqrt{{1-{3:1.3f}^2}}{4:1.1f}t}}+{2:1.2f}'
|
488
|
+
r'\cos{{\sqrt{{1-{3:1.3f}^2}}{4:1.1f}t}}\right]$')
|
489
|
+
equation = equation.format(p[0], p[1], p[2], p[3], p[4])
|
490
|
+
rsquare = r'$r^2={0:1.3f}$'.format(rsq)
|
491
|
+
period = r'$T={0} s$'.format(T)
|
504
492
|
plt.title(equation + '\n' + rsquare + ', ' + period)
|
505
493
|
plt.legend(['Measured', 'Fit'])
|
506
494
|
if m is not None:
|
@@ -511,13 +499,12 @@ def plot_osfit(t, ym, yf, p, rsq, T, m=None, fig=None):
|
|
511
499
|
|
512
500
|
|
513
501
|
def select_good_data(data, percent):
|
514
|
-
|
515
502
|
'''Returns a slice of the data from the index at maximum value to the index
|
516
503
|
at a percent of the maximum value.
|
517
504
|
|
518
505
|
Parameters
|
519
506
|
----------
|
520
|
-
data : ndarray, shape(
|
507
|
+
data : ndarray, shape(n,)
|
521
508
|
This should be a decaying function.
|
522
509
|
percent : float
|
523
510
|
The percent of the maximum to clip.
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import os
|
2
|
+
import numpy as np
|
3
|
+
from bicycleparameters.io import load_pendulum_mat_file
|
4
|
+
|
5
|
+
TESTS_DIR = os.path.dirname(__file__)
|
6
|
+
|
7
|
+
|
8
|
+
def test_load_pendulum_mat_file():
|
9
|
+
path = os.path.join(TESTS_DIR, 'sample_data',
|
10
|
+
'BrowserForkCompoundFirst1.mat')
|
11
|
+
|
12
|
+
d = load_pendulum_mat_file(path)
|
13
|
+
|
14
|
+
assert d['angle'] == 'First'
|
15
|
+
assert d['ActualRate'] == 1000
|
16
|
+
assert d['bicycle'] == 'BrowserIns'
|
17
|
+
assert d['data'].shape == (30000,)
|
18
|
+
np.testing.assert_allclose(
|
19
|
+
d['data'][0:5],
|
20
|
+
np.array([0.33034183, 0.32525861, 0.31509219, 0.31509219, 0.33034183]))
|
21
|
+
assert d['duration'] == 30
|
22
|
+
assert d['filename'] == 'BrowserInsForkCompoundFirst1'
|
23
|
+
assert d['notes'] == ''
|
24
|
+
assert d['part'] == 'Fork'
|
25
|
+
assert d['pendulum'] == 'Compound'
|
26
|
+
assert d['trial'] == '1'
|
@@ -1,2 +1,2 @@
|
|
1
|
-
__version_info__ = (1,
|
1
|
+
__version_info__ = (1, 2, 0)
|
2
2
|
__version__ = '.'.join(map(str, __version_info__))
|
@@ -211,14 +211,31 @@ Notes
|
|
211
211
|
|
212
212
|
Pendulum Data Files
|
213
213
|
===================
|
214
|
+
|
214
215
|
If you have raw signal data that the periods can be estimated from, then these
|
215
216
|
should be included in the ``RawData`` directory. There should be at least one
|
216
217
|
file for every period typically found in ``<bicycle name>Measured.txt`` file. The
|
217
218
|
signals collected should exhibit very typical decayed oscillations. Currently
|
218
219
|
the only supported file is a Matlab mat file with these variables:
|
219
220
|
|
220
|
-
- ``
|
221
|
-
- ``
|
221
|
+
- ``bicycle``, char : short name of the bicycle, e.g. ``'Browser'``
|
222
|
+
- ``part``, char : examples are ``'Fork'``, ``'Frame'``, ``'Rwheel'``
|
223
|
+
- ``pendulum``, char : either ``'Compound'`` or ``'Torsional'``
|
224
|
+
- ``angle`` or ``angleOrder``, char : the ``'First'``, ``'Second'``, ...,
|
225
|
+
``'Sixth'`` orientation
|
226
|
+
- ``trial``, char : the integer number of the repetition ``'1'``, ``'2'``, etc.
|
227
|
+
- ``filename``, char : filename constructed from above variables (see below for
|
228
|
+
explanation)
|
229
|
+
- ``notes``, char : any notes recorded for that measurement
|
230
|
+
- ``data``, double size n x 1 : signal vector of a decaying oscillation (from
|
231
|
+
rate gyro)
|
232
|
+
- Time information, either ``time`` OR both ``duration`` and ``sampleRate``:
|
233
|
+
|
234
|
+
- ``duration``, double size 1 x 1 : time in seconds for the measurement
|
235
|
+
- ``sampleRate`` or ``ActualRate``, double size 1 x 1 (integer) : sample
|
236
|
+
rate of data in Hertz
|
237
|
+
- ``time``, double size n x 1 : time values in seconds that correspond to
|
238
|
+
``data``
|
222
239
|
|
223
240
|
The files should be named in this manner ``<short
|
224
241
|
name><part><pendulum><orientation><trial>.mat`` where:
|
@@ -230,6 +247,11 @@ name><part><pendulum><orientation><trial>.mat`` where:
|
|
230
247
|
``Fifth``, or ``Sixth``
|
231
248
|
- ``<trial>`` is an integer greater than or equal to 1
|
232
249
|
|
250
|
+
These data files were originally collected with Matlab and a National
|
251
|
+
Instruments USB-6218 using a Silicon Sensing CRS03-04S single axis angular rate
|
252
|
+
gyro and a `data collection script
|
253
|
+
<https://github.com/moorepants/PhysicalParameters/blob/master/PhysicalParameters/matlab/acquire_data.m>`_.
|
254
|
+
|
233
255
|
Notes
|
234
256
|
-----
|
235
257
|
|
@@ -273,7 +295,7 @@ files.
|
|
273
295
|
riders/<rider name>/RawData/
|
274
296
|
============================
|
275
297
|
|
276
|
-
**These files must follow the YAML format used in the
|
298
|
+
**These files must follow the YAML format used in the yeadon package.**
|
277
299
|
|
278
300
|
<rider name><bicycle name>YeadonCFG.txt
|
279
301
|
---------------------------------------
|
@@ -291,4 +313,4 @@ all of the geometric measurements of the rider. See the `yeadon documentation`_
|
|
291
313
|
for more details.
|
292
314
|
|
293
315
|
.. _yeadon package: http://pypi.python.org/pypi/yeadon
|
294
|
-
.. _yeadon documentation :
|
316
|
+
.. _yeadon documentation : https://yeadon.readthedocs.io
|
@@ -617,6 +617,20 @@ plotted:
|
|
617
617
|
|
618
618
|
model.plot_eigenvalue_parts(v=speeds)
|
619
619
|
|
620
|
+
There are several common customization options available:
|
621
|
+
|
622
|
+
.. plot::
|
623
|
+
:include-source: True
|
624
|
+
:context: close-figs
|
625
|
+
|
626
|
+
speeds = np.linspace(0.0, 10.0, num=200)
|
627
|
+
|
628
|
+
ax = model.plot_eigenvalue_parts(v=speeds,
|
629
|
+
colors=['C0', 'C0', 'C1', 'C2'],
|
630
|
+
show_stable_regions=False,
|
631
|
+
hide_zeros=True)
|
632
|
+
ax.set_ylim((-10.0, 10.0))
|
633
|
+
|
620
634
|
You can choose any parameter in the dictionary to generate the root locus and
|
621
635
|
also override other parameters.
|
622
636
|
|
@@ -7,13 +7,20 @@ exec(open('bicycleparameters/version.py').read())
|
|
7
7
|
setup(
|
8
8
|
name='BicycleParameters',
|
9
9
|
version=__version__,
|
10
|
-
author='Jason
|
10
|
+
author='Jason K. Moore',
|
11
11
|
author_email='moorepants@gmail.com',
|
12
12
|
packages=find_packages(),
|
13
13
|
url='http://pypi.python.org/pypi/BicycleParameters',
|
14
14
|
license='LICENSE.txt',
|
15
15
|
description='Generates and manipulates the physical parameters of a bicycle.',
|
16
16
|
long_description=open('README.rst').read(),
|
17
|
+
project_urls={
|
18
|
+
'Web Application': 'https://bicycle-dynamics.onrender.com',
|
19
|
+
'Documentation': 'http://bicycleparameters.readthedocs.io',
|
20
|
+
'Source Code': 'https://github.com/moorepants/BicycleParameters',
|
21
|
+
'Issue Tracker': 'https://github.com/moorepants/BicycleParameters/issues',
|
22
|
+
},
|
23
|
+
include_package_data=True, # includes things in MANIFEST.in
|
17
24
|
install_requires=[
|
18
25
|
'DynamicistToolKit>=0.5.3',
|
19
26
|
'matplotlib>=3.5.1',
|
@@ -43,6 +50,7 @@ setup(
|
|
43
50
|
'Programming Language :: Python :: 3.10',
|
44
51
|
'Programming Language :: Python :: 3.11',
|
45
52
|
'Programming Language :: Python :: 3.12',
|
53
|
+
'Programming Language :: Python :: 3.13',
|
46
54
|
'Operating System :: OS Independent',
|
47
55
|
'Development Status :: 5 - Production/Stable',
|
48
56
|
'Intended Audience :: Science/Research',
|
File without changes
|
{bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/BicycleParameters.egg-info/dependency_links.txt
RENAMED
File without changes
|
{bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/BicycleParameters.egg-info/entry_points.txt
RENAMED
File without changes
|
File without changes
|
{bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/BicycleParameters.egg-info/top_level.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/assets/app-explanation.md
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bicycleparameters-1.1.0 → bicycleparameters-1.2.0}/bicycleparameters/tests/test_parameter_sets.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|