diff --git a/README.md b/README.md
index d46f43c..60f944d 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,13 @@
-# FrequenPy
+
FrequenPy
-![coverage_badge](https://codecov.io/gh/tomaslink/frequenpy/branch/master/graph/badge.svg)
-
-_FrequenPy_ is a high-precision physics engine dedicated to the study of standing waves and visualization of its normal modes.
+
+
+
+
+
-This package has educational purposes.
+**frequenpy** is a high-precision physics engine dedicated to the study and visualization of standing waves.
## Wave theory
@@ -21,21 +23,38 @@ This results have been (and can be) demonstrated experimentally.
- According to wave theory, any arbitrary movement of the string
- can be decomposed into a superposition of natural modes of oscillation.
- In each natural mode **m**,
- all masses in the system oscilate at the same frequency ***f(m)***
- and pass through the equilibrium position at the same time.
- This natural modes of oscillation are called **normal modes**.
-
+ A flexible elastic string with tension **T** is loaded with **N** identical particles,
+ each of mass **m**, equally spaced a distance **a** apart.
+ Let us hold the string fixed at two points,
+ one at a distance **a** to the left of the first particle
+ and the other at a distance **a** to the right of the Nth particle.
+
+ According to the theory, the movement of each of the masses in the vertical direction
+ can be decomposed into a superposition of **N** **normal modes** modes of oscillation.
+ That way, the $y$ position of the particle **n** as a function of time is
+ ```math
+ y_n(t) = \sum_{p=1}^N A_p \sin(k_p n a) \cos(\omega_p t + \theta_p).
+ ```
+ Where $A_p$ and $\theta_p$ depend on the initial conditions,
+ $k_p$ will depend on the boundary conditions and $\omega_p$ will have the form
+ ```math
+ \omega_p = 2 \omega_0 \sin\left(\frac{p \pi}{2(N + 1)}\right)
+ \qquad,
+ \qquad
+ \omega_0 = \sqrt{\frac{T}{ma}}.
+ ```
+
There are as many normal modes as there are degrees of freedom (masses) in the system.
- So, a string loaded with **N** masses, will have **N** **normal modes**.
- The first will corresponde to the lowest frequency (called fundamental)
- and each next will be higher than the previous one, until we reach the last and highest frequency.
- Any movement, as strange as it may be, can be expressed as a superposition of those **N** normal modes
+ In each natural mode **p**,
+ all masses in the system oscilate at the same frequency $\omega_p$
+ and pass through the equilibrium position at the same time.
+ The first mode, **p=1**, corresponds to the lowest frequency (called fundamental)
+ and each subsequent mode will have a frequency higher than the previous one.
+ Any movement of the string, as strange as it may be,
+ can be expressed as a superposition of those **N** normal modes
(some will contribute more than others to the final movement).
- As the number of masses gets higher and highter (***N*** ---> ***∞***),
+ As the number of masses gets higher and highter ($N \rightarrow \infty$),
we approximate to the continuous system (a vibrating string - no discrete masses).
In this simulation, you can use **N = 30** to see a continuous effect.
@@ -98,7 +117,7 @@ optional arguments:
Example: frequenpy loaded_string --masses 3 --modes 1 2 3 --speed 0.1 --boundary 0
```
-Remember that for system of **N** masses there are N normal modes.
+Remember that for system of **N** masses there are **N** normal modes.
You can pass only one of them or a combination of several, e.g. "2 6 3".
The order doesn't matter.
diff --git a/frequenpy/loaded_string/animation.py b/frequenpy/loaded_string/animation.py
index fa75085..744ba6d 100644
--- a/frequenpy/loaded_string/animation.py
+++ b/frequenpy/loaded_string/animation.py
@@ -10,10 +10,10 @@
logger = logging.getLogger(__name__)
-LINE_WIDTH = 1
+LINE_WIDTH = 0.5
LINE_MARKERTYPE = 'o'
LINE_MARKERSIZE = 8
-LINE_MARKERFACECOLOR = 'None'
+LINE_MARKERFACECOLOR = 'gray'
LINE_COLOR = 'white'
BACKGROUND_COLOR = 'black'
@@ -22,7 +22,7 @@
WALL_WIDTH = 0.5
WALL_COLOR = 'white'
-FIG_SIZE = (7, 2)
+FIG_SIZE = (7, 4)
FIG_DPI = 100
FIG_X_LIMIT = (-0.5, 0.5)
FIG_Y_LIMIT = (-1, 1)
@@ -93,11 +93,10 @@ def _build_line_without_markers(self):
def _build_frames(self):
self._loaded_string.apply_speed(self._speed)
- frames = range(0, self._n_frames)
return [
self._loaded_string.position_at_time_t(t)
- for t in frames
+ for t in range(0, self._n_frames)
]
def _build_figure(self):
@@ -117,6 +116,8 @@ def _build_figure(self):
ax = plt.axes(xlim=FIG_X_LIMIT, ylim=FIG_Y_LIMIT, frameon=False)
ax.set_yticks([])
ax.set_xticks([])
+ ax.set_xlim(-0.5, 0.51)
+ ax.set_ylim(-0.5, 0.51)
ax.add_line(self._left_support(support_distance_from_origin))
ax.add_line(self._right_support(support_distance_from_origin))
@@ -151,7 +152,7 @@ def _build_animation(self):
self._figure,
self._update,
frames=self._n_frames,
- interval=5,
+ interval=10,
blit=True,
repeat=True)
diff --git a/frequenpy/loaded_string/loaded_string.py b/frequenpy/loaded_string/loaded_string.py
index 4a283ec..a1274ba 100644
--- a/frequenpy/loaded_string/loaded_string.py
+++ b/frequenpy/loaded_string/loaded_string.py
@@ -3,10 +3,10 @@
LONGITUDE = 1
-TENSION = 0.5
+TENSION = 1
MASS = 0.1
-AMPLITUDE = 0.5
+AMPLITUDE = 0.2
THETA = 0
@@ -18,6 +18,8 @@ def __init__(self, N, modes):
self._modes = modes
self._masses = range(0, N + 2)
self._a = LONGITUDE / (N + 1)
+
+ self._omega0 = np.sqrt(TENSION / (MASS * self._a))
self._omega = self._omega()
self.rest_position = self._get_rest_position()
@@ -57,7 +59,7 @@ def modes(self):
def _omega(self):
return {
- p: 2 * np.sqrt(TENSION / MASS * self._a) * np.sin(self._wavenumber(p) * self._a / 2)
+ p: 2 * self._omega0 * np.sin((self._wavenumber(p) * self._a) / 2)
for p in self._modes
}