Klicke in das Bild um die Simulation zu stoppen bzw. neu zu starten.
d1: Lineare Dämpfung, enstpricht Reibung im Lager
d2: Quadratische Dämpfung, enstpricht dem Luftwiderstand
v0: Start-Winkelgeschwindigkeit
g: Gravitationsbeschleunigung, Erde = 9,81 m/s2
Speed: Simulations-Geschwindigkeit: > 1 für Timelaps, < 1 für Zeitlupe
var PendulumModel = { v0: 4, // start speed a: 0, // current angle da: 0, // current angular speed dda: 0, // current angular acceleration d1: 0, // linear damping d2: 0.1, // quadratic damping m: 1, // pendulum mass l: 1, // pendulum length g: 9.81, // gravitational acceleration Fl: 0, // current string force Fg: 0, // current gravity force Fd: 0, // current damping force Ft: 0, // current total force graph: null, sim: null, Create: function( sim ) { this.sim = sim; var me = this; this.graph = NewGraph2D( { Id: 'PendulumModel-Graph', Width: '100%', Height: '60%', DrawFunc: function(){ me.Draw(); }, OnClick: function(){ sim.Pause(true); }, AutoReset: false, AutoClear: false, } ); }, Reset: function() { this.a = 0; this.da = this.v0; this.dda = 0; }, Update: function() { // is called from sim to compute next time step values // compute all forces this.Fg = this.m * this.g; this.Fl = this.Fg * Math.cos( this.a ); this.Fd = this.d1 * Math.abs( this.da ) + this.d2 * this.da * this.da; var vdir = this.da >= 0 ? -1 : 1; this.Ft = -this.Fg * Math.sin( this.a ) + vdir * this.Fd; // compute new acceleration, speed and position by simple numerical integration this.dda = this.Ft / this.m; this.da += this.dda * this.sim.DeltaTime; this.a += this.da * this.sim.DeltaTime; }, Draw: function() { // is called from sim once per frame to draw pendulum var g = this.graph; g.Reset(); g.MapWindow( 0, 0.5, 2.2, 0, 0 ); // compute pendulum position var x = this.l * Math.sin( this.a ); var y = -this.l * Math.cos( this.a ) + 1; // draw pendulum g.SetLineAttr( 'black', 2 ); g.Line( 0, 1, x, y ); g.SetMarkerAttr( 'Circle', 20, 'black', 'yellow', 2 ); g.Marker( x, y ); // draw zero marker g.SetMarkerAttr( 'ArrowUp', 10, 'black', 'white', 1 ); g.Marker( 0, -0.04 ); // draw Ft var ax = 0.025 * this.Ft * Math.cos( this.a ); var ay = 0.025 * this.Ft * Math.sin( this.a ); g.SetMarkerAttr( 'Arrow1', 8, 'black', 'red', 1 ) g.Arrow( x, y, x+ax, y+ay, 1, 3 ); // display sim values var sim = this.sim; var txtpos = 0; g.SelectTrans( 'viewport' ); g.SetTextAttr( 'Arial', 16, 'black', 'normal', 'normal', 'left', 'top', 4 ); var cpuDrawMax = sim.CpuLoadFrameMax - sim.CpuLoadSimMax; if (cpuDrawMax < 0) cpuDrawMax = 0; var cpuDrawAvg = sim.CpuLoadFrameAvg - sim.CpuLoadSimAvg; if (cpuDrawAvg < 0) cpuDrawAvg = 0; g.Text( 'FPS max = ' + sim.FpsMax.toFixed(0), 0, 20*txtpos++ ); g.Text( 'CPU sim max = ' + sim.CpuLoadSimMax.toFixed(3), 0, 20*txtpos++ ); g.Text( 'CPU draw max = ' + cpuDrawMax.toFixed(3), 0, 20*txtpos++ ); g.Text( 'CPU frame max = ' + sim.CpuLoadFrameMax.toFixed(3), 0, 20*txtpos++ ); g.Text( 'FPS avg = ' + sim.FpsAvg.toFixed(0), 0, 20*txtpos++ ); g.Text( 'CPU sim avg = ' + sim.CpuLoadSimAvg.toFixed(3), 0, 20*txtpos++ ); g.Text( 'CPU draw avg = ' + cpuDrawAvg.toFixed(3), 0, 20*txtpos++ ); g.Text( 'CPU frame avg = ' + sim.CpuLoadFrameAvg.toFixed(3), 0, 20*txtpos++ ); g.Text( 'RealTime = ' + sim.RealTime.toFixed(1), 0, 20*txtpos++ ); g.Text( 'SimTime = ' + sim.SimulTime.toFixed(1), 0, 20*txtpos++ ); // display pendulum valus g.Text( 'a = ' + this.a.toFixed(2), 0, 20*txtpos++ ); g.Text( 'da = ' + this.da.toFixed(2), 0, 20*txtpos++); g.Text( 'dda = ' + this.dda.toFixed(2), 0, 20*txtpos++); g.Text( 'Ft = ' + this.Ft.toFixed(2), 0, 20*txtpos++); }, }; var PendulumSim = new Sim( { EnableStatistics: true, TimeStep: 0.0005, TimeSpeed: 1, SimObj: PendulumModel, ResetFuncs: function(sim) { sim.SimObj.Reset(); }, TimeStepFuncs: function(sim) { sim.SimObj.Update(); }, FrameFuncs: function(sim) { sim.SimObj.Draw(); }, } ); PendulumModel.Create( PendulumSim ); PendulumSim.Run( true ); function UpdateAll() { ControlPanels.Update(); } PendulumSim.AddResetFunc( UpdateAll ); ControlPanels.NewSliderPanel( { Name: 'SliderPanel', ModelRef: 'PendulumModel', NCols: 1, ValuePos: 'left', OnModelChange: UpdateAll, Format: 'fix0', Digits: 2, ReadOnly: true, PanelFormat: 'InputShortWidth' } ).AddValueSliderField( { Name: 'd1', Min: 0, Max: 2, } ).AddValueSliderField( { Name: 'd2', Min: 0, Max: 2, } ).AddValueSliderField( { Name: 'v0', Color: 'green', Min: -20, Max: 20, } ).AddValueSliderField( { Name: 'g', Color: 'blue', Min: 0, Max: 20, } ).AddValueSliderField( { Name: 'PendulumSim.TimeSpeed', Color: 'black', Label: 'Speed', Min: 0.25, Max: 4, } ).Render(); UpdateAll();