0

I'm working on an interactive pseudo-standing wave demo, and I'm at a bit of an impasse. Essentially, the goal of this project is to recreate a variant of Melde's experiment, wherein a string is driven by an oscillator on one end with the other end connected to a pulley at a 90 degree angle. In the physical version of this experiment, one would add lead shot pellets to a cup hanging from this pulley, increasing the tension in the string until a standing wave is formed.

This project isn't truly a standing wave simulation, as I'm not numerically solving the wave equation with the necessary boundary conditions; rather, I'm generating an incident sine wave and a 'reflected' sine wave. Here, the incident wave can be tuned such that the wave vectors between the two waves match up, producing a standing wave. My goal is to be able to tune this wave by adjusting the number of lead shot pellets dropped into the cup via a scale widget through Tkinter. In other words, I want to be able to adjust the slider shown in the screenshot below and have the (animated) wave update accordingly.

enter image description here

I've found a few somewhat related questions on this very forum, but they all seem to be related to updating a still plot with the movement of the slider, or animating the slider itself. In my case, the wave plot is already animated - already moving in time, and I want to refresh the animation itself whenever the slider is adjusted. I know that I need to command the scale widget to call on a function, but I'm not sure how to do this while still preserving the animation function already present in the code. Ultimately, I want to be able to control the parameter N (towards the top of the code below) using the scale widget, with the animated plot updating accordingly.

import matplotlib.pylab as plot
import numpy as np
import matplotlib.animation as animation
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk

h = 3                           #define nth harmonic
kval = np.pi*h/100              #wave vector from nth harmonic (1/cm)
mu = 0.001                      #linear string mass density (g/cm)
g = 980                         #gravitational acceleration (cm/s/s)
N = 50                          #number of lead shot pellets
m = N*0.01216                   #total mass of lead shot pellets (g)
A = 0.15                        #wave amplitude
omega = 120                     #angular wave frequency
k1 = omega*np.sqrt(mu/(m*g))    #wave vector for initial wave (1/cm)
k2 = k1*k1/kval                 #wave vector for 'reflected' wave (1/cm)

fig = plot.Figure()

x = np.linspace(0,100,500)

def animate(i):
    line.set_ydata(A*np.sin(k1*x+omega*i) + A*np.sin(k2*x - omega*i))
    return line,

main = tk.Tk()

#background text
intro = tk.Label(main,text='Add lead shot to produce a standing wave.').grid(column=0,row=0)

canvas = FigureCanvasTkAgg(fig, master=main)
canvas.get_tk_widget().grid(column=0,row=1)

ax = fig.add_subplot(111)
ax.set_xlim(0,100)
ax.set_ylim(-2,2)

line, = ax.plot(x, A*np.sin(k1*x) + A*np.sin(k2*x))
anim = animation.FuncAnimation(fig, animate, interval=50, blit=False)

horizontal = tk.Scale(main, from_=50, to=300, length=400, orient='horizontal').grid(column=0,row=2)

main.mainloop()

Any suggestions are greatly appreciated! I'm very new to using Tkinter, so I'm likely just missing something obvious.

martineau
  • 119,623
  • 25
  • 170
  • 301
  • Since you already have an animation running, you don't actually need to do anything in response to the slider being moved. Just get the current slider value in your `animate()` function, and use it as appropriate in your update calculation. Note that in order to do this, you need a name by which to refer to the slider. `horizontal` is currently just `None`, the result of the `.grid()` call rather than the widget itself. – jasonharper Aug 25 '20 at 23:18
  • Thank you so much, that worked perfectly! Much simpler than I was fearing the solution might be. – SSimpossible Aug 25 '20 at 23:35

1 Answers1

0

Simply getting the current slider value within the animate function itself worked perfectly, as user jasonharper stated.