# Notebook from DianaMosquera/course-content
Path: tutorials/W1D1_ModelTypes/student/W1D1_Tutorial1.ipynb

_____no_output_____
#  Neuromatch Academy: Week 1, Day 1, Tutorial 1
# Model Types: "What" models
__Content creators:__ Matt Laporte, Byron Galbraith, Konrad Kording

__Content reviewers:__ Dalin Guo, Aishwarya Balwani, Madineh Sarvestani, Maryam Vaziri-Pashkam, Michael Waskom

We would like to acknowledge [Steinmetz _et al._ (2019)](https://www.nature.com/articles/s41586-019-1787-x) for sharing their data, a subset of which is used here.
_____no_output________
# Tutorial Objectives
This is tutorial 1 of a 3-part series on different flavors of models used to understand neural data. In this tutorial we will explore 'What' models, used to describe the data. To understand what our data looks like, we will visualize it in different ways. Then we will compare it to simple mathematical models. Specifically, we will:

- Load a dataset with spiking activity from hundreds of neurons and understand how it is organized
- Make plots to visualize characteristics of the spiking activity across the population
- Compute the distribution of "inter-spike intervals" (ISIs) for a single neuron
- Consider several formal models of this distribution's shape and fit them to the data "by hand"_____no_output_____

#@title Video 1: "What" Models
from IPython.display import YouTubeVideo
video = YouTubeVideo(id='KgqR_jbjMQg', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

# Setup

_____no_output_____Python requires you to explictly "import" libraries before their functions are available to use. We will always specify our imports at the beginning of each notebook or script._____no_output_____

import numpy as np
import matplotlib.pyplot as plt_____no_output_____

Tutorial notebooks typically begin with several set-up steps that are hidden from view by default.

**Important:** Even though the code is hidden, you still need to run it so that the rest of the notebook can work properly. Step through each cell, either by pressing the play button in the upper-left-hand corner or with a keyboard shortcut (`Cmd-Return` on a Mac, `Ctrl-Enter` otherwise). A number will appear inside the brackets (e.g. `[3]`) to tell you that the cell was executed and what order that happened in.

If you are curious to see what is going on inside each cell, you can double click to expand. Once expanded, double-click the white space to the right of the editor to collapse again._____no_output_____

#@title Figure Settings
import ipywidgets as widgets #interactive display

%matplotlib inline
%config InlineBackend.figure_format = 'retina'
plt.style.use("https://raw.githubusercontent.com/NeuromatchAcademy/course-content/master/nma.mplstyle")_____no_output_____#@title Helper functions

#@markdown Most of the tutorials make use of helper functions
#@markdown to simplify the code that you need to write. They are defined here.

# Please don't edit these, or worry about understanding them now!

def restrict_spike_times(spike_times, interval):
  """Given a spike_time dataset, restrict to spikes within given interval.

  Args:
    spike_times (sequence of np.ndarray): List or array of arrays,
      each inner array has spike times for a single neuron.
    interval (tuple): Min, max time values; keep min <= t < max.

  Returns:
    np.ndarray: like `spike_times`, but only within `interval`
  """
  interval_spike_times = []
  for spikes in spike_times:
    interval_mask = (spikes >= interval[0]) & (spikes < interval[1])
    interval_spike_times.append(spikes[interval_mask])
  return np.array(interval_spike_times, object)_____no_output_____#@title Data retrieval
#@markdown This cell downloads the example dataset that we will use in this tutorial.
import io
import requests
r = requests.get('https://osf.io/sy5xt/download')
if r.status_code != 200:
  print('Failed to download data')
else:
  spike_times = np.load(io.BytesIO(r.content), allow_pickle=True)['spike_times']_____no_output_____

---

# Section 1: Exploring the Steinmetz dataset

In this tutorial we will explore the structure of a neuroscience dataset.

We consider a subset of data from a study of [Steinmetz _et al._ (2019)](https://www.nature.com/articles/s41586-019-1787-x). In this study, Neuropixels probes were implanted in the brains of mice. Electrical potentials were measured by hundreds of electrodes along the length of each probe. Each electrode's measurements captured local variations in the electric field due to nearby spiking neurons. A spike sorting algorithm was used to infer spike times and cluster spikes according to common origin: a single cluster of sorted spikes is causally attributed to a single neuron.

In particular, a single recording session of spike times and neuron assignments was loaded and assigned to `spike_times` in the preceding setup.

Typically a dataset comes with some information about its structure. However, this information may be incomplete. You might also apply some transformations or "pre-processing" to create a working representation of the data of interest, which might go partly undocumented depending on the circumstances. In any case it is important to be able to use the available tools to investigate unfamiliar aspects of a data structure.

Let's see what our data looks like..._____no_output_____## Section 1.1: Warming up with `spike_times`_____no_output_____What is the Python type of our variable?_____no_output_____

type(spike_times)_____no_output_____

You should see `numpy.ndarray`, which means that it's a normal NumPy array.

If you see an error message, it probably means that you did not execute the set-up cells at the top of the notebook. So go ahead and make sure to do that.

Once everything is running properly, we can ask the next question about the dataset: what's its shape?_____no_output_____

spike_times.shape_____no_output_____

There are 734 entries in one dimension, and no other dimensions. What is the Python type of the first entry, and what is *its* shape?_____no_output_____

idx = 0
print(
  type(spike_times[idx]),
  spike_times[idx].shape,
  sep="\n",
)_____no_output_____

It's also a NumPy array with a 1D shape! Why didn't this show up as a second dimension in the shape of `spike_times`? That is, why not `spike_times.shape == (734, 826)`?

To investigate, let's check another entry._____no_output_____

idx = 321
print(
  type(spike_times[idx]),
  spike_times[idx].shape,
  sep="\n",
)_____no_output_____

It's also a 1D NumPy array, but it has a different shape. Checking the NumPy types of the values in these arrays, and their first few elements, we see they are composed of floating point numbers (not another level of `np.ndarray`):_____no_output_____

i_neurons = [0, 321]
i_print = slice(0, 5)

for i in i_neurons:
  print(
    "Neuron {}:".format(i),
    spike_times[i].dtype,
    spike_times[i][i_print],
    "\n",
    sep="\n"
  )_____no_output_____

Note that this time we've checked the NumPy `dtype` rather than the Python variable type. These two arrays contain floating point numbers ("floats") with 32 bits of precision.

The basic picture is coming together:
- `spike_times` is 1D, its entries are NumPy arrays, and its length is the number of neurons (734): by indexing it, we select a subset of neurons.
- An array in `spike_times` is also 1D and corresponds to a single neuron; its entries are floating point numbers, and its length is the number of spikes attributed to that neuron. By indexing it, we select a subset of spike times for that neuron.

Visually, you can think of the data structure as looking something like this:

```
| . . . . . |
| . . . . . . . . |
| . . . |
| . . . . . . . |
```

Before moving on, we'll calculate and store the number of neurons in the dataset and the number of spikes per neuron:_____no_output_____

n_neurons = len(spike_times)
total_spikes_per_neuron = [len(spike_times_i) for spike_times_i in spike_times]

print(f"Number of neurons: {n_neurons}")
print(f"Number of spikes for first five neurons: {total_spikes_per_neuron[:5]}")_____no_output_____#@title Video 2: Exploring the dataset
from IPython.display import YouTubeVideo
video = YouTubeVideo(id='oHwYWUI_o1U', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

## Section 1.2: Getting warmer: counting and plotting total spike counts

As we've seen, the number of spikes over the entire recording is variable between neurons. More generally, some neurons tend to spike more than others in a given period. Lets explore what the distribution of spiking looks like across all the neurons in the dataset._____no_output_____Are most neurons "loud" or "quiet", compared to the average? To see, we'll define bins of constant width in terms of total spikes and count the neurons that fall in each bin. This is known as a "histogram".

You can plot a histogram with the matplotlib function `plt.hist`. If you just need to compute it, you can use the numpy function `np.histogram` instead._____no_output_____

plt.hist(total_spikes_per_neuron, bins=50, histtype="stepfilled")
plt.xlabel("Total spikes per neuron")
plt.ylabel("Number of neurons");_____no_output_____

Let's see what percentage of neurons have a below-average spike count:_____no_output_____

mean_spike_count = np.mean(total_spikes_per_neuron)
frac_below_mean = (total_spikes_per_neuron < mean_spike_count).mean()
print(f"{frac_below_mean:2.1%} of neurons are below the mean")_____no_output_____

We can also see this by adding the average spike count to the histogram plot:_____no_output_____

plt.hist(total_spikes_per_neuron, bins=50, histtype="stepfilled")
plt.xlabel("Total spikes per neuron")
plt.ylabel("Number of neurons")
plt.axvline(mean_spike_count, color="orange", label="Mean neuron")
plt.legend();_____no_output_____

This shows that the majority of neurons are relatively "quiet" compared to the mean, while a small number of neurons are exceptionally "loud": they must have spiked more often to reach a large count.

### Exercise 1: Comparing mean and median neurons

If the mean neuron is more active than 68% of the population, what does that imply about the relationship between the mean neuron and the median neuron?

*Exercise objective:* Reproduce the plot above, but add the median neuron.
_____no_output_____

# To complete the exercise, fill in the missing parts (...) and uncomment the code

median_spike_count = ...  # Hint: Try the function np.median

# plt.hist(..., bins=50, histtype="stepfilled")
# plt.axvline(..., color="limegreen", label="Median neuron")
# plt.axvline(mean_spike_count, color="orange", label="Mean neuron")
# plt.xlabel("Total spikes per neuron")
# plt.ylabel("Number of neurons")
# plt.legend()_____no_output_____

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W1D1_ModelTypes/solutions/W1D1_Tutorial1_Solution_b3411d5d.py)

*Example output:*

_____no_output_____
*Bonus:* The median is the 50th percentile. What about other percentiles? Can you show the interquartile range on the histogram?_____no_output_____---

# Section 2: Visualizing neuronal spiking activity_____no_output_____## Section 2.1: Getting a subset of the data

Now we'll visualize trains of spikes. Because the recordings are long, we will first define a short time interval and restrict the visualization to only the spikes in this interval. We defined a utility function, `restrict_spike_times`, to do this for you. If you call `help()` on the function, it will tell you a little bit about itself:_____no_output_____

help(restrict_spike_times)_____no_output_____t_interval = (5, 15)  # units are seconds after start of recording
interval_spike_times = restrict_spike_times(spike_times, t_interval)_____no_output_____

Is this a representative interval? What fraction of the total spikes fall in this interval?_____no_output_____

original_counts = sum([len(spikes) for spikes in spike_times])
interval_counts = sum([len(spikes) for spikes in interval_spike_times])
frac_interval_spikes = interval_counts / original_counts
print(f"{frac_interval_spikes:.2%} of the total spikes are in the interval")_____no_output_____

How does this compare to the ratio between the interval duration and the experiment duration? (What fraction of the total time is in this interval?)

We can approximate the experiment duration by taking the minimum and maximum spike time in the whole dataset. To do that, we "concatenate" all of the neurons into one array and then use `np.ptp` ("peak-to-peak") to get the difference between the maximum and minimum value:_____no_output_____

spike_times_flat = np.concatenate(spike_times)
experiment_duration = np.ptp(spike_times_flat)
interval_duration = t_interval[1] - t_interval[0]

frac_interval_time = interval_duration / experiment_duration
print(f"{frac_interval_time:.2%} of the total time is in the interval")_____no_output_____

These two values—the fraction of total spikes and the fraction of total time—are similar. This suggests the average spike rate of the neuronal population is not very different in this interval compared to the entire recording.

## Section 2.2: Plotting spike trains and rasters

Now that we have a representative subset, we're ready to plot the spikes, using the matplotlib `plt.eventplot` function. Let's look at a single neuron first:_____no_output_____

neuron_idx = 1
plt.eventplot(interval_spike_times[neuron_idx], color=".2")
plt.xlabel("Time (s)")
plt.yticks([]);_____no_output_____

We can also plot multiple neurons. Here are three:_____no_output_____

neuron_idx = [1, 11, 51]
plt.eventplot(interval_spike_times[neuron_idx], color=".2")
plt.xlabel("Time (s)")
plt.yticks([]);_____no_output_____

This makes a "raster" plot, where the spikes from each neuron appear in a different row.

Plotting a large number of neurons can give you a sense for the characteristics in the population. Let's show every 5th neuron that was recorded:_____no_output_____

neuron_idx = np.arange(0, len(spike_times), 5)
plt.eventplot(interval_spike_times[neuron_idx], color=".2")
plt.xlabel("Time (s)")
plt.yticks([]);_____no_output_____

*Question*: How does the information in this plot relate to the histogram of total spike counts that you saw above?_____no_output_____

#@title Video 3: Visualizing activity
from IPython.display import YouTubeVideo
video = YouTubeVideo(id='QGA5FCW7kkA', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

---

# Section 3: Inter-spike intervals and their distributions_____no_output_____Given the ordered arrays of spike times for each neuron in `spike_times`, which we've just visualized, what can we ask next?

Scientific questions are informed by existing models. So, what knowledge do we already have that can inform questions about this data?

We know that there are physical constraints on neuron spiking. Spiking costs energy, which the neuron's cellular machinery can only obtain at a finite rate. Therefore neurons should have a refractory period: they can only fire as quickly as their metabolic processes can support, and there is a minimum delay between consecutive spikes of the same neuron.

More generally, we can ask "how long does a neuron wait to spike again?" or "what is the longest a neuron will wait?" Can we transform spike times into something else, to address questions like these more directly?

We can consider the inter-spike times (or interspike intervals: ISIs). These are simply the time differences between consecutive spikes of the same neuron.

### Exercise 2: Plot the distribution of ISIs for a single neuron

*Exercise objective:* make a histogram, like we did for spike counts, to show the distribution of ISIs for one of the neurons in the dataset.

Do this in three steps:

1. Extract the spike times for one of the neurons
2. Compute the ISIs (the amount of time between spikes, or equivalently, the difference between adjacent spike times)
3. Plot a histogram with the array of individual ISIs_____no_output_____

def compute_single_neuron_isis(spike_times, neuron_idx):
  """Compute a vector of ISIs for a single neuron given spike times.

  Args:
    spike_times (list of 1D arrays): Spike time dataset, with the first
      dimension corresponding to different neurons.
    neuron_idx (int): Index of the unit to compute ISIs for.

  Returns:
    isis (1D array): Duration of time between each spike from one neuron.
  """
  #############################################################################
  # Students: Fill in missing code (...) and comment or remove the next line
  raise NotImplementedError("Exercise: compute single neuron ISIs")
  #############################################################################

  # Extract the spike times for the specified neuron
  single_neuron_spikes = ...

  # Compute the ISIs for this set of spikes
  # Hint: the function np.diff computes discrete differences along an array
  isis = ...

  return isis

# Uncomment the following lines when you are ready to test your function
# single_neuron_isis = compute_single_neuron_isis(spike_times, neuron_idx=283)
# plt.hist(single_neuron_isis, bins=50, histtype="stepfilled")
# plt.axvline(single_neuron_isis.mean(), color="orange", label="Mean ISI")
# plt.xlabel("ISI duration (s)")
# plt.ylabel("Number of spikes")
# plt.legend()_____no_output_____

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W1D1_ModelTypes/solutions/W1D1_Tutorial1_Solution_4792dbfa.py)

*Example output:*

_____no_output_____---

In general, the shorter ISIs are predominant, with counts decreasing rapidly (and smoothly, more or less) with increasing ISI. However, counts also rapidly decrease to zero with _decreasing_ ISI, below the maximum of the distribution (8-11 ms). The absence of these very low ISIs agrees with the refractory period hypothesis: the neuron cannot fire quickly enough to populate this region of the ISI distribution.

Check the distributions of some other neurons. To resolve various features of the distributions, you might need to play with the value of `n_bins`. Using too few bins might smooth over interesting details, but if you use too many bins, the random variability will start to dominate.

You might also want to restrict the range to see the shape of the distribution when focusing on relatively short or long ISIs. *Hint:* `plt.hist` takes a `range` argument _____no_output_____---

# Section 4: What is the functional form of an ISI distribution?_____no_output_____

#@title Video 4: ISI distribution
from IPython.display import YouTubeVideo
video = YouTubeVideo(id='DHhM80MOTe8', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

The ISI histograms seem to follow continuous, monotonically decreasing functions above their maxima. The function is clearly non-linear. Could it belong to a single family of functions?

To motivate the idea of using a mathematical function to explain physiological phenomena, let's define a few different function forms that we might expect the relationship to follow: exponential, inverse, and linear._____no_output_____

def exponential(xs, scale, rate, x0):
  """A simple parametrized exponential function, applied element-wise.

  Args:
    xs (np.ndarray or float): Input(s) to the function.
    scale (float): Linear scaling factor.
    rate (float): Exponential growth (positive) or decay (negative) rate.
    x0 (float): Horizontal offset.

  """
  ys = scale * np.exp(rate * (xs - x0))
  return ys

def inverse(xs, scale, x0):
  """A simple parametrized inverse function (`1/x`), applied element-wise.

  Args:
    xs (np.ndarray or float): Input(s) to the function.
    scale (float): Linear scaling factor.
    x0 (float): Horizontal offset.

  """
  ys = scale / (xs - x0)
  return ys

def linear(xs, slope, y0):
  """A simple linear function, applied element-wise.

  Args:
    xs (np.ndarray or float): Input(s) to the function.
    slope (float): Slope of the line.
    y0 (float): y-intercept of the line.

  """
  ys = slope * xs + y0
  return ys_____no_output_____

### Interactive Demo: ISI functions explorer

Here is an interactive demo where you can vary the parameters of these functions and see how well the resulting outputs correspond to the data. Adjust the parameters by moving the sliders and see how close you can get the lines to follow the falling curve of the histogram. This will give you a taste of what you're trying to do when you *fit a model* to data.

"Interactive demo" cells have hidden code that defines an interface where you can play with the parameters of some function using sliders. You don't need to worry about how the code works – but you do need to **run the cell** to enable the sliders.
_____no_output_____

#@title

#@markdown Be sure to run this cell to enable the demo
# Don't worry about understanding this code! It's to setup an interactive plot.
single_neuron_idx = 283
single_neuron_spikes = spike_times[single_neuron_idx]
single_neuron_isis = np.diff(single_neuron_spikes)

counts, edges = np.histogram(
  single_neuron_isis,
  bins=50,
  range=(0, single_neuron_isis.max())
)

functions = dict(
  exponential=exponential,
  inverse=inverse,
  linear=linear,
)

colors = dict(
  exponential="C1",
  inverse="C2",
  linear="C4",
)

@widgets.interact(
  exp_scale=widgets.FloatSlider(1000, min=0, max=20000, step=250),
  exp_rate=widgets.FloatSlider(-10, min=-200, max=50, step=1),
  exp_x0=widgets.FloatSlider(0.1, min=-0.5, max=0.5, step=0.005),
  inv_scale=widgets.FloatSlider(1000, min=0, max=3e2, step=10),
  inv_x0=widgets.FloatSlider(0, min=-0.2, max=0.2, step=0.01),
  lin_slope=widgets.FloatSlider(-1e5, min=-6e5, max=1e5, step=10000),
  lin_y0=widgets.FloatSlider(10000, min=0, max=4e4, step=1000),
)
def fit_plot(
  exp_scale=1000, exp_rate=-10, exp_x0=0.1,
  inv_scale=1000, inv_x0=0,
  lin_slope=-1e5, lin_y0=2000,
):
  """Helper function for plotting function fits with interactive sliders."""
  func_params = dict(
    exponential=(exp_scale, exp_rate, exp_x0),
    inverse=(inv_scale, inv_x0),
    linear=(lin_slope, lin_y0),
  )
  f, ax = plt.subplots()
  ax.fill_between(edges[:-1], counts, step="post", alpha=.5)
  xs = np.linspace(1e-10, edges.max())
  for name, function in functions.items():
    ys = function(xs, *func_params[name])
    ax.plot(xs, ys, lw=3, color=colors[name], label=name);
  ax.set(
      xlim=(edges.min(), edges.max()),
      ylim=(0, counts.max() * 1.1),
      xlabel="ISI (s)",
      ylabel="Number of spikes",
  )
  ax.legend()_____no_output_____#@title Video 5: Fitting models by hand
from IPython.display import YouTubeVideo
video = YouTubeVideo(id='uW2HDk_4-wk', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

# Summary

In this tutorial, we loaded some neural data and poked at it to understand how the dataset is organized. Then we made some basic plots to visualize (1) the average level of activity across the population and (2) the distribution of ISIs for an individual neuron. In the very last bit, we started to think about using mathematical formalisms to understand or explain some physiological phenomenon. All of this only allowed us to understand "What" the data looks like.

This is the first step towards developing models that can tell us something about the brain. That's what we'll focus on in the next two tutorials._____no_output_____


# Notebook from CSCI4850/s21-team7-project
Path: DEMO/LargeDemo_notebook.ipynb

WELCOME TO THE DEMO!!!

Let's get going!  We are going to assume you are using our custom datasets for this.  We used a Google Drive to store the data.  The following code supports the use of a Google Drive and code execution on Google Colab.

What do I need right now?
1.  A Google account
2.  Access to you own Google Drive

Once that is taken care of, head over to the Data section and copy our datasets to your Google Drive.  You will need these 3 sets:
1. original_data_set   (these are the 3000 spectrogram images converted directly from the free-spoken-digit dataset)
2. plusAugmented       (these are the originals PLUS all of our custom spectrograms crafted from our own augmented audio files for a total of 32,898 images)
3.  unsen_originals   (102 original unaltered spectrogram images NOT included in the plusAugmented batch)

Go grab yourself a snack.  This will take a minute (or 12...or 20)....
Actually if you just want to see some quick not so meaningfull results heres our smaller dataset. A much much smaller
[dataset](https://drive.google.com/drive/folders/10ldZfWHfqrv20AnGLO9QQdpr2S9493Tz?usp=sharing)

Or better yet use our smaller [demo](https://colab.research.google.com/drive/1VggPr2CdDHAgMlyAp1WiE2Y9_yfRsTSy?usp=sharing)

_____no_output_____Next step, head over to Google Colab  (https://colab.research.google.com/).
You need to mount your Google Drive so you can have access to the datasets.
Execute the cell below to get started._____no_output_____

 #this code snippet is used to import our custom dataset
from google.colab import drive
drive.mount('/content/drive')Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).

Now we are cooking with grease!

The following section of code will import all the needed modules used to build our neural network.

If you get an error related to modules not being present, please refer here on how to install them locally:
https://docs.python.org/3/installing/index.html_____no_output_____

# import all necessary modules
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import numpy as np
from IPython.display import display
import matplotlib.pyplot as plt
%matplotlib inline_____no_output_____

Next step we need to set up the variables we used in the model.

We processed the images as 256 X 256.  You can change these settings if you like to make the picture smaller (like 128 X 128) or larger (512 X 512). Smaller settings will process faster, but less detail means less accuracy.  The opposite would be the case for larger.

Be sure to use 3 for rgb (red, green, blue) setting to designate the images are in color.

Next up, figure out your batch size (how many images you want to process at a time) and the number or epochs (how many times you want to process the batch).  These are totally adjustable.  Careful though, there can be too much of a good thing.  We found that a batch size of 10 and 50 epochs would yield some decent results._____no_output_____

# set the variables to work with throughout model
img_height = 256
img_width= 256
rgb = 3
batch_size = 10
epochs = 50_____no_output_____

Alright, so it's time to get the data loaded.  Be sure to use your local path to the data.  Also be sure that you are placing the correct path into the proper identifier (originals to ods_train for example)._____no_output_____

# set-up training data from the original dataset only
ods_train = tf.keras.preprocessing.image_dataset_from_directory(
    '/content/drive/MyDrive/original_data_set', # need local path to directory
    labels = 'inferred',
    label_mode = 'categorical',
    batch_size = batch_size,
    image_size = (img_height, img_width),
    shuffle = True,
    seed = 123,
    validation_split = 0.3,
    subset = 'training',
)Found 35 files belonging to 3 classes.
Using 25 files for training.
# set-up training data using original plus the augmented data as well
plusAugmented_train = tf.keras.preprocessing.image_dataset_from_directory(
    '/content/drive/MyDrive/plusAugmented', # need local path to directory
    labels = 'inferred',
    label_mode = 'categorical',
    batch_size = batch_size,
    image_size = (img_height, img_width),
    shuffle = True,
    seed = 123,
    validation_split = 0.3,
    subset = 'training',
)Found 300 files belonging to 3 classes.
Using 210 files for training.
# now create a batch to test ont the plusAugmented model with unseen original images
ods_test = tf.keras.preprocessing.image_dataset_from_directory(
   '/content/drive/MyDrive/original_data_set', # need local path to directory
    labels = 'inferred',
    label_mode = 'categorical',
    batch_size = batch_size,
    image_size = (img_height, img_width),
    shuffle = True,
    seed = 456,
    validation_split = 0.3,
    subset = "validation",
)Found 35 files belonging to 3 classes.
Using 10 files for validation.
# also need a batch to test with from the original plus augmented dataset
plusAugmented_test = tf.keras.preprocessing.image_dataset_from_directory(
    '/content/drive/MyDrive/plusAugmented', # need local path to directory
    labels = 'inferred',
    label_mode = 'categorical',
    batch_size = batch_size,
    image_size = (img_height, img_width),
    shuffle = True,
    seed = 456,
    validation_split = 0.3,
    subset = "validation",
)Found 300 files belonging to 3 classes.
Using 90 files for validation.
# the real test....
# NOW, a batch of unseen originals the plusAugmented model has not seen
unseen_test = tf.keras.preprocessing.image_dataset_from_directory(
    '/content/drive/MyDrive/unseen_originals', # need local path to directory
    labels = 'inferred',
    label_mode = 'categorical',
    batch_size = batch_size,
    image_size = (img_height, img_width),
    shuffle = True,
    seed = 456,
)Found 30 files belonging to 3 classes.

You may have noticed that last batch we made does not have a validaiton split included.  That's because the unseen_test batch is strictly to test the trained model made from the plusAugmented dataset.  A split is not necessary._____no_output_____Now it's time to make the doughnuts!

The following cell will build the model.  If you have an interest, you can twist and tweak quite a few variables here to alter how the model will perform.  For starters, I would suggest you use it as-is since this was the exact setup used to get our final results.  You can always come back and customize it and try out something new a little later.

NOTE CHANGE **DENSE LAYER TO 3** IF USING OUR **SMALLER DATASET**_____no_output_____

#  build up model
model = keras.models.Sequential()
model.add(keras.layers.Convolution2D(16, kernel_size = (5, 5), input_shape=(img_height, img_width, rgb ), activation='relu'))
model.add(keras.layers.Convolution2D(16, kernel_size = (3, 3), activation='relu'))
model.add(keras.layers.BatchNormalization())
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(keras.layers.Dropout(0.2))
# have to make sure we pass the correct shape to LSTM
# use reshape to convert from 2D to 3D!
model.add(keras.layers.Reshape((125, -1)))
# using TimeDistributed layer
# this makes sure the dense layer keeps track of the
# temporal aspects of the data
model.add(keras.layers.TimeDistributed(layers.Dense(50)))
model.add(keras.layers.LSTM(50, return_sequences=False))
model.add(keras.layers.Dense(10,activation = 'softmax'))    _____no_output_____

This next step is not 100% needed, but does give a really nice visual on the model structure.  It will display each layer's input and output.  This will give you an idea of how each layer connects moving downstream._____no_output_____

# display model layers w/ input and output from layers
tf.keras.utils.plot_model(model, show_shapes=True, expand_nested=True)_____no_output_____

We now have parameters in place, data initialized and split-up, and a model woven together.  Time to compile the model and get it ready to process._____no_output_____

# compile model
model.compile(optimizer = keras.optimizers.Adam(),
             loss = [ keras.losses.CategoricalCrossentropy(from_logits=True)],
             metrics = [ keras.metrics.CategoricalAccuracy()])_____no_output_____

The next step is not a requirement either, but again, this gives some insight into what is happening with the model.  A quick snapshot of each layer and how many parameters it will be working with summarized at the end.  Now, don't let the low number of total parameters at the end fool you.  This thing is going to take up a fair amount of time run (unless you are using some serious GPU horsepower)._____no_output_____

# show a summary of layers and the parameters
model.summary()Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_12 (Conv2D)           (None, 252, 252, 16)      1216
_________________________________________________________________
conv2d_13 (Conv2D)           (None, 250, 250, 16)      2320
_________________________________________________________________
batch_normalization_6 (Batch (None, 250, 250, 16)      64
_________________________________________________________________
max_pooling2d_6 (MaxPooling2 (None, 125, 125, 16)      0
_________________________________________________________________
dropout_6 (Dropout)          (None, 125, 125, 16)      0
_________________________________________________________________
reshape_6 (Reshape)          (None, 125, 2000)         0
_________________________________________________________________
time_distributed_6 (TimeDist (None, 125, 50)           100050
_________________________________________________________________
lstm_6 (LSTM)                (None, 50)                20200
_________________________________________________________________
dense_13 (Dense)             (None, 3)                 153
=================================================================
Total params: 124,003
Trainable params: 123,971
Non-trainable params: 32
_________________________________________________________________

I guess it's time to make the magic happen... Let the training begin!!_____no_output_____

# training the original dataset
ods_history = model.fit(ods_train,
                    batch_size = batch_size,
                    epochs = epochs,
                    verbose = 1)Epoch 1/50
3/3 [==============================] - 17s 21ms/step - loss: 1.1967 - categorical_accuracy: 0.4125
Epoch 2/50
3/3 [==============================] - 0s 21ms/step - loss: 0.9301 - categorical_accuracy: 0.5875
Epoch 3/50
3/3 [==============================] - 0s 21ms/step - loss: 0.9669 - categorical_accuracy: 0.4400
Epoch 4/50
3/3 [==============================] - 0s 21ms/step - loss: 0.6929 - categorical_accuracy: 0.7350
Epoch 5/50
3/3 [==============================] - 0s 20ms/step - loss: 0.8131 - categorical_accuracy: 0.6575
Epoch 6/50
3/3 [==============================] - 0s 20ms/step - loss: 0.7845 - categorical_accuracy: 0.7025
Epoch 7/50
3/3 [==============================] - 0s 21ms/step - loss: 0.6571 - categorical_accuracy: 0.8325
Epoch 8/50
3/3 [==============================] - 0s 21ms/step - loss: 0.5113 - categorical_accuracy: 0.9675
Epoch 9/50
3/3 [==============================] - 0s 21ms/step - loss: 0.4163 - categorical_accuracy: 1.0000
Epoch 10/50
3/3 [==============================] - 0s 21ms/step - loss: 0.3622 - categorical_accuracy: 1.0000
Epoch 11/50
3/3 [==============================] - 0s 21ms/step - loss: 0.3129 - categorical_accuracy: 1.0000
Epoch 12/50
3/3 [==============================] - 0s 21ms/step - loss: 0.1911 - categorical_accuracy: 1.0000
Epoch 13/50
3/3 [==============================] - 0s 21ms/step - loss: 0.1759 - categorical_accuracy: 1.0000
Epoch 14/50
3/3 [==============================] - 0s 21ms/step - loss: 0.1912 - categorical_accuracy: 1.0000
Epoch 15/50
3/3 [==============================] - 0s 22ms/step - loss: 0.1081 - categorical_accuracy: 1.0000
Epoch 16/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0970 - categorical_accuracy: 1.0000
Epoch 17/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0752 - categorical_accuracy: 1.0000
Epoch 18/50
3/3 [==============================] - 0s 23ms/step - loss: 0.0681 - categorical_accuracy: 1.0000
Epoch 19/50
3/3 [==============================] - 0s 20ms/step - loss: 0.0640 - categorical_accuracy: 1.0000
Epoch 20/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0600 - categorical_accuracy: 1.0000
Epoch 21/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0510 - categorical_accuracy: 1.0000
Epoch 22/50
3/3 [==============================] - 0s 22ms/step - loss: 0.0418 - categorical_accuracy: 1.0000
Epoch 23/50
3/3 [==============================] - 0s 19ms/step - loss: 0.0432 - categorical_accuracy: 1.0000
Epoch 24/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0348 - categorical_accuracy: 1.0000
Epoch 25/50
3/3 [==============================] - 0s 22ms/step - loss: 0.0285 - categorical_accuracy: 1.0000
Epoch 26/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0284 - categorical_accuracy: 1.0000
Epoch 27/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0262 - categorical_accuracy: 1.0000
Epoch 28/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0323 - categorical_accuracy: 1.0000
Epoch 29/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0286 - categorical_accuracy: 1.0000
Epoch 30/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0308 - categorical_accuracy: 1.0000
Epoch 31/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0439 - categorical_accuracy: 1.0000
Epoch 32/50
3/3 [==============================] - 0s 22ms/step - loss: 0.0256 - categorical_accuracy: 1.0000
Epoch 33/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0257 - categorical_accuracy: 1.0000
Epoch 34/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0214 - categorical_accuracy: 1.0000
Epoch 35/50
3/3 [==============================] - 0s 20ms/step - loss: 0.0235 - categorical_accuracy: 1.0000
Epoch 36/50
3/3 [==============================] - 0s 25ms/step - loss: 0.0194 - categorical_accuracy: 1.0000
Epoch 37/50
3/3 [==============================] - 0s 22ms/step - loss: 0.0189 - categorical_accuracy: 1.0000
Epoch 38/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0173 - categorical_accuracy: 1.0000
Epoch 39/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0214 - categorical_accuracy: 1.0000
Epoch 40/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0144 - categorical_accuracy: 1.0000
Epoch 41/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0186 - categorical_accuracy: 1.0000
Epoch 42/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0149 - categorical_accuracy: 1.0000
Epoch 43/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0112 - categorical_accuracy: 1.0000
Epoch 44/50
3/3 [==============================] - 0s 20ms/step - loss: 0.0107 - categorical_accuracy: 1.0000
Epoch 45/50
3/3 [==============================] - 0s 23ms/step - loss: 0.0131 - categorical_accuracy: 1.0000
Epoch 46/50
3/3 [==============================] - 0s 21ms/step - loss: 0.0123 - categorical_accuracy: 1.0000
Epoch 47/50
3/3 [==============================] - 0s 20ms/step - loss: 0.0130 - categorical_accuracy: 1.0000
Epoch 48/50
3/3 [==============================] - 0s 27ms/step - loss: 0.0111 - categorical_accuracy: 1.0000
Epoch 49/50
3/3 [==============================] - 0s 20ms/step - loss: 0.0097 - categorical_accuracy: 1.0000
Epoch 50/50
3/3 [==============================] - 0s 20ms/step - loss: 0.0108 - categorical_accuracy: 1.0000

The next cell gives us a little info on what just happened.  It will show you how well the training went._____no_output_____

# how did we do?
# graphically display results of training
plt.figure()
plt.subplot(211)
plt.plot(ods_history.history['categorical_accuracy'])
plt.title('Using Original Data: Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['training'], loc = 'upper left')

plt.subplot(212)
plt.plot(ods_history.history['loss'])
plt.title('Using Original Data: Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['training'], loc = 'upper right')

plt.tight_layout()
plt.show()_____no_output_____

Cool little feature here.  You don't have to do this, but if you would like to be able to access these results for future use, this will save your model after training.  _____no_output_____

# go ahead and save the model here
model.save("ods_16.h5") # you can pick your own filename, just be sure to put .h5 at the end_____no_output_____

One step closer to the end.

The model has been trained.  Let's check and validate that training.  The next cell uses the unseen chunk of images pulled off for validation.  We will be able to see how accurate our model really is._____no_output_____

# now test the model against the reserved unseen images from the original dataset
ods_t = model.evaluate(ods_test, verbose = 1)
print("Using only original test samples:")
print("Accuracy: ", ods_t[1] * 100)
print("Loss: ", ods_t[0])1/1 [==============================] - 2s 2s/step - loss: 0.8415 - categorical_accuracy: 0.8000
Using only original test samples:
Accuracy:  80.0000011920929
Loss:  0.8415465354919434
# NOW, let's test the original model with super secret unseen original images
unseen_test_history = model.evaluate(unseen_test, verbose = 1)
print("Using completely unseen originals only:")
print("Accuracy: ", unseen_test_history[1] * 100)
print("Loss: ", unseen_test_history[0])3/3 [==============================] - 17s 11ms/step - loss: 1.6449 - categorical_accuracy: 0.5000
Using completely unseen originals only:
Accuracy:  50.0
Loss:  1.6449111700057983

Now repeat the training and testing process for the plusAugmented data set.  Just a reminder, this one is ten times larger than the original.  Once you get it up and running, consider turning on the TV and catching a show to pass the time needed to process this volume of data.  May i suggest a Star Wars movie, possibly even a few of them? (Just Kidding!)
(Or ya know just use our smaller dataset...)_____no_output_____

# next, we need to train with the original plus the augmented data on the exact same architecture
plusAugmented_history = model.fit(plusAugmented_train,
                    batch_size = batch_size,
                    epochs = epochs,
                    verbose = 1)Epoch 1/50
21/21 [==============================] - 131s 4s/step - loss: 1.1424 - categorical_accuracy: 0.5333
Epoch 2/50
21/21 [==============================] - 1s 46ms/step - loss: 0.8789 - categorical_accuracy: 0.5667
Epoch 3/50
21/21 [==============================] - 1s 47ms/step - loss: 0.8383 - categorical_accuracy: 0.6429
Epoch 4/50
21/21 [==============================] - 1s 46ms/step - loss: 0.6923 - categorical_accuracy: 0.7238
Epoch 5/50
21/21 [==============================] - 1s 47ms/step - loss: 0.6391 - categorical_accuracy: 0.7619
Epoch 6/50
21/21 [==============================] - 1s 46ms/step - loss: 0.5162 - categorical_accuracy: 0.8476
Epoch 7/50
21/21 [==============================] - 1s 47ms/step - loss: 0.4239 - categorical_accuracy: 0.8857
Epoch 8/50
21/21 [==============================] - 1s 46ms/step - loss: 0.3520 - categorical_accuracy: 0.9048
Epoch 9/50
21/21 [==============================] - 1s 46ms/step - loss: 0.2975 - categorical_accuracy: 0.9238
Epoch 10/50
21/21 [==============================] - 1s 46ms/step - loss: 0.2684 - categorical_accuracy: 0.9429
Epoch 11/50
21/21 [==============================] - 1s 46ms/step - loss: 0.2073 - categorical_accuracy: 0.9524
Epoch 12/50
21/21 [==============================] - 1s 46ms/step - loss: 0.1543 - categorical_accuracy: 0.9857
Epoch 13/50
21/21 [==============================] - 1s 46ms/step - loss: 0.1023 - categorical_accuracy: 1.0000
Epoch 14/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0982 - categorical_accuracy: 0.9952
Epoch 15/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0818 - categorical_accuracy: 1.0000
Epoch 16/50
21/21 [==============================] - 1s 45ms/step - loss: 0.0742 - categorical_accuracy: 0.9952
Epoch 17/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0523 - categorical_accuracy: 0.9952
Epoch 18/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0432 - categorical_accuracy: 1.0000
Epoch 19/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0474 - categorical_accuracy: 0.9952
Epoch 20/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0523 - categorical_accuracy: 0.9952
Epoch 21/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0651 - categorical_accuracy: 1.0000
Epoch 22/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0371 - categorical_accuracy: 1.0000
Epoch 23/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0331 - categorical_accuracy: 0.9952
Epoch 24/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0277 - categorical_accuracy: 1.0000
Epoch 25/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0206 - categorical_accuracy: 1.0000
Epoch 26/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0191 - categorical_accuracy: 1.0000
Epoch 27/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0202 - categorical_accuracy: 1.0000
Epoch 28/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0203 - categorical_accuracy: 1.0000
Epoch 29/50
21/21 [==============================] - 1s 48ms/step - loss: 0.0174 - categorical_accuracy: 1.0000
Epoch 30/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0120 - categorical_accuracy: 1.0000
Epoch 31/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0133 - categorical_accuracy: 1.0000
Epoch 32/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0135 - categorical_accuracy: 1.0000
Epoch 33/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0116 - categorical_accuracy: 1.0000
Epoch 34/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0177 - categorical_accuracy: 0.9952
Epoch 35/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0256 - categorical_accuracy: 0.9952
Epoch 36/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0120 - categorical_accuracy: 1.0000
Epoch 37/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0108 - categorical_accuracy: 1.0000
Epoch 38/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0119 - categorical_accuracy: 1.0000
Epoch 39/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0101 - categorical_accuracy: 1.0000
Epoch 40/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0072 - categorical_accuracy: 1.0000
Epoch 41/50
21/21 [==============================] - 1s 48ms/step - loss: 0.0084 - categorical_accuracy: 1.0000
Epoch 42/50
21/21 [==============================] - 1s 45ms/step - loss: 0.0077 - categorical_accuracy: 1.0000
Epoch 43/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0081 - categorical_accuracy: 1.0000
Epoch 44/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0074 - categorical_accuracy: 1.0000
Epoch 45/50
21/21 [==============================] - 1s 48ms/step - loss: 0.0061 - categorical_accuracy: 1.0000
Epoch 46/50
21/21 [==============================] - 1s 45ms/step - loss: 0.0053 - categorical_accuracy: 1.0000
Epoch 47/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0052 - categorical_accuracy: 1.0000
Epoch 48/50
21/21 [==============================] - 1s 45ms/step - loss: 0.0053 - categorical_accuracy: 1.0000
Epoch 49/50
21/21 [==============================] - 1s 47ms/step - loss: 0.0043 - categorical_accuracy: 1.0000
Epoch 50/50
21/21 [==============================] - 1s 46ms/step - loss: 0.0057 - categorical_accuracy: 1.0000
# save one last time
model.save("pA_16.h5")_____no_output_____# how did we do?
# graphically display results of training
plt.figure()
plt.subplot(211)
plt.plot(plusAugmented_history.history['categorical_accuracy'])
plt.title('Using Augmented Plus Origianl Data: Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['training'], loc = 'upper left')

plt.subplot(212)
plt.plot(plusAugmented_history.history['loss'])
plt.title('Using Augmented Plus Original Data: Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['training'], loc = 'upper right')

plt.tight_layout()
plt.show()
_____no_output_____# now let's test with unseen images from the augmented plus original dataset
plusAugmented_history_test = model.evaluate(plusAugmented_test, verbose = 1)
print("Using the augmented plus original test samples:")
print("Accuracy: ", plusAugmented_history_test[1] * 100)
print("Loss: ", plusAugmented_history_test[0])9/9 [==============================] - 16s 96ms/step - loss: 0.1149 - categorical_accuracy: 0.9667
Using the augmented plus original test samples:
Accuracy:  96.66666388511658
Loss:  0.11488407850265503

AND NOW.....what we have all been waiting for....
Has this really been worth it???

Let's check our last model against the unssen images and see how it stacks up against the validation from the original model._____no_output_____

# NOW, let's test the plusAugmented model with super secret unseen original images
unseen_test_history = model.evaluate(unseen_test, verbose = 1)
print("Using completely unseen originals only:")
print("Accuracy: ", unseen_test_history[1] * 100)
print("Loss: ", unseen_test_history[0])3/3 [==============================] - 0s 14ms/step - loss: 0.9999 - categorical_accuracy: 0.7333
Using completely unseen originals only:
Accuracy:  73.33333492279053
Loss:  0.9998588562011719

And you are done!

How did it go?  Use the accuracy from the 'unseen_test_history' and compare it to the accuracy from the 'unseen_test_history' from before to figure out what level of improvement you achieved.

One thing you may find is that every time you train up the models (even reusing the same data over and over) you can get different results.
During the course of our testing, our results showed varying degrees of improvement.

We hope you found this demo informative and enjoyable._____no_output_____


# Notebook from regifukuchi/bmc-1
Path: notebooks/FreeBodyDiagramForRigidBodies.ipynb

# Free Body Diagram for Rigid Bodies

Renato Naville Watanabe_____no_output_____

import numpy as np
import matplotlib.pyplot as plt
%matplotlib notebook_____no_output_____

## Equivalent systems

A set of forces and moments is considered equivalent if its resultant force and sum of the moments computed relative to a given point are the same. Normally, we want to reduce all the forces and moments being applied to a body into a single force and a single moment.

We have done this with particles for the resultant force. The resultant force is simply the sum of all the forces being applied to the body.

\begin{equation}
    \vec{\bf{F}} = \sum\limits_{i=1}^n \vec{\bf{F_i}}
\end{equation}

where $\vec{\bf{F_i}}$ is each force applied to the body.

Similarly, the total moment applied to the body relative to a point O is:

\begin{equation}
    \vec{\bf{M_O}} = \sum\limits_{i}\vec{\bf{r_{i/O}}} \times \vec{\bf{F_i}}
\end{equation}

where $\vec{\bf{r_{i/O}}} $ is the vector from the point O to the point where the force $\vec{\bf{F_i}}$ is being applied.

But where the resultant force should be applied in the body? If the resultant force were applied to any point different from the point O, it would produce an additional  moment to the body relative to point O. So, the resultant force must be applied to the point O.

So, any set of forces can be reduced to a moment relative to a chosen point O and a resultant force applied to the point O.

To compute the resultant force and moment relative to another point O', the new moment is:

\begin{equation}
    \vec{\bf{M_{O'}}} = \vec{\bf{M_O}} + \vec{\bf{r_{O'/O}}} \times \vec{\bf{F}}
\end{equation}

And the resultant force is the same.

It is worth to note that if the resultant force  $\vec{\bf{F}}$ is zero, than the moment is the same relative to any point.

_____no_output_____### Steps to draw a free-body diagram

The steps to draw the free-body diagram of a body is very similar to the case of particles.

1 - Draw separately each object considered in the problem. How you separate depends on what questions you want to answer.

2 - Identify the forces acting on each object. If you are analyzing more than one object, remember the third Newton law (action and reaction), and identify where the reaction of a force is being applied. Whenever a movement of translation of the body is constrained, a force at the direction of the constraint must exist.

3 - Identify the moments acting on each object. In the case you are analyzing more than one object, you must consider the  action and reaction law (third Newton-Euler law). Whenever a movement of rotation of the body is constrained, a moment at the direction of the constraint must exist.

4 - Draw all the identified forces, representing them as vectors. The vectors should be represented with the origin in the object.

5 - Draw all the identified moments, representing them as vectors. In planar movements, the moments we be orthogonal to the considered plane. In these cases, normally the moment vectors are represented as curved arrows.

6 - If necessary, you should represent the reference frame (or references frames in case you use more than one reference frame) in the free-body diagram.

7 - After this, you can solve the problem using the First and Second Newton-Euler  Laws (see, e.g,  [Newton-Euler Laws](newton_euler_equations.ipynb)) to find the motion of the body.

\begin{equation}
    \vec{\bf{F}} = m\vec{\bf{a_{cm}}} = m\frac{d^2\vec{\bf{r_{cm}}}}{dt^2}
\end{equation}

\begin{equation}
    \vec{\bf{M_O}} = I_{zz}^{cm}\alpha + m \vec{\bf{r_{cm/O}}} \times \vec{\bf{a_{cm}}}=I_{zz}^{cm}\frac{d^2\theta}{dt^2} + m \vec{\bf{r_{cm/O}}} \times \frac{d^2\vec{\bf{r_{cm}}}}{dt^2}
\end{equation}
_____no_output_____Below, we will see some examples of how to draw the free-body diagram and obtain the equation of motion._____no_output_____## 1) Horizontal fixed bar

The first example is an example of statics. The bar has no velocity and no acceleration.

The free-body diagram of the bar is depicted below. At the point where the bar is connected to the wall, there is a force $\vec{\bf{F_1}}$ constraining the translation movement of the point O and a moment $\vec{\bf{M}}$ constraining the rotation of the bar.

The resultant force being applied to the bar is:

\begin{equation}
    \vec{\bf{F}} = -mg\hat{\bf{j}} + \vec{\bf{F_1}}
\end{equation}

And the total moment in the z direction around the point O is:

\begin{equation}
    \vec{\bf{M_O}} = \vec{\bf{r_{C/O}}}\times-mg\hat{\bf{j}} + \vec{\bf{M}}
\end{equation}

The vector from the point O to the point C is given by $\vec{\bf{r_{C/O}}} =\frac{l}{2}\hat{\bf{i}}$.

As the bar is fixed, all the accelerations are zero. So we can find the forces and the moment at the constraint.

\begin{equation}
    \vec{\bf{F}} = \vec{\bf{0}} \rightarrow -mg\hat{\bf{j}} + \vec{\bf{F_1}} = \vec{\bf{0}} \rightarrow   \vec{\bf{F_1}} = mg\hat{\bf{j}}
\end{equation}

\begin{equation}
    \vec{\bf{M_O}} = \vec{\bf{0}} \rightarrow  \vec{\bf{r_{C/O}}}\times-mg\hat{\bf{j}} + \vec{\bf{M}} = \vec{\bf{0}} \rightarrow \frac{l}{2}\hat{\bf{i}}\times-mg\hat{\bf{j}} + \vec{\bf{M}} = \vec{\bf{0}} \rightarrow -\frac{mgl}{2}\hat{\bf{k}} + \vec{\bf{M}} = \vec{\bf{0}} \rightarrow \vec{\bf{M}} = \frac{mgl}{2}\hat{\bf{k}}
\end{equation}

_____no_output_____## 2) Rotating ball with drag force

A basketball has a mass $m = 0.63$ kg and radius equal $R = 12$ cm. A basketball player shots the ball from the free-throw line (4.6 m from the basket) with a speed of 9.5 m/s, angle of 51 degrees with the court, height of 2 m and angular velocity of 42 rad/s. At the ball is acting a drag force proportional to the modulus of the ball velocity in the opposite direction of the velocity and a drag moment, proportional and in the opposite direction of the angular velocity of the ball. Consider the moment of inertia of the ball as $I_{zz}^{cm} = \frac{2mR^2}{3}$.

Below is depicted the free-body diagram of the ball.

The resultant force being applied at the ball is:

\begin{equation}
    \vec{\bf{F}} = -mg\hat{\bf{j}} - b_l\vec{\bf{v}} + b_m\omega\hat{\bf{k}}\times \vec{\bf{v}} = -mg\hat{\bf{j}} - b_l\frac{d\vec{\bf{r}}}{dt} = -mg\hat{\bf{j}} - b_l\frac{d\vec{\bf{r}}}{dt}
\end{equation}

\begin{equation}
    \vec{\bf{M_C}} = - b_r\omega\hat{\bf{k}}=- b_r\frac{d\theta}{dt}\hat{\bf{k}}
\end{equation}

\begin{equation}
    \frac{d\vec{\bf{H_C}}}{dt} = I_{zz}^{C}\frac{d^2\theta}{dt^2}\hat{\bf{k}}
\end{equation}

So, by the second Newton-Euler law:

\begin{equation}
    \frac{d\vec{\bf{H_C}}}{dt}=\vec{\bf{M_C}} \rightarrow I_{zz}^{C}\frac{d^2\theta}{dt^2} = - b_r\frac{d\theta}{dt}
\end{equation}

and by the first Newton-Euler law (for a revision on Newton-Euler laws, [see this notebook](newton_euler_equations.ipynb)):

\begin{equation}
    m\frac{d\vec{\bf{r}}}{dt}=\vec{\bf{F}} \rightarrow \frac{d\vec{\bf{r}}}{dt} = -g\hat{\bf{j}} - \frac{b_l}{m}\frac{d\vec{\bf{r}}}{dt}
\end{equation}

So, we can split the differential equations above in three equations:

\begin{equation}
    \frac{d^2\theta}{dt^2} = - \frac{b_r}{I_{zz}^{C}}\frac{d\theta}{dt}
\end{equation}

\begin{equation}
    \frac{d^2x}{dt^2} = - \frac{b_l}{m}\frac{dx}{dt}
\end{equation}

\begin{equation}
    \frac{d^2y}{dt^2} = -g - \frac{b_l}{m}\frac{dy}{dt}
\end{equation}

To solve these equations numerically, we can split each of these equations in first-order equations and the use a numerical method to integrate them. The first-order equations we be written in a matrix form, considering the moment of inertia of the ball as $I_{zz}^{C}=\frac{2mR^2}{3}$:

\begin{equation}
    \left[\begin{array}{c}\frac{d\omega}{dt}\\\frac{dv_x}{dt}\\\frac{dv_y}{dt}\\\frac{d\theta}{dt}\\\frac{dx}{dt}\\\frac{dy}{dt} \end{array}\right] = \left[\begin{array}{c}- \frac{3b_r}{2mR^2}\omega\\- \frac{b_l}{m}v_x\\-g - \frac{b_l}{m}v_y\\\omega\\v_x\\v_y\end{array}\right]
\end{equation}

Below, the equations were solved numerically by using the Euler method (for a revision on numerical methods to solve ordinary differential equations, [see this notebook](OrdinaryDifferentialEquation.ipynb))._____no_output_____

m = 0.63
R = 0.12
I = 2.0/3*m*R**2

bl = 0.5
br = 0.001
g = 9.81

x0 = 0
y0 = 2

v0 = 9.5
angle = 51*np.pi/180.0

vx0 = v0*np.cos(angle)
vy0 = v0*np.sin(angle)

dt = 0.001
t = np.arange(0, 2.1, dt)

x = x0
y = y0
vx = vx0
vy = vy0

omega = 42
theta = 0

r = np.array([x,y])
ballAngle = np.array([theta])

state = np.array([omega, vx, vy, theta, x, y])

while state[4]<=4.6:

    dstatedt = np.array([-br/I*state[0],-bl/m*state[1], -g-bl/m*state[2],state[0], state[1], state[2] ])
    state = state + dt * dstatedt

    r = np.vstack((r, [state[4], state[5]]))
    ballAngle = np.vstack((ballAngle, [state[3]]))

plt.figure()
plt.plot(r[0:-1:50,0], r[0:-1:50,1], 'o', color = np.array([1, 0.6,0]), markerSize =10)
plt.plot(np.array([4, 4.45]), np.array([3.05, 3.05]))
for i in range(len(r[0:-1:50,0])):
    plt.plot(r[i*50,0]+np.array([-0.05*(np.cos(ballAngle[i*50])-np.sin(ballAngle[i*50])), 0.05*(np.cos(ballAngle[i*50])-np.sin(ballAngle[i*50]))]),
             r[i*50,1] + np.array([-0.05*(np.sin(ballAngle[i*50])+np.cos(ballAngle[i*50])), 0.05*(np.sin(ballAngle[i*50])+np.cos(ballAngle[i*50]))]),'k')
plt.ylim((0,4.5))
plt.show()
print(state[0])_____no_output_____

Above is the trajectory of the ball until it reaches the basket (height of 3.05 m, marked with a blue line)._____no_output__________no_output_____## 3) Pendulum

Now, we will analyze a pendulum. It consists of a bar with its upper part linked to a hinge.

Below is the free-body diagram of the bar. On the center of mass of the bar is acting the gravitational force. On the point O, where there is a hinge, a force $\vec{\bf{F_1}}$ restrains the point to translate. As the hinge does not constrains a rotational movement of the bar, there is no moment applied by the hinge.

To find the equation of motion of the bar we can use the second Newton-Euler law. So, we must find the sum of the moments and the resultant force being applied to the bar. The sum of moments could be computed relative to any point, but if we choose the fixed point O, it is easier because we can ignore the force $\vec{\bf{F_1}}$.

The moment around the fixed point is:

\begin{equation}
    \vec{\bf{M_O}} = \vec{\bf{r_{cm/O}}} \times (-mg\hat{\bf{j}})
\end{equation}

The resultant force applied in the bar is:

\begin{equation}
        \vec{\bf{F}} = -mg\hat{\bf{j}} + \vec{\bf{F_1}}
\end{equation}

The angular momentum derivative of the bar around point O is:

\begin{equation}
    \frac{d\vec{\bf{H_O}}}{dt} = I_{zz}^{cm} \frac{d^2\theta}{dt^2} \hat{\bf{k}}  + m \vec{\bf{r_{cm/O}}} \times \vec{\bf{a_{cm}}}
\end{equation}

The vector from point O to the center of mass is:

\begin{equation}
    \vec{\bf{r_{cm/O}}} = \frac{l}{2}\sin{\theta}\hat{\bf{i}}-\frac{l}{2}\cos{\theta}\hat{\bf{j}}
\end{equation}

The position of the center of mass is, considering the point O as the origin, equal to $\vec{\bf{r_{cm/O}}}$. So, the center of mass acceleration is obtained by deriving it twice.

\begin{equation}
    \vec{\bf{v_{cm}}} = \frac{\vec{\bf{r_{cm/O}}}}{dt} = \frac{l}{2}(\cos{\theta}\hat{\bf{i}}+\sin{\theta}\hat{\bf{j}})\frac{d\theta}{dt} \rightarrow \vec{\bf{a_{cm}}} = \frac{l}{2}(-\sin{\theta}\hat{\bf{i}}+\cos{\theta}\hat{\bf{j}})\left(\frac{d\theta}{dt}\right)^2 + \frac{l}{2}(\cos{\theta}\hat{\bf{i}}+\sin{\theta}\hat{\bf{j}})\frac{d^2\theta}{dt^2}
\end{equation}

So, the moment around the point O:

\begin{equation}
    \vec{\bf{M_O}} = \left(\frac{l}{2}\sin{\theta}\hat{\bf{i}}-\frac{l}{2}\cos{\theta}\hat{\bf{j}}\right) \times (-mg\hat{\bf{j}}) = \frac{-mgl}{2}\sin{\theta}\hat{\bf{k}}
\end{equation}

And the derivative of the angular momentum is:

\begin{equation}
    \frac{d\vec{\bf{H_O}}}{dt} = I_{zz}^{cm} \frac{d^2\theta}{dt^2}\hat{\bf{k}}  + m \frac{l}{2}(\sin{\theta}\hat{\bf{i}}-\cos{\theta}\hat{\bf{j}}) \times \left[ \frac{l}{2}(-\sin{\theta}\hat{\bf{i}}+\cos{\theta}\hat{\bf{j}})\left(\frac{d\theta}{dt}\right)^2 + \frac{l}{2}(\cos{\theta}\hat{\bf{i}}+\sin{\theta}\hat{\bf{j}})\frac{d^2\theta}{dt^2}    \right] = I_{zz}^{cm} \frac{d^2\theta}{dt^2}\hat{\bf{k}}  + m \frac{l^2}{4}\frac{d^2\theta}{dt^2} \hat{\bf{k}}  =\left(I_{zz}^{cm} + \frac{ml^2}{4}\right)\frac{d^2\theta}{dt^2} \hat{\bf{k}}
\end{equation}

Now, by using the Newton-Euler laws, we can obtain the differential equation that describes the bar angle along time:

\begin{equation}
    \frac{d\vec{\bf{H_O}}}{dt} = \vec{\bf{M_O}} \rightarrow \frac{-mgl}{2}\sin{\theta} = \left(I_{zz}^{cm} + \frac{ml^2}{4}\right)\frac{d^2\theta}{dt^2} \rightarrow \frac{d^2\theta}{dt^2} = \frac{-2mgl}{\left(4I_{zz}^{cm} + ml^2\right)}\sin{\theta}
\end{equation}

The moment of inertia of the bar relative to its center of mass is $I_{zz}^{cm} = \frac{ml^2}{12}$ (for a revision on moment of inertia see [this notebook](CenterOfMassAndMomentOfInertia.ipynb)).  So, the equation of motion of the pendulum is:

\begin{equation}
    \frac{d^2\theta}{dt^2} = \frac{-3g}{2l}\sin{\theta}
\end{equation}_____no_output_____## 4) Inverted Pendulum

At this example we analyze the inverted pendulum. It consists of a bar with its lowest extremity linked to a hinge.

 The free-body diagram of the bar is depicted below. At the point where the bar is linked to the hinge, a force $\vec{\bf{F_1}}$ acts at the bar due to the restraint of the translation imposed to the point O by the hinge. Additionally, the gravitational force acts at the center of mass of the bar.

Similarly to pendulum, in this case we can find the equation of motion of the bar by using the second Newton-Euler law. To do that we must find the sum of the moments and the resultant force being applied to the bar. The sum of moments could be computed relative to any point, but if we choose the fixed point O, it is easier because we can ignore the force $\vec{\bf{F_1}}$.

The moment around the fixed point is:

\begin{equation}
    \vec{\bf{M_O}} = \vec{\bf{r_{cm/O}}} \times (-mg\hat{\bf{j}})
\end{equation}

The resultant force applied in the bar is:

\begin{equation}
        \vec{\bf{F}} = -mg\hat{\bf{j}} + \vec{\bf{F_1}}
\end{equation}

The angular momentum derivative of the bar around point O is:

\begin{equation}
    \frac{d\vec{\bf{H_O}}}{dt} = I_{zz}^{cm} \frac{d^2\theta}{dt^2} \hat{\bf{k}}  + m \vec{\bf{r_{cm/O}}} \times \vec{\bf{a_{cm}}}
\end{equation}

Until this part, the equations are exactly the same of the pendulum example. The difference is in the kinematics of the bar. Now,the vector from point O to the center of mass is:

\begin{equation}
    \vec{\bf{r_{cm/O}}} = -\frac{l}{2}\sin{\theta}\hat{\bf{i}}+\frac{l}{2}\cos{\theta}\hat{\bf{j}}
\end{equation}

The position of the center of mass of the bar is equal to the vector $\vec{\bf{r_{cm/O}}}$, since the point O is with velocity zero relative to the global reference frame. So the center of mass acceleration can be obtained by deriving this vector twice:

\begin{equation}
    \vec{\bf{v_{cm}}} = \frac{\vec{\bf{r_{cm/O}}}}{dt} = -\frac{l}{2}(\cos{\theta}\hat{\bf{i}}+\sin{\theta}\hat{\bf{j}})\frac{d\theta}{dt} \rightarrow \vec{\bf{a_{cm}}} = \frac{l}{2}(\sin{\theta}\hat{\bf{i}}-\cos{\theta}\hat{\bf{j}})\left(\frac{d\theta}{dt}\right)^2 - \frac{l}{2}(\cos{\theta}\hat{\bf{i}}+\sin{\theta}\hat{\bf{j}})\frac{d^2\theta}{dt^2}
\end{equation}

So, the moment around the point O is:

\begin{equation}
    \vec{\bf{M_O}} = \left(-\frac{l}{2}\sin{\theta}\hat{\bf{i}}+\frac{l}{2}\cos{\theta}\hat{\bf{j}}\right) \times (-mg\hat{\bf{j}}) = \frac{mgl}{2}\sin{\theta} \hat{\bf{k}}
\end{equation}

And the derivative of the angular momentum is:

\begin{equation}
    \frac{d\vec{\bf{H_O}}}{dt} = I_{zz}^{cm} \frac{d^2\theta}{dt^2} \hat{\bf{k}}  + m \left(-\frac{l}{2}\sin{\theta}\hat{\bf{i}}+\frac{l}{2}\cos{\theta}\hat{\bf{j}}\right) \times \left[\frac{l}{2}(\sin{\theta}\hat{\bf{i}}-\cos{\theta}\hat{\bf{j}})\left(\frac{d\theta}{dt}\right)^2 - \frac{l}{2}(\cos{\theta}\hat{\bf{i}}+\sin{\theta}\hat{\bf{j}})\frac{d^2\theta}{dt^2}\right] = I_{zz}^{cm} \frac{d^2\theta}{dt^2} \hat{\bf{k}}  + m \frac{l^2}{4}\frac{d^2\theta}{dt^2}\hat{\bf{k}} = \left(I_{zz}^{cm} +  \frac{ml^2}{4}\right)\frac{d^2\theta}{dt^2}\hat{\bf{k}}
\end{equation}

By using the Newton-Euler laws, we can find the equation of motion of the bar:

\begin{equation}
    \frac{d\vec{\bf{H_O}}}{dt} = \vec{\bf{M_O}} \rightarrow \left(I_{zz}^{cm} +  \frac{ml^2}{4}\right)\frac{d^2\theta}{dt^2} = \frac{mgl}{2}\sin{\theta} \rightarrow \frac{d^2\theta}{dt^2} = \frac{2mgl}{\left(4I_{zz}^{cm} + ml^2\right)}\sin(\theta)
\end{equation}

The moment of inertia of the bar is $I_{zz}^{cm} = \frac{ml^2}{12}$. So, the equation of motion of the bar is:

\begin{equation}
    \frac{d^2\theta}{dt^2} = \frac{3g}{2l}\sin(\theta)
\end{equation}
_____no_output__________no_output_____## 5) Human quiet standing

A very simple model of the human quiet standing (and still today frequently used) is to use an inverted pendulum to model the human body. On [this notebook](http://nbviewer.jupyter.org/github/demotu/BMC/blob/master/notebooks/IP_Model.ipynb) there is a more comprehensive explanation of human standing.

Adapted from [Elias, Watanabe and Kohn (2014)](http://dx.doi.org/10.1371/journal.pcbi.1003944)

Below is depicted the free-body diagram of the foot and the rest of the body. At the ankle joint there is a constraint to the translation of the ankle joint. So, a force $\vec{\bf{F_1}}$ is applied to the body at the ankle joint. By the third Newton law, a force  $-\vec{\bf{F_1}}$ is applied to the foot at the ankle joint. At the center of mass of the body and of the foot, gravitational forces are applied. Additionally, a ground reaction force is applied to the foot at the center of pressure of the forces applied at the foot.

Additionally, a moment $\vec{\bf{T_A}}$ is applied at the body and its reaction is applied to the foot. This moment $\vec{\bf{T_A}}$ comes from the muscles around the ankle joint. It is usual in Biomechanics to represent the net torque generated by all the muscles on a single joint as a single moment applied to the body.

The process to obtain the equation of motion of the angle is very similar. The moment around the ankle being applied to the body is:

\begin{equation}
    \vec{\bf{M_A}} = \vec{\bf{T_A}} + \vec{\bf{r_{cm/A}}} \times (-m_Bg\hat{\bf{j}})
\end{equation}

And the derivative of the angular momentum is:

\begin{equation}
    \frac{d\vec{\bf{H_A}}}{dt} = I_{zz}^{cm}\frac{d\theta_A}{dt} + m\vec{\bf{r_{cm/A}}} \times \vec{\bf{a_{cm}}}
\end{equation}

To find the kinematics of the bar, we could do the same procedure we have used in the pendulum and inverted pendulum examples, but this time we will use polar coordinates (for a revision on polar coordinates, see [Polar coordinates notebook](PolarCoordinates.ipynb)).

\begin{equation}
    \vec{\bf{r_{cm/A}}} = \vec{\bf{r_{cm}}} = h_G\hat{\bf{e_r}} \rightarrow \vec{\bf{v_{cm}}} = h_G\frac{d\theta_A}{dt}\hat{\bf{e_\theta}} \rightarrow \vec{\bf{a_{cm}}} = -h_G\left(\frac{d\theta_A}{dt}\right)^2\hat{\bf{e_r}} + h_G\frac{d^2\theta_A}{dt^2}\hat{\bf{e_\theta}}
\end{equation}

where $\hat{\bf{e_r}} = -\sin(\theta_A)\hat{\bf{i}} + \cos(\theta_A)\hat{\bf{j}}$ and $\hat{\bf{e_\theta}} = -\cos(\theta_A)\hat{\bf{i}} - \sin(\theta_A)\hat{\bf{j}}$

Having the kinematics computed, we can go back to the moment and derivative of the angular momentum:

\begin{equation}
     \vec{\bf{M_A}} =  \vec{\bf{T_A}} + h_G\hat{\bf{e_r}} \times (-m_Bg\hat{\bf{j}}) = T_A\hat{\bf{k}} + h_Gm_Bg\sin(\theta_A)\hat{\bf{k}}
\end{equation}

\begin{equation}
    \frac{d\vec{\bf{H_A}}}{dt} = I_{zz}^{cm}\frac{d^2\theta_A}{dt^2} \hat{\bf{k}} + mh_G\hat{\bf{e_r}} \times \left(-h_G\left(\frac{d^2\theta_A}{dt^2}\right)^2\hat{\bf{e_r}} + h_G\frac{d^2\theta_A}{dt^2}\hat{\bf{e_\theta}}\right) = I_{zz}^{cm}\frac{d^2\theta_A}{dt^2}\hat{\bf{k}} + mh_G^2\frac{d^2\theta_A}{dt^2}\hat{\bf{k}} = \left(I_{zz}^{cm} + mh_G^2\right)\frac{d^2\theta_A}{dt^2}\hat{\bf{k}}
\end{equation}

By using the Newton-Euler equations, we can now find the equation of motion of the body during quiet standing:

\begin{equation}
    \vec{\bf{M_A}}=\frac{d\vec{\bf{H_A}}}{dt} \rightarrow  \left(I_{zz}^{cm} + mh_G^2\right)\frac{d^2\theta_A}{dt^2} =  T_A + h_Gm_B g\sin(\theta_A) \rightarrow \frac{d^2\theta_A}{dt^2} = \frac{h_Gm_B g}{I_{zz}^{cm} + mh_G^2}\sin(\theta_A)+ \frac{T_A}{I_{zz}^{cm} + m_Bh_G^2}
\end{equation}

If we consider the body as a rigid uniform bar, the moment of inertia is $I_{zz}^{cm} = \frac{m_Bh_G^2}{3}$. So, the equation of motion of the body is:

\begin{equation}
    \frac{d^2\theta_A}{dt^2} = \frac{3 g}{4h_g}\sin(\theta_A)+ \frac{3 T_A}{4m_bh_G^2}
\end{equation}_____no_output_____## 6) Force platform

From the same example above, now we will find the position of the center of pressure during the quiet standing. The center of pressure is the point where the ground reaction force is being applied. The point O is linked to the ground in a way that it constraints the translation and rotation movement of the platform. Also, it is in the point O that sensors of force and moments are located.

The free-body diagram of the foot and the force platform is depicted below.

In the platform , the distance $y_0$ is known. As the platform is in equilibrium its derivative of the angular momentum is zero. Now, we must find the sum of the moments. As we can choose any point, we will choose, the point where the force $\vec{\bf{F}}$ is being applied, and equal it to zero.

\begin{equation}
    \vec{\bf{M}} + \vec{\bf{r_{COP/O}}} \times (-\vec{\bf{GRF}}) = 0
\end{equation}

The vector $\vec{\bf{r_{COP/O}}}$ is:

\begin{equation}
    \vec{\bf{r_{COP/O}}} = COP_x \hat{\bf{i}} + y_0 \hat{\bf{j}}
\end{equation}

So, from the equation of the sum of the moments we can isolate the postion of the center of pressure:

\begin{equation}
    M - COP_x GRF_y + y_0 GRF_x = 0 \rightarrow COP_x = \frac{M+y_0 GRF_x}{GRF_y}
\end{equation}

Using the expression above, we can track the position of the center of pressure during an experiment._____no_output_____## 7) Segway

The horizontal acceleration of the point A $a_A$ of the segway is known. There is a motor at point A that generates a moment $\vec{\bf{T}}$ at the bar.

The free-body diagrams of the upper part of the segway and the cart are depicted below. At the upper part are applied the moment $\vec{\bf{T}}$ due to the motor, the gravitational force at the center of mass of the bar and the constraint force at the hinge at the point A. At the cart are applied the ground reaction force, the reaction of $\vec{\bf{F_1}}$ at the hinge and the reaction of the moment due to the motor. As the cart has an acceleration, there is a force $\vec{\bf{F}}$ to produce an acceleration.

The equation of motion of the bar can be obtained by using the Newton-Euler equations.

Considering the  bar, the moment around the point A is:

\begin{equation}
    \vec{\bf{M_A}} = \vec{\bf{r_{cm/A}}} \times (-mg\hat{\bf{j}}) + \vec{\bf{T}}
\end{equation}

And the derivative of the angular momentum around the point A is:

\begin{equation}
        \frac{d\vec{H_A}}{dt} = I_{zz}^{cm}\frac{d^2\theta}{dt^2}+m\vec{\bf{r_{cm/A}}}\times \vec{\bf{a_{cm}}}
\end{equation}

The vector from the point A to the center of mass is:

\begin{equation}
    \vec{\bf{r_{cm/A}}} = \frac{l}{2}\hat{\bf{e_R}}
\end{equation}

and the acceleration of the center of mass is obtained by deriving the position of the center of mass twice:

\begin{equation}
    \vec{\bf{r_{cm}}} = \vec{\bf{r_{A}}} + \vec{\bf{r_{cm/A}}} = \vec{\bf{r_{A}}} + \frac{l}{2}\hat{\bf{e_R}} \rightarrow  \vec{\bf{v_{cm}}} = \vec{\bf{v_{A}}} + \frac{l}{2}\frac{d\theta}{dt}\hat{\bf{e_\theta}} \rightarrow  \vec{\bf{a_{cm}}} = \vec{\bf{a_{A}}} - \frac{l}{2}\left(\frac{d\theta}{dt}\right)^2\hat{\bf{e_R}}+\frac{l}{2}\frac{d^2\theta}{dt^2}\hat{\bf{e_\theta}}
\end{equation}

where $\hat{\bf{e_R}} = -\sin(\theta)\hat{\bf{i}}+\cos(\theta)\hat{\bf{j}}$ and $\hat{\bf{e_\theta}} = -\cos(\theta)\hat{\bf{i}}-\sin(\theta)\hat{\bf{j}}$.

Using the Newton-Euler laws, we can find the equation of motion of the upper part of the segway:

\begin{equation}
    \frac{d\vec{H_A}}{dt} = \vec{\bf{M_A}} \rightarrow  I_{zz}^{cm}\frac{d^2\theta}{dt^2}\hat{\bf{k}}+m\vec{\bf{r_{cm/A}}}\times \vec{\bf{a_{cm}}} =  \vec{\bf{r_{cm/A}}} \times (-mg\hat{\bf{j}}) + \vec{\bf{T}} \rightarrow I_{zz}^{cm}\frac{d^2\theta}{dt^2}+m\frac{l}{2}\hat{\bf{e_R}}\times\left(a_{A}\hat{\bf{i}} - \frac{l}{2}\left(\frac{d\theta}{dt}\right)^2\hat{\bf{e_R}}+\frac{l}{2}\frac{d^2\theta}{dt^2}\hat{\bf{e_\theta}}\right) = ( \frac{l}{2}\hat{\bf{e_R}} \times (-mg\hat{\bf{j}}) + \vec{\bf{T}}) \rightarrow I_{zz}^{cm}\frac{d^2\theta}{dt^2}\hat{\bf{k}}-\frac{ml}{2}a_{A}\cos(\theta)\hat{\bf{k}} +\frac{ml^2}{4}\frac{d^2\theta}{dt^2}\hat{\bf{k}} = \frac{mgl}{2}\sin(\theta)\hat{\bf{k}} + T\hat{\bf{k}}
\end{equation}

So, the equation of motion of the upper part of the segway is:

\begin{equation}
    \frac{d^2\theta}{dt^2} = \frac{mgl}{2\left(I_{zz}^{cm}+\frac{ml^2}{4}\right)}\sin(\theta) + \frac{ml}{2\left(I_{zz}^{cm}+\frac{ml^2}{4}\right)}a_{A}\cos(\theta)+ \frac{T}{\left(I_{zz}^{cm}+\frac{ml^2}{4}\right)}
\end{equation}

Considering the moment of inertia of the bar is $I_{zz}^{cm}=\frac{ml^2}{12}$, the equation of motion of the bar is:

\begin{equation}
     \frac{d^2\theta}{dt^2} = \frac{3g}{2l}\sin(\theta) + \frac{3ml}{2ml^2}a_{A}\cos(\theta)+ \frac{3T}{2ml^2}
\end{equation}_____no_output__________no_output_____## 8) Double pendulum with actuators

The figure below shows a  double pendulum. This model can represent, for example, the arm and forearm of a subject.

The free-body diagrams of both bars are depicted below. There are constraint  forces at all joints and moments from the muscles from both joints.

The versors $\hat{\bf{e_{R_1}}}$, $\hat{\bf{e_{R_2}}}$, $\hat{\bf{e_{\theta_1}}}$ and $\hat{\bf{e_{\theta_2}}}$ are defined as:

\begin{equation}
    \hat{\bf{e_{R_1}}} = \sin(\theta_1) \hat{\bf{i}} - \cos(\theta_1) \hat{\bf{j}}
\end{equation}

\begin{equation}
    \hat{\bf{e_{\theta_1}}} = \cos(\theta_1) \hat{\bf{i}} + \sin(\theta_1) \hat{\bf{j}}
\end{equation}

\begin{equation}
    \hat{\bf{e_{R_2}}} = \sin(\theta_2) \hat{\bf{i}} - \cos(\theta_2) \hat{\bf{j}}
\end{equation}

\begin{equation}
    \hat{\bf{e_{\theta_2}}} = \cos(\theta_2) \hat{\bf{i}} + \sin(\theta_2) \hat{\bf{j}}
\end{equation}_____no_output_____First, we can analyze the sum of the moments and the derivative of the angular momentum at the upper bar. They will be computed relative to the point O1.

\begin{equation}
    \vec{\bf{M_{O1}}} = \vec{\bf{r_{C1/O1}}} \times (-m_1g\hat{\bf{j}}) + \vec{\bf{r_{O2/O1}}} \times (-\vec{\bf{F_{12}}}) + \vec{\bf{M_{1}}} - \vec{\bf{M_{12}}} = \frac{l_1}{2}  \hat{\bf{e_{R_1}}}  \times (-m_1g\hat{\bf{j}}) + l_1\hat{\bf{e_{R_1}}} \times (-\vec{\bf{F_{12}}}) + \vec{\bf{M_{1}}} - \vec{\bf{M_{12}}} = \frac{-m_1gl_1}{2}\sin(\theta_1)\hat{\bf{k}} + l_1\hat{\bf{e_{R_1}}} \times (-\vec{\bf{F_{12}}}) + \vec{\bf{M_{1}}} - \vec{\bf{M_{12}}}
\end{equation}

\begin{equation}
    \frac{d\vec{\bf{H_{O1}}}}{dt} = I_{zz}^{C1} \frac{d^2\theta_1}{dt^2} + m_1 \vec{\bf{r_{C1/O1}}} \times \vec{\bf{a_{C1}}} = I_{zz}^{C1} \frac{d^2\theta_1}{dt^2} + m_1 \frac{l_1}{2}  \hat{\bf{e_{R_1}}} \times \left[-\frac{l_1}{2}\left(\frac{d\theta_1}{dt}\right)^2 \hat{\bf{e_{R_1}}} + \frac{l_1}{2}\frac{d^2\theta_1}{dt^2} \hat{\bf{e_{\theta_1}}}\right] = \left( I_{zz}^{C1}  + m_1 \frac{l_1^2}{4}\right)\frac{d^2\theta_1}{dt^2}
\end{equation}

Note that the force $\vec{\bf{F_{12}}}$ is unknown. We will take care of this later._____no_output_____Now, we analyze the the sum of the moments and the derivative of the angular momentum at the lower bar relative to the point O2.

\begin{equation}
    \vec{\bf{M_{O2}}} = \vec{\bf{r_{C2/O2}}} \times (-m_2g\hat{\bf{j}}) + \vec{\bf{M_{12}}} =  \frac{l_2}{2}   \hat{\bf{e_{R_2}}} \times (-m_2g\hat{\bf{j}}) + \vec{\bf{M_{12}}} = -\frac{m_2gl_2}{2}\sin(\theta_2)\hat{\bf{k}} + \vec{\bf{M_{12}}}
\end{equation}

\begin{equation}
    \frac{d\vec{\bf{H_{O2}}}}{dt} = I_{zz}^{C2} \frac{d^2\theta_2}{dt^2} + m_2 \vec{\bf{r_{C2/O2}}} \times \vec{\bf{a_{C2}}} = I_{zz}^{C2} \frac{d^2\theta_2}{dt^2} + m_2 \frac{l_2}{2}  \hat{\bf{e_{R_2}}} \times \left[-l_1\left(\frac{d\theta_1}{dt}\right)^2 \hat{\bf{e_{R_1}}} + l_1\frac{d^2\theta_1}{dt^2} \hat{\bf{e_{\theta_1}}} -\frac{l_2}{2}\left(\frac{d\theta_2}{dt}\right)^2 \hat{\bf{e_{R_2}}} + \frac{l_2}{2}\frac{d^2\theta_2}{dt^2} \hat{\bf{e_{\theta_2}}}\right]
\end{equation}_____no_output_____To complete the computation of the derivative of the angular momentum we must find the products $\hat{\bf{e_{R_2}}} \times \hat{\bf{e_{R_1}}} $,  $\hat{\bf{e_{R_2}}} \times \hat{\bf{e_{\theta_1}}}$ and $\hat{\bf{e_{R_1}}} \times \hat{\bf{e_{\theta_2}}}$:

\begin{equation}
    \hat{\bf{e_{R_2}}} \times \hat{\bf{e_{\theta_1}}} = \left[\begin{array}{c}\sin(\theta_2)\\-\cos(\theta_2)\end{array}\right] \times \left[\begin{array}{c}\cos(\theta_1)\\\sin(\theta_1)\end{array}\right] = \sin(\theta_1)\sin(\theta_2)+\cos(\theta_1)\cos(\theta_2) = \cos(\theta_1-\theta_2)
\end{equation}

\begin{equation}
    \hat{\bf{e_{R_2}}} \times \hat{\bf{e_{R_1}}} = \left[\begin{array}{c}\sin(\theta_2)\\-\cos(\theta_2)\end{array}\right] \times \left[\begin{array}{c}\sin(\theta_1)\\-\cos(\theta_1)\end{array}\right] = -\sin(\theta_2)\cos(\theta_1)+\cos(\theta_2)\sin(\theta_1) = \sin(\theta_1-\theta_2)
\end{equation}

\begin{equation}
    \hat{\bf{e_{R_1}}} \times \hat{\bf{e_{\theta_2}}} =\left[\begin{array}{c}\sin(\theta_1)\\-\cos(\theta_1)\end{array}\right] \times \left[\begin{array}{c}\cos(\theta_2)\\\sin(\theta_2)\end{array}\right] = \sin(\theta_2)\sin(\theta_1)+\cos(\theta_2)\cos(\theta_1) = \cos(\theta_1-\theta_2)
\end{equation}

So, the derivative of the angular momentum is:

\begin{align}
\begin{split}
    \frac{d\vec{\bf{H_{O2}}}}{dt} &=  I_{zz}^{C2} \frac{d^2\theta_2}{dt^2} - \frac{m_2l_1l_2}{2}\left(\frac{d\theta_1}{dt}\right)^2 \sin(\theta_1-\theta_2) + \frac{m_2l_1l_2}{2}\frac{d^2\theta_1}{dt^2} \cos(\theta_1-\theta_2) + \frac{m_2l_2^2}{4}\frac{d^2\theta_2}{dt^2} \\
    &=  \frac{m_2l_1l_2}{2}\cos(\theta_1-\theta_2)\frac{d^2\theta_1}{dt^2} + \left(I_{zz}^{C2} + \frac{m_2l_2^2}{4} \right)\frac{d^2\theta_2}{dt^2}- \frac{m_2l_1l_2}{2}\left(\frac{d\theta_1}{dt}\right)^2 \sin(\theta_1-\theta_2)
    \end{split}
\end{align}_____no_output_____It remains to find the force $\vec{\bf{F_{12}}}$ that is in the sum of moment of the upper bar. It can be found by finding the resultant force in the lower bar and use the First Newton-Euler law:

\begin{equation}
    \vec{\bf{F_{12}}} - m_2g \hat{\bf{j}} = m\vec{\bf{a_{C2}}} \rightarrow \vec{\bf{F_{12}}}  =  m_2g \hat{\bf{j}}  + m_2\left[-l_1\left(\frac{d\theta_1}{dt}\right)^2 \hat{\bf{e_{R_1}}} + l_1\frac{d^2\theta_1}{dt^2} \hat{\bf{e_{\theta_1}}} -\frac{l_2}{2}\left(\frac{d\theta_2}{dt}\right)^2 \hat{\bf{e_{R_2}}} + \frac{l_2}{2}\frac{d^2\theta_2}{dt^2} \hat{\bf{e_{\theta_2}}}\right]
\end{equation}

Now, we can go back to the moment $\vec{\bf{M_{O1}}}$:

\begin{align}
    \begin{split}
    \vec{\bf{M_{O1}}} &= \frac{-m_1gl_1}{2}\sin(\theta_1)\hat{\bf{k}} + l_1\hat{\bf{e_{R_1}}} \times (-\vec{\bf{F_{12}}}) + \vec{\bf{M_{1}}} - \vec{\bf{M_{12}}} \\
    &= -\frac{m_1gl_1}{2}\sin(\theta_1)\hat{\bf{k}} - l_1\hat{\bf{e_{R_1}}} \times   m_2\left[g \hat{\bf{j}}-l_1\left(\frac{d\theta_1}{dt}\right)^2 \hat{\bf{e_{R_1}}} + l_1\frac{d^2\theta_1}{dt^2} \hat{\bf{e_{\theta_1}}} -\frac{l_2}{2}\left(\frac{d\theta_2}{dt}\right)^2 \hat{\bf{e_{R_2}}} + \frac{l_2}{2}\frac{d^2\theta_2}{dt^2} \hat{\bf{e_{\theta_2}}}\right]  + \vec{\bf{M_{1}}} - \vec{\bf{M_{12}}} \\
    &= -\frac{m_1gl_1}{2}\sin(\theta_1)\hat{\bf{k}} - m_2l_1g \sin(\theta_1)\hat{\bf{k}}  - m_2l_1^2\frac{d^2\theta_1}{dt^2}\hat{\bf{k}}  + \frac{m_2l_1l_2}{2}\left(\frac{d\theta_2}{dt}\right)^2 \sin(\theta_1-\theta_2)\hat{\bf{k}}  - \frac{m_2l_1l_2}{2}\frac{d^2\theta_2}{dt^2} \cos(\theta_1-\theta_2)\hat{\bf{k}}  + M_1\hat{\bf{k}}  - M_{12}\hat{\bf{k}}
    \end{split}
\end{align}_____no_output_____Finally, using the second Newton-Euler law for both bars, we can find the equation of motion of both angles:

\begin{equation}
    \frac{d\vec{\bf{H_{O1}}}}{dt} = \vec{\bf{M_{O1}}} \rightarrow  \left( I_{zz}^{C1}  + m_1 \frac{l_1^2}{4}\right)\frac{d^2\theta_1}{dt^2} =  -\frac{m_1gl_1}{2}\sin(\theta_1)- m_2l_1g \sin(\theta_1)  - m_2l_1^2\frac{d^2\theta_1}{dt^2}  + \frac{m_2l_1l_2}{2}\left(\frac{d\theta_2}{dt}\right)^2 \sin(\theta_1-\theta_2)  - \frac{m_2l_1l_2}{2}\frac{d^2\theta_2}{dt^2} \cos{(\theta_1-\theta_2)}  + M_1 - M_{12}
\end{equation}

\begin{equation}
    \frac{d\vec{\bf{H_{O2}}}}{dt} = \vec{\bf{M_{O2}}} \rightarrow \frac{m_2l_1l_2}{2}\cos(\theta_1-\theta_2)\frac{d^2\theta_1}{dt^2} + \left(I_{zz}^{C2} + \frac{m_2l_2^2}{4} \right)\frac{d^2\theta_2}{dt^2}- \frac{m_2l_1l_2}{2}\left(\frac{d\theta_1}{dt}\right)^2 \sin(\theta_1-\theta_2) = -\frac{m_2gl_2}{2}\sin(\theta_2) + M_{12}
\end{equation}

Considering the moment of inertia of the bars as $I_{zz}^{C1}=\frac{m_1l_1^2}{12}$ and $I_{zz}^{C2}=\frac{m_2l_2^2}{12}$ the differential equations above are:

\begin{equation}
     \left(\frac{m_1l_1^2}{3} +m_2l_1^2\right)\frac{d^2\theta_1}{dt^2} + \frac{m_2l_1l_2}{2} \cos{(\theta_1-\theta_2)\frac{d^2\theta_2}{dt^2}}  =  -\frac{m_1gl_1}{2}\sin(\theta_1)- m_2l_1g \sin(\theta_1)   + \frac{m_2l_1l_2}{2}\left(\frac{d\theta_2}{dt}\right)^2 \sin(\theta_1-\theta_2)  + M_1 - M_{12}
\end{equation}

\begin{equation}
    \frac{m_2l_1l_2}{2}\cos(\theta_1-\theta_2)\frac{d^2\theta_1}{dt^2} + \frac{m_2l_2^2}{3}\frac{d^2\theta_2}{dt^2} = -\frac{m_2gl_2}{2}\sin(\theta_2) + \frac{m_2l_1l_2}{2}\left(\frac{d\theta_1}{dt}\right)^2 \sin(\theta_1-\theta_2)+ M_{12}
\end{equation}

We could isolate the angular accelerations but this would lead to long equations._____no_output_____### Problems

- Solve the problems 6, 7 and 8 from [this Notebook](FreeBodyDiagram.ipynb).

- Solve the problems 16.2.9, 18.3.26, 18.3.29 from Ruina and Pratap book.

_____no_output_____### References

- Ruina A., Rudra P. (2015) [Introduction to Statics and Dynamics](http://ruina.tam.cornell.edu/Book/index.html). Oxford University Press.

- Duarte M. (2017) [Free body diagram](FreeBodyDiagram.ipynb)

- Elias, L A, Watanabe, R N, Kohn, A F.(2014) [Spinal Mechanisms May Provide a Combination of Intermittent and Continuous Control of Human Posture: Predictions from a Biologically Based Neuromusculoskeletal Model.](http://dx.doi.org/10.1371/journal.pcbi.1003944) PLOS Computational Biology (Online)

- Winter D. A., (2009) Biomechanics and motor control of human movement. John Wiley and Sons.

- Duarte M. (2017) [The inverted pendulum model of the human standing](http://nbviewer.jupyter.org/github/demotu/BMC/blob/master/notebooks/IP_Model.ipynb)_____no_output_____