diff --git a/js/faradays-law/model/Voltmeter.js b/js/faradays-law/model/Voltmeter.js index 651623d1..ad371773 100644 --- a/js/faradays-law/model/Voltmeter.js +++ b/js/faradays-law/model/Voltmeter.js @@ -16,26 +16,29 @@ define( function( require ) { // constants var ACTIVITY_THRESHOLD = 1E-3; // Used to prevent perpetual oscillation of the needle, value empirically determined. + var NEEDLE_RESPONSIVENESS = 50; // needle responsiveness + var NEEDLE_FRICTION = 10; // friction coefficient, so needle motion looks realistic /** - * @param faradaysLawModel - simulation model + * @param {FaradaysLawModel} model - simulation model * @param {Tandem} tandem * @constructor */ - function Voltmeter( faradaysLawModel, tandem ) { + function Voltmeter( model, tandem ) { - this.faradaysLawModel = faradaysLawModel; + // @private + this.model = model; - this.omega = 0; // angular velocity of needle in rad/sec - this.alpha = 0; // angular acceleration of needle in rad/s^2 - this.D = 50; // needle responsiveness - this.C = 1; // meter gain - this.B = 10; // friction coefficient, so needle motion looks realistic + // @private {number} - rad/sec + this.needleAngularVelocity = 0; - // Needle angle in radians. This apparently drives both the needle location and the lightbulb brightness. + // @private {number} - rad/s^2 + this.needleAngularAcceleration = 0; + + // @public {NumberProperty} Needle angle in radians. This drives both the needle location and the light bulb brightness. this.thetaProperty = new NumberProperty( 0 ); - // input voltage to meter + // @private - input voltage to meter this.signalProperty = new NumberProperty( 0, { tandem: tandem.createTandem( 'signalProperty' ), units: 'volts' @@ -45,30 +48,31 @@ define( function( require ) { faradaysLaw.register( 'Voltmeter', Voltmeter ); return inherit( Object, Voltmeter, { + /** - * voltmeter needle evolution over time + * Voltmeter needle evolution over time * @param dt */ step: function( dt ) { // Calculate the signal, combining the EMF from both coils. The multiplier (including the sign thereof) is // empirically determined to make the needle move the correct amount and direction. - this.signalProperty.set( -0.2 * (this.faradaysLawModel.bottomCoil.emfProperty.get() + this.faradaysLawModel.topCoil.emfProperty.get()) ); + this.signalProperty.set( -0.2 * (this.model.bottomCoil.emfProperty.get() + this.model.topCoil.emfProperty.get()) ); - this.alpha = this.D * (this.signalProperty.get() - this.C * this.thetaProperty.get()) - this.B * this.omega; //angular acceleration of needle - this.thetaProperty.set( this.thetaProperty.get() + this.omega * dt + 0.5 * this.alpha * dt * dt ); //angle of needle - var omegaTemp = this.omega + this.alpha * dt; - var alphaTemp = this.D * (this.signalProperty.get() - this.C * this.thetaProperty.get()) - this.B * omegaTemp; - this.omega = this.omega + 0.5 * dt * (this.alpha + alphaTemp); //angular velocity + this.needleAngularAcceleration = NEEDLE_RESPONSIVENESS * (this.signalProperty.get() - this.thetaProperty.get()) - NEEDLE_FRICTION * this.needleAngularVelocity; //angular acceleration of needle + this.thetaProperty.set( this.thetaProperty.get() + this.needleAngularVelocity * dt + 0.5 * this.needleAngularAcceleration * dt * dt ); //angle of needle + var omega = this.needleAngularVelocity + this.needleAngularAcceleration * dt; + var alpha = NEEDLE_RESPONSIVENESS * (this.signalProperty.get() - this.thetaProperty.get()) - NEEDLE_FRICTION * omega; + this.needleAngularVelocity = this.needleAngularVelocity + 0.5 * dt * (this.needleAngularAcceleration + alpha); // Clamp the needle angle when its position, velocity, and acceleration go below a threshold so that it doesn't // oscillate forever. - if ( Math.abs( this.alpha ) !== 0 && Math.abs( this.alpha ) < ACTIVITY_THRESHOLD && - Math.abs( this.omega ) !== 0 && Math.abs( this.omega ) < ACTIVITY_THRESHOLD && + if ( Math.abs( this.needleAngularAcceleration ) !== 0 && Math.abs( this.needleAngularAcceleration ) < ACTIVITY_THRESHOLD && + Math.abs( this.needleAngularVelocity ) !== 0 && Math.abs( this.needleAngularVelocity ) < ACTIVITY_THRESHOLD && Math.abs( this.thetaProperty.get() ) !== 0 && Math.abs( this.thetaProperty.get() ) < ACTIVITY_THRESHOLD ) { this.thetaProperty.set( 0 ); - this.omega = 0; - this.alpha = 0; + this.needleAngularVelocity = 0; + this.needleAngularAcceleration = 0; } } } );