diff --git a/content/01_vectors.html b/content/01_vectors.html index b532e2d..7d76d2a 100644 --- a/content/01_vectors.html +++ b/content/01_vectors.html @@ -601,7 +601,7 @@ function draw() { let center = createVector(width / 2, height / 2); mouse.sub(center); - // The magnitude (that is, length) of a vector can be accessed via the `mag()` function. Here it is used as the width of a rectangle drawn at the top of the window. + // The magnitude (that is, length) of a vector can be accessed via the mag() function. Here it is used as the width of a rectangle drawn at the top of the window. let m = mouse.mag(); fill(0); rect(0, 0, m, 10); diff --git a/content/03_oscillation.html b/content/03_oscillation.html index 26a88da..72ae81d 100644 --- a/content/03_oscillation.html +++ b/content/03_oscillation.html @@ -836,14 +836,14 @@ function draw() { connect(bob) { // Get a vector pointing from the anchor to the bob position. let force = p5.Vector.sub(bob.position, this.anchor); - // Calculate the displacement between distance and rest length. I’ll use the variable name “stretch” instead of “x” to be more descriptive. + // Calculate the displacement between distance and rest length. I’ll use the variable name stretch instead of x to be more descriptive. let currentLength = force.mag(); let stretch = currentLength - this.restLength; // Direction and magnitude together! force.setMag(-1 * this.k * stretch); - // Call applyForce() right here! + // Call applyForce() right here! bob.applyForce(force); } diff --git a/content/05_steering.html b/content/05_steering.html index 404dfb7..d6390f4 100644 --- a/content/05_steering.html +++ b/content/05_steering.html @@ -963,7 +963,11 @@ for (let i = 0; i < path.points.length - 1; i++) { Stated more evocatively, the theory is that a single butterfly flapping its wings on the other side of the world could cause a massive weather shift and ruin your weekend at the beach. It‘s called nonlinear because there isn’t a linear relationship between a change in initial conditions and a change in outcome. A small change in initial conditions can have a massive effect on the outcome. Nonlinear systems are a superset of chaotic systems. In Chapter 7, you’ll see how even in a system of many 0s and 1s, if you change just one bit, the result will be completely different.
  • Competition and cooperation: One ingredient that often makes a complex system tick is the presence of both competition and cooperation among the elements. The upcoming flocking system will have three rules: alignment, cohesion, and separation. Alignment and cohesion will ask the elements to “cooperate” by trying to stay together and move together. Separation, however, will ask the elements to “compete” for space. When the time comes, try taking out just the cooperation or just the competition, and you’ll see how the system loses its complexity. Competition and cooperation are found together in living complex systems, but not in nonliving complex systems like the weather.
  • -
  • Feedback: Complex systems often include a loop that feeds the output of the system back into the system to influence its behavior in a positive or negative direction. Let’s say you decide to take public transportation to work each day because it’s the most reliable and cost-effective solution, and you’re put off by the traffic congestion and environmental impact of driving. You aren’t alone; others turn to public transportation too. The system grows more efficient and attractive, serving more people with the same resources, and meanwhile, vehicle traffic is reduced. Over time, however, the system may struggle to accommodate the rising demand, leading to overcrowding, delays, and increased fares to fund infrastructure improvements. As a result, you and others start to switch back to driving, thereby increasing traffic congestion once again and reducing public transport’s efficiency. As traffic worsens, the funds from increased fares are (hopefully) used to improve public transport infrastructure, making it more appealing once again. In this way, the cost and efficiency of public transportation are both the input of the system (determining whether you choose to use it or not) and the output (the degree of traffic congestion and subsequent cost and efficiency). Economic models are just one example of a human complex system. Others include fads and trends, elections, crowds, and traffic flow.
  • +
  • + Feedback: Complex systems often include a loop that feeds the output of the system back into the system to influence its behavior in a positive or negative direction. Let’s say you decide to take public transportation to work each day because it’s the most reliable and cost-effective solution, and you’re put off by the traffic congestion and environmental impact of driving. You aren’t alone; others turn to public transportation too. The system grows more efficient and attractive, serving more people with the same resources, and meanwhile, vehicle traffic is reduced. + Over time, however, the system may struggle to accommodate the rising demand, leading to overcrowding, delays, and increased fares to fund infrastructure improvements. As a result, you and others start to switch back to driving, thereby increasing traffic congestion once again and reducing public transport’s efficiency. As traffic worsens, the funds from increased fares are (hopefully) used to improve public transport infrastructure, making it more appealing once again. + In this way, the cost and efficiency of public transportation are both the input of the system (determining whether you choose to use it or not) and the output (the degree of traffic congestion and subsequent cost and efficiency). Economic models are just one example of a human complex system. Others include fads and trends, elections, crowds, and traffic flow. +
  • Complexity will serve as a key theme for much of the remainder of the book. In this section, I’ll begin by introducing an additional feature to the Vehicle class: the ability to perceive neighboring vehicles. This enhancement will pave the way for a culminating example of a complex system, in which the interplay of simple individual behaviors results in an emergent behavior: flocking.

    Implementing Group Behaviors (or: Let’s Not Run Into Each Other)

    diff --git a/content/07_ca.html b/content/07_ca.html index 1f6ede4..84de75d 100644 --- a/content/07_ca.html +++ b/content/07_ca.html @@ -317,7 +317,7 @@ function rules(a, b, c) {

    First, this visual interpretation of the data is completely literal. It’s useful for demonstrating the algorithms and results of Wolfram’s elementary CA, but it shouldn’t necessarily drive your own personal work. You’re not likely building a project that needs precisely this algorithm with this visual style. So while learning to draw a CA in this way will help you understand and implement CA systems, this skill should exist only as a foundation.

    Second, the fact that a 1D CA is visualized with a 2D image can be misleading. It’s very important to remember that this is not a 2D CA. I’m simply choosing to show a history of all the generations stacked vertically. This technique creates a 2D image out of many instances of 1D data, but the system itself is 1D. Later, I’ll show you an actual 2D CA (the Game of Life), and I’ll cover how to visualize such a system.

    -

    The good news is that drawing an elementary CA isn’t particularly difficult. I’ll begin by rendering a single generation. Let’s say each cell should be a 10 by 10 square:

    +

    The good news is that drawing an elementary CA isn’t particularly difficult. I’ll begin by rendering a single generation. Let’s say each cell should be a 10\times10 square:

    let w = 10;

    Assuming the canvas is 640 pixels wide, the CA will have 64 cells. Of course, I can calculate this value dynamically when I initialize the cells array in setup():

    //{!1} How many cells fit across, given a certain width
    @@ -558,7 +558,7 @@ if (board[i + 1][j    ] === 1) sum++;
     if (board[i - 1][j + 1] === 1) sum++;
     if (board[i    ][j + 1] === 1) sum++;
     if (board[i + 1][j + 1] === 1) sum++;
    -

    Just as with the Wolfram CA, I find myself writing out a bunch of if statements. This is another situation where, for teaching purposes, it’s useful and clear to write the code this way, explicitly stating every step (each time a neighbor has a state of 1, the counter increases). Nevertheless, it’s a bit silly to say, “If the cell state equals 1, add 1 to a counter” when I could instead just say, “Add every cell state to a counter.” After all, if the state can be only 0 or 1, the sum of all the neighbors’ states will yield the total number of live cells. Since the neighbors are arranged in a mini 3 by 3 grid, I can introduce another nested loop to compute the sum more efficiently:

    +

    Just as with the Wolfram CA, I find myself writing out a bunch of if statements. This is another situation where, for teaching purposes, it’s useful and clear to write the code this way, explicitly stating every step (each time a neighbor has a state of 1, the counter increases). Nevertheless, it’s a bit silly to say, “If the cell state equals 1, add 1 to a counter” when I could instead just say, “Add every cell state to a counter.” After all, if the state can be only 0 or 1, the sum of all the neighbors’ states will yield the total number of live cells. Since the neighbors are arranged in a mini 3\times3 grid, I can introduce another nested loop to compute the sum more efficiently:

    let sum = 0;
     
     //{!2} Use k and l as the counters since i and j are already used!
    diff --git a/content/08_fractals.html b/content/08_fractals.html
    index 9c24c03..d9df4f9 100644
    --- a/content/08_fractals.html
    +++ b/content/08_fractals.html
    @@ -47,7 +47,7 @@
       Figure 8.4: Two coastlines
       
    Figure 8.4: Two coastlines
    -

    The absence of a scale in these illustrations is no accident. Am I showing the entire coastline or just a small portion of it? There’s no way for you to know without a scale reference because coastlines, as fractals, look essentially the same at any scale. (Incidentally, coastline B shows an approximately 3X magnified view of a specific section of coastline A. I’ve added the scales in Figure 8.5.)

    +

    The absence of a scale in these illustrations is no accident. Am I showing the entire coastline or just a small portion of it? There’s no way for you to know without a scale reference because coastlines, as fractals, look essentially the same at any scale. (Incidentally, coastline B shows an approximately 3\times magnified view of a specific section of coastline A. I’ve added the scales in Figure 8.5.)

    Figure 8.5: Two coastlines, with scale
    Figure 8.5: Two coastlines, with scale
    @@ -653,24 +653,24 @@ for (let i = 0; i < message.length; i++) {

    I’ll begin with a simple L-system. In fact, it’s Lindenmayer’s original L-system, which models the growth of algae. Here are its components:

    - + - + @@ -746,17 +746,17 @@ function generate() { - + - + @@ -766,19 +766,19 @@ function generate() { - + - + - + - +
    AlphabetA, BA, B
    AxiomAA
    Rules - A→AB - B→A + A → AB + B → A
    AlphabetA, BA, B
    AxiomAA
    Rules - A→ABA - B→BBB + A → ABA + B → BBB
    Generation 0AA
    Generation 1ABAABA
    Generation 2ABABBBABAABABBBABA
    Generation 3ABABBBABABBBBBBBBBABABBBABAABABBBABABBBBBBBBBABABBBABA
    @@ -786,11 +786,11 @@ function generate() { - + - + @@ -805,27 +805,27 @@ function generate() {
    AA Draw a line forward.
    BB Move forward (without drawing a line).
    - + - + - + - + - + - + @@ -834,38 +834,38 @@ function generate() {
    FF Draw a line and move forward.
    GG Move forward (without drawing a line).
    ++ Turn right.
    - Turn left.
    [[ Save current state.
    ]] Restore current state.
    - + - + - + - + - + - + @@ -902,15 +902,15 @@ translate(0, length); - + - + - +
    FF
    line(0, 0, 0, length);
     translate(0, length);
    GG
    translate(0, length);
    ++
    rotate(angle);
    -
    rotate(-angle);
    [[
    push();
    ]]
    pop();
    AlphabetF, G, +, -, [ , ]F, G, +, –, [, ]
    AxiomFF
    RulesF → FF+[+F-F-F]-[-F+F+F]F → FF + [+ F – F – F] – [– F + F + F]
    diff --git a/content/09_ga.html b/content/09_ga.html index e6b6d7e..aae117e 100644 --- a/content/09_ga.html +++ b/content/09_ga.html @@ -55,7 +55,10 @@ console.log(s);

    I want to emphasize the context in which I’m applying these Darwinian concepts: a simulated, artificial environment where specific goals can be quantified, all for the sake of creative exploration. Throughout history, the principles of genetics have been used to harm those who have been marginalized and oppressed by dominant societal structures. I believe it is essential to approach projects involving GAs with careful consideration of the language used, and to ensure that the documentation and descriptions of the work are framed inclusively.

    With these concepts established, I’ll begin walking through the GA narrative. I’ll do this in the context of typing cats. The algorithm will be divided into several steps that unfold over two parts: a set of conditions for initialization, and the steps that are repeated over and over again until the correct phrase is found.

    @@ -648,7 +651,7 @@ function draw() { population[i] = child; } - // Step 4: Repeat—go back to the beginning of draw()! + // Step 4: Repeat — go back to the beginning of draw()! }

    The sketch.js file precisely mirrors the steps of the GA. However, most of the functionality called upon is encapsulated in the DNA class:

    diff --git a/content/10_nn.html b/content/10_nn.html
    index 844da26..802e2ee 100644
    --- a/content/10_nn.html
    +++ b/content/10_nn.html
    @@ -288,24 +288,24 @@ let guess = perceptron.feedForward(inputs);
    - -1 - -1 - 0 + –1 + –1 + 0 - -1 - +1 - -2 + –1 + +1 + –2 - +1 - -1 - +2 + +1 + –1 + +2 - +1 - +1 - 0 + +1 + +1 + 0 @@ -496,7 +496,7 @@ function draw() {

    Exercise 10.1

    Modify the code from Example 10.1 to also draw the perceptron’s current decision boundary during the training process—its best guess for where the line should be. Hint: Use the perceptron’s current weights to calculate the line’s equation.

    -

    While this perceptron example offers a conceptual foundation, real-world datasets often feature more diverse and dynamic ranges of input values. For the simplified scenario here, the range of values for x is larger than that for y because of the canvas size of 640 by 240. Despite this, the example still works—after all, the sign activation function doesn’t rely on specific input ranges, and it’s such a straightforward binary classification task.

    +

    While this perceptron example offers a conceptual foundation, real-world datasets often feature more diverse and dynamic ranges of input values. For the simplified scenario here, the range of values for x is larger than that for y because of the canvas size of 640\times240. Despite this, the example still works—after all, the sign activation function doesn’t rely on specific input ranges, and it’s such a straightforward binary classification task.

    However, real-world data often has much greater complexity in terms of input ranges. To this end, data normalization is a critical step in machine learning. Normalizing data involves mapping the training data to ensure that all inputs (and outputs) conform to a uniform range—typically 0 to 1, or perhaps –1 to 1. This process can improve training efficiency and prevent individual inputs from dominating the learning process. In the next section, using the ml5.js library, I’ll build data normalization into the process.

    Exercise 10.2

    @@ -572,7 +572,7 @@ function draw() {
    Figure 10.14: Labeling images as cats or dogs

    Classification doesn’t happen by magic. The model must first be shown many examples of dogs and cats with the correct labels in order to properly configure the weights of all the connections. This is the training part of supervised learning.

    -

    The classic “Hello, world!” demonstration of machine learning and supervised learning is a classification problem of the MNIST dataset. Short for Modified National Institute of Standards and Technology, MNIST is a dataset that was collected and processed by Yann LeCun (Courant Institute, NYU), Corinna Cortes (Google Labs), and Christopher J. C. Burges (Microsoft Research). Widely used for training and testing in the field of machine learning, this dataset consists of 70,000 handwritten digits from 0 to 9; each is a 28 by 28-pixel grayscale image (see Figure 10.15 for examples). Each image is labeled with its corresponding digit.

    +

    The classic “Hello, world!” demonstration of machine learning and supervised learning is a classification problem of the MNIST dataset. Short for Modified National Institute of Standards and Technology, MNIST is a dataset that was collected and processed by Yann LeCun (Courant Institute, NYU), Corinna Cortes (Google Labs), and Christopher J. C. Burges (Microsoft Research). Widely used for training and testing in the field of machine learning, this dataset consists of 70,000 handwritten digits from 0 to 9; each is a 28\times28 pixel grayscale image (see Figure 10.15 for examples). Each image is labeled with its corresponding digit.

    Figure 10.15: A selection of handwritten digits 0–9 from the MNIST dataset (image by Suvanjanprasai, CC-SA-4.0)
    Figure 10.15: A selection of handwritten digits 0–9 from the MNIST dataset (image by Suvanjanprasai, CC-SA-4.0)
    @@ -921,15 +921,15 @@ function gotResults(error, results) { status = results[0].label; }

    Since the results array is sorted by confidence, if I just want to use a single label as the prediction, I can access the first element of the array with results[0].label, as in the gotResults() function in Example 10.2. This label is passed to the status variable to be displayed on the canvas.

    -
    +

    Exercise 10.5

    Divide Example 10.2 into three sketches: one for collecting data, one for training, and one for deployment. Use the ml5.neuralNetwork functions save() and load() for saving and loading the model to and from a file, respectively.

    -
    +

    Exercise 10.6

    Expand the gesture-recognition model to classify a sequence of vectors, capturing more accurately the path of a longer mouse movement. Remember, your input data must have a consistent shape, so you’ll have to decide how many vectors to use to represent a gesture and store no more and no less for each data point. While this approach can work, other machine learning models (such as recurrent neural networks) are specifically designed to handle sequential data and might offer more flexibility and potential accuracy.

    -
    +

    Exercise 10.7

    One of the pretrained models in ml5.js is called Handpose. The input of the model is an image, and the prediction is a list of 21 key points—x- and y-positions, also known as landmarks—that describe a hand.

    diff --git a/content/11_nn_ga.html b/content/11_nn_ga.html index 04c238f..008e0a2 100644 --- a/content/11_nn_ga.html +++ b/content/11_nn_ga.html @@ -201,7 +201,7 @@ function draw() { } }

    The trickiest aspect of this code lies in spawning the pipes at regular intervals with the frameCount variable and modulo operator. In p5.js, frameCount is a system variable that tracks the number of frames rendered since the sketch began, incrementing with each cycle of the draw() loop. The modulo operator, denoted by %, returns the remainder of a division operation. For example, 7 % 3 yields 1 because when dividing 7 by 3, the result is 2 with a remainder of 1. The Boolean expression frameCount % 100 === 0 therefore checks whether the current frameCount value, when divided by 100, has a remainder of 0. This condition is true every 100 frames, and at those frames, a new pipe is spawned and added to the pipes array.

    -
    +

    Exercise 11.1

    Implement a scoring system that awards points for successfully navigating through each set of pipes. Feel free to also add your own visual design elements for the bird, pipes, and environment!

    @@ -454,11 +454,11 @@ function resetPipes() { pipes.splice(0, pipes.length - 1); }

    Note the addition of a new resetPipes() function. If I don’t remove the pipes before starting a new generation, the birds may immediately restart at a position colliding with a pipe, in which case even the best bird won’t have a chance to fly! The full online code for Example 11.2 also adjusts the behavior of the birds so that they die when they leave the canvas, either by crashing into the ground or soaring too high above the top.

    -
    +

    Exercise 11.2

    It takes a very long time for Example 11.2 to produce any results. Could you “speed up time” by skipping the drawing of every single frame of the game to reach an optimal bird faster? (A solution is presented in “Speeding Up Time" on page XX.) Additionally, could you add an overlay that displays information about the simulation’s status, such as the number of birds still in play, the current generation, and the lifespan of the best bird?

    -
    +

    Exercise 11.3

    To avoid starting the neuroevolution process from scratch every time, try using ml5.js’s neural network save() and load() methods. How might you add a feature that saves the best bird model as well as an option to load a previously saved model?

    @@ -522,7 +522,7 @@ for (let i = 0; i < lifeSpan; i++) { this.generations++; }

    Now that I’m using ml5.js, notice that I no longer need a separate DNA class with implementations of crossover() and mutate(). Instead, those methods are built into ml5.neuralNetwork and can be called directly.

    -
    +

    Exercise 11.4

    A steering force, as defined by Reynolds, is the difference between an agent’s desired velocity and its current velocity. How might this evolutionary system mirror that methodology? Instead of using only the position as an input to the neural network, what if you feed in the rocket’s current velocity? You could try using the x- and y-components or the direction and magnitude of the vector. Remember to normalize these values!

    diff --git a/content/images/01_vectors/01_vectors_10.png b/content/images/01_vectors/01_vectors_10.png index eb2a541..2c469d1 100644 Binary files a/content/images/01_vectors/01_vectors_10.png and b/content/images/01_vectors/01_vectors_10.png differ diff --git a/content/images/01_vectors/01_vectors_11.png b/content/images/01_vectors/01_vectors_11.png index e68c347..ae39af5 100644 Binary files a/content/images/01_vectors/01_vectors_11.png and b/content/images/01_vectors/01_vectors_11.png differ diff --git a/content/images/01_vectors/01_vectors_12.png b/content/images/01_vectors/01_vectors_12.png index 1c84b0b..4333ab3 100644 Binary files a/content/images/01_vectors/01_vectors_12.png and b/content/images/01_vectors/01_vectors_12.png differ diff --git a/content/images/01_vectors/01_vectors_13.png b/content/images/01_vectors/01_vectors_13.png index dbe74fd..955c209 100644 Binary files a/content/images/01_vectors/01_vectors_13.png and b/content/images/01_vectors/01_vectors_13.png differ diff --git a/content/images/01_vectors/01_vectors_14.png b/content/images/01_vectors/01_vectors_14.png index 78cfe53..e336c4c 100644 Binary files a/content/images/01_vectors/01_vectors_14.png and b/content/images/01_vectors/01_vectors_14.png differ diff --git a/content/images/01_vectors/01_vectors_15.png b/content/images/01_vectors/01_vectors_15.png index 115ea77..3c8a31c 100644 Binary files a/content/images/01_vectors/01_vectors_15.png and b/content/images/01_vectors/01_vectors_15.png differ diff --git a/content/images/01_vectors/01_vectors_16.png b/content/images/01_vectors/01_vectors_16.png index b54fc1d..f4b4a45 100644 Binary files a/content/images/01_vectors/01_vectors_16.png and b/content/images/01_vectors/01_vectors_16.png differ diff --git a/content/images/01_vectors/01_vectors_17.png b/content/images/01_vectors/01_vectors_17.png index 0731f6c..1bf0e49 100644 Binary files a/content/images/01_vectors/01_vectors_17.png and b/content/images/01_vectors/01_vectors_17.png differ diff --git a/content/images/01_vectors/01_vectors_2.png b/content/images/01_vectors/01_vectors_2.png index f27d487..5d4117c 100644 Binary files a/content/images/01_vectors/01_vectors_2.png and b/content/images/01_vectors/01_vectors_2.png differ diff --git a/content/images/01_vectors/01_vectors_5.png b/content/images/01_vectors/01_vectors_5.png index 64f983c..bbcdf76 100644 Binary files a/content/images/01_vectors/01_vectors_5.png and b/content/images/01_vectors/01_vectors_5.png differ diff --git a/content/images/01_vectors/01_vectors_6.png b/content/images/01_vectors/01_vectors_6.png index 3aee485..be9df1b 100644 Binary files a/content/images/01_vectors/01_vectors_6.png and b/content/images/01_vectors/01_vectors_6.png differ diff --git a/content/images/01_vectors/01_vectors_7.png b/content/images/01_vectors/01_vectors_7.png index ae49c4c..6e707b1 100644 Binary files a/content/images/01_vectors/01_vectors_7.png and b/content/images/01_vectors/01_vectors_7.png differ diff --git a/content/images/01_vectors/01_vectors_9.png b/content/images/01_vectors/01_vectors_9.png index e750c1e..8bd2281 100644 Binary files a/content/images/01_vectors/01_vectors_9.png and b/content/images/01_vectors/01_vectors_9.png differ diff --git a/content/images/02_forces/02_forces_11.png b/content/images/02_forces/02_forces_11.png index f1b0ab6..cb07049 100644 Binary files a/content/images/02_forces/02_forces_11.png and b/content/images/02_forces/02_forces_11.png differ diff --git a/content/images/02_forces/02_forces_3.png b/content/images/02_forces/02_forces_3.png index fb65c6c..da11e11 100644 Binary files a/content/images/02_forces/02_forces_3.png and b/content/images/02_forces/02_forces_3.png differ diff --git a/content/images/02_forces/02_forces_4.png b/content/images/02_forces/02_forces_4.png index 629e79b..fff060c 100644 Binary files a/content/images/02_forces/02_forces_4.png and b/content/images/02_forces/02_forces_4.png differ diff --git a/content/images/02_forces/02_forces_5.png b/content/images/02_forces/02_forces_5.png index a4a1bc2..ee41101 100644 Binary files a/content/images/02_forces/02_forces_5.png and b/content/images/02_forces/02_forces_5.png differ diff --git a/content/images/02_forces/02_forces_6.png b/content/images/02_forces/02_forces_6.png index ba121aa..535df4e 100644 Binary files a/content/images/02_forces/02_forces_6.png and b/content/images/02_forces/02_forces_6.png differ diff --git a/content/images/02_forces/02_forces_9.png b/content/images/02_forces/02_forces_9.png index c920f38..6595c43 100644 Binary files a/content/images/02_forces/02_forces_9.png and b/content/images/02_forces/02_forces_9.png differ diff --git a/content/images/03_oscillation/03_oscillation_12.png b/content/images/03_oscillation/03_oscillation_12.png index 0a54da3..230c208 100644 Binary files a/content/images/03_oscillation/03_oscillation_12.png and b/content/images/03_oscillation/03_oscillation_12.png differ diff --git a/content/images/03_oscillation/03_oscillation_13.png b/content/images/03_oscillation/03_oscillation_13.png index 4551f60..be53050 100644 Binary files a/content/images/03_oscillation/03_oscillation_13.png and b/content/images/03_oscillation/03_oscillation_13.png differ diff --git a/content/images/03_oscillation/03_oscillation_3.png b/content/images/03_oscillation/03_oscillation_3.png index 9043a58..4dc2b46 100644 Binary files a/content/images/03_oscillation/03_oscillation_3.png and b/content/images/03_oscillation/03_oscillation_3.png differ diff --git a/content/images/03_oscillation/03_oscillation_4.png b/content/images/03_oscillation/03_oscillation_4.png index b0a7c82..a39859a 100644 Binary files a/content/images/03_oscillation/03_oscillation_4.png and b/content/images/03_oscillation/03_oscillation_4.png differ diff --git a/content/images/03_oscillation/03_oscillation_6.png b/content/images/03_oscillation/03_oscillation_6.png index 41a76fc..28be01a 100644 Binary files a/content/images/03_oscillation/03_oscillation_6.png and b/content/images/03_oscillation/03_oscillation_6.png differ diff --git a/content/images/03_oscillation/03_oscillation_8.png b/content/images/03_oscillation/03_oscillation_8.png index 77cf21b..d557737 100644 Binary files a/content/images/03_oscillation/03_oscillation_8.png and b/content/images/03_oscillation/03_oscillation_8.png differ diff --git a/content/images/03_oscillation/03_oscillation_9.png b/content/images/03_oscillation/03_oscillation_9.png index 1c5c18e..4c80505 100644 Binary files a/content/images/03_oscillation/03_oscillation_9.png and b/content/images/03_oscillation/03_oscillation_9.png differ