Modeling and Simulation in Python

Chapter 25

Copyright 2017 Allen Downey

License: Creative Commons Attribution 4.0 International


In [2]:
# Configure Jupyter so figures appear in the notebook
%matplotlib inline

# Configure Jupyter to display the assigned value after an assignment
%config InteractiveShell.ast_node_interactivity='last_expr_or_assign'

import pint
UNITS = pint.UnitRegistry()
Quantity = UNITS.Quantity

import matplotlib.pyplot as plt

import numpy as np
import pandas as pd

In [3]:
plt.plot(1, 1, None)


---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-e6f346678a7c> in <module>()
----> 1 plt.plot(1, 1, None)

~/anaconda3/lib/python3.6/site-packages/matplotlib/pyplot.py in plot(*args, **kwargs)
   3356                       mplDeprecation)
   3357     try:
-> 3358         ret = ax.plot(*args, **kwargs)
   3359     finally:
   3360         ax._hold = washold

~/anaconda3/lib/python3.6/site-packages/matplotlib/__init__.py in inner(ax, *args, **kwargs)
   1853                         "the Matplotlib list!)" % (label_namer, func.__name__),
   1854                         RuntimeWarning, stacklevel=2)
-> 1855             return func(ax, *args, **kwargs)
   1856 
   1857         inner.__doc__ = _add_data_doc(inner.__doc__,

~/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_axes.py in plot(self, *args, **kwargs)
   1525         kwargs = cbook.normalize_kwargs(kwargs, _alias_map)
   1526 
-> 1527         for line in self._get_lines(*args, **kwargs):
   1528             self.add_line(line)
   1529             lines.append(line)

~/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_base.py in _grab_next_args(self, *args, **kwargs)
    404                 this += args[0],
    405                 args = args[1:]
--> 406             for seg in self._plot_args(this, kwargs):
    407                 yield seg
    408 

~/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_base.py in _plot_args(self, tup, kwargs)
    364         # downstream.
    365         if any(v is None for v in tup):
--> 366             raise ValueError("x and y must not be None")
    367 
    368         kw = {}

ValueError: x and y must not be None

In [21]:
meter = UNITS.meter
minute = UNITS.minute
newton = UNITS.newton


Out[21]:
newton

And a few more parameters in the Params object.


In [22]:
max_torque = 240 * newton * meter


Out[22]:
240.0 meter newton

In [23]:
max_rpm = 5500 / minute


Out[23]:
5500 1/minute

In [24]:
def available_torque(rpm):
    if rpm > max_rpm:
        return 0 * newton * meter
    return max_torque * (1 - rpm/max_rpm)

In [25]:
available_torque(0 / minute)


Out[25]:
240.0 meter newton

In [26]:
rpms = np.linspace(0, max_rpm*1.1, 21) / minute


Out[26]:
[ 0. 302.5 605. 907.5 1210. 1512.5 1815. 2117.5 2420. 2722.5 3025. 3327.5 3630. 3932.5 4235. 4537.5 4840. 5142.5 5445. 5747.5 6050. ] 1/minute

In [27]:
taus = [available_torque(rpm) for rpm in rpms]


Out[27]:
[<Quantity(240.0, 'meter * newton')>,
 <Quantity(226.79999999999998, 'meter * newton')>,
 <Quantity(213.6, 'meter * newton')>,
 <Quantity(200.39999999999998, 'meter * newton')>,
 <Quantity(187.20000000000002, 'meter * newton')>,
 <Quantity(174.0, 'meter * newton')>,
 <Quantity(160.79999999999998, 'meter * newton')>,
 <Quantity(147.6, 'meter * newton')>,
 <Quantity(134.39999999999998, 'meter * newton')>,
 <Quantity(121.19999999999997, 'meter * newton')>,
 <Quantity(107.99999999999999, 'meter * newton')>,
 <Quantity(94.79999999999998, 'meter * newton')>,
 <Quantity(81.59999999999997, 'meter * newton')>,
 <Quantity(68.39999999999995, 'meter * newton')>,
 <Quantity(55.19999999999997, 'meter * newton')>,
 <Quantity(41.99999999999996, 'meter * newton')>,
 <Quantity(28.799999999999972, 'meter * newton')>,
 <Quantity(15.59999999999996, 'meter * newton')>,
 <Quantity(2.399999999999949, 'meter * newton')>,
 <Quantity(0.0, 'meter * newton')>,
 <Quantity(0.0, 'meter * newton')>]

In [33]:
series = pd.Series(taus, index=rpms.magnitude)


Out[33]:
0.0                    240.0 meter * newton
302.5     226.79999999999998 meter * newton
605.0                  213.6 meter * newton
907.5     200.39999999999998 meter * newton
1210.0    187.20000000000002 meter * newton
1512.5                 174.0 meter * newton
1815.0    160.79999999999998 meter * newton
2117.5                 147.6 meter * newton
2420.0    134.39999999999998 meter * newton
2722.5    121.19999999999997 meter * newton
3025.0    107.99999999999999 meter * newton
3327.5     94.79999999999998 meter * newton
3630.0     81.59999999999997 meter * newton
3932.5     68.39999999999995 meter * newton
4235.0     55.19999999999997 meter * newton
4537.5     41.99999999999996 meter * newton
4840.0    28.799999999999972 meter * newton
5142.5     15.59999999999996 meter * newton
5445.0     2.399999999999949 meter * newton
5747.5                   0.0 meter * newton
6050.0                   0.0 meter * newton
dtype: object

In [34]:
plt.plot(series)
plt.xlabel('Motor speed (rad/s)')
plt.ylabel('Available torque (N m)')


---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-34-be25389df638> in <module>()
----> 1 plt.plot(series)
      2 plt.xlabel('Motor speed (rad/s)')
      3 plt.ylabel('Available torque (N m)')

~/anaconda3/lib/python3.6/site-packages/matplotlib/pyplot.py in plot(*args, **kwargs)
   3356                       mplDeprecation)
   3357     try:
-> 3358         ret = ax.plot(*args, **kwargs)
   3359     finally:
   3360         ax._hold = washold

~/anaconda3/lib/python3.6/site-packages/matplotlib/__init__.py in inner(ax, *args, **kwargs)
   1853                         "the Matplotlib list!)" % (label_namer, func.__name__),
   1854                         RuntimeWarning, stacklevel=2)
-> 1855             return func(ax, *args, **kwargs)
   1856 
   1857         inner.__doc__ = _add_data_doc(inner.__doc__,

~/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_axes.py in plot(self, *args, **kwargs)
   1526 
   1527         for line in self._get_lines(*args, **kwargs):
-> 1528             self.add_line(line)
   1529             lines.append(line)
   1530 

~/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_base.py in add_line(self, line)
   1930             line.set_clip_path(self.patch)
   1931 
-> 1932         self._update_line_limits(line)
   1933         if not line.get_label():
   1934             line.set_label('_line%d' % len(self.lines))

~/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_base.py in _update_line_limits(self, line)
   1952         Figures out the data limit of the given line, updating self.dataLim.
   1953         """
-> 1954         path = line.get_path()
   1955         if path.vertices.size == 0:
   1956             return

~/anaconda3/lib/python3.6/site-packages/matplotlib/lines.py in get_path(self)
    949         """
    950         if self._invalidy or self._invalidx:
--> 951             self.recache()
    952         return self._path
    953 

~/anaconda3/lib/python3.6/site-packages/matplotlib/lines.py in recache(self, always)
    655         if always or self._invalidy:
    656             yconv = self.convert_yunits(self._yorig)
--> 657             y = _to_unmasked_float_array(yconv).ravel()
    658         else:
    659             y = self._y

~/anaconda3/lib/python3.6/site-packages/matplotlib/cbook/__init__.py in _to_unmasked_float_array(x)
   2048         return np.ma.asarray(x, float).filled(np.nan)
   2049     else:
-> 2050         return np.asarray(x, float)
   2051 
   2052 

~/anaconda3/lib/python3.6/site-packages/numpy/core/numeric.py in asarray(a, dtype, order)
    490 
    491     """
--> 492     return array(a, dtype, copy=False, order=order)
    493 
    494 

ValueError: setting an array element with a sequence.

In [ ]: