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();