phetsims / circuit-construction-kit-common

"Circuit Construction Kit: Basics" is an educational simulation in HTML5, by PhET Interactive Simulations.
GNU General Public License v3.0
10 stars 10 forks source link

Add noise to the model #602

Open arouinfar opened 3 years ago

arouinfar commented 3 years ago

A common teacher requests for PhET sims in general is to add noise to the model. As lab instruction is being done online, this is a more timely request.

There is a standalone Java version that included noise that was used for a study. We should reach out to Carl, Engin, and Natasha.

The feature should be accessible through the options dialog and query parameter (similar to the pressure noise in Gas Properties).

@ariel-phet suggests adding this feature to 1.0 if time allows.

Assigning to @samreid to find the documentation for the Java work.

samreid commented 3 years ago

Here is a sim published with that model (May 11, 2015) https://phet-dev.colorado.edu/circuit-construction-kit/3.20.35/

Here is the version in SVN master in April 2015:

package edu.colorado.phet.circuitconstructionkit.model;

import java.util.Random;

/**
 * 
 * Created by samreid on 4/2/15.
 */
public class NoiseGenerator {
    static final Random random = new Random();

    public static double getReadout( double trueVoltage ) {

        double maxVoltage = 10.0; // This parameter is freely chosen.

        // Cap the maximum possible noise to either 10% of the true voltage or 10% of the maximum voltage
        double maxNoise = Math.min( Math.abs( trueVoltage ), maxVoltage ) / 10.0;

        // Noise standard deviation is capped to 2.5% of the maximum voltage / amp
        double voltageNoise;
        if ( Math.abs( trueVoltage ) < maxVoltage ) {
            voltageNoise = random.nextGaussian() * 2.5 / 100.0 * trueVoltage;
        }
        else {
            voltageNoise = random.nextGaussian() * 2.5 / 100 * maxVoltage;
        }

        if ( voltageNoise > maxNoise ) {
            voltageNoise = maxNoise;
        }
        if ( voltageNoise < -maxNoise ) {
            voltageNoise = -maxNoise;
        }
        double voltageDisplay = trueVoltage + voltageNoise;
        return voltageDisplay;
    }

    public static void main( String[] args ) {
        System.out.println( "true voltage\tnoisy readout\tdifference\tpercentNoise" );
        double maxNoise = 0;
        for ( double trueVoltage = -40; trueVoltage <= +40; trueVoltage += 0.05 ) {
            double readout = getReadout( trueVoltage );
            double difference = Math.abs( trueVoltage - readout );
            double percentNoise = Math.abs( difference / trueVoltage * 100 );
            System.out.println( trueVoltage + "\t" + readout + "\t" + difference + "\t" + percentNoise );
            if ( percentNoise > maxNoise ) {
                maxNoise = percentNoise;
            }
        }
        System.out.println( "\t\t\t\t" + maxNoise );
    }
}

Here is the Java model with values filled in by EB in May 2015:

package edu.colorado.phet.circuitconstructionkit.model;

import java.util.Random;

/**
 * 
 * Created by samreid on 4/2/15.
 */
public class NoiseGenerator {
    static final Random random = new Random();

    public static double getReadout( double trueVoltage ) {

        double maxVoltage = 10.0; // This parameter is freely chosen.
        double stdNoise = 3.25;
        double pctCap = 0.125;

        // Cap the maximum possible noise to either 10% of the true voltage or 10% of the maximum voltage
        double maxNoise = Math.min( Math.abs( trueVoltage ), maxVoltage ) * pctCap;

        // Noise standard deviation is capped to 2.5% of the maximum voltage / amp
        double voltageNoise;
        if ( Math.abs( trueVoltage ) < maxVoltage ) {
            voltageNoise = random.nextGaussian() * stdNoise / 100.0 * trueVoltage;
        }
        else {
            voltageNoise = random.nextGaussian() * stdNoise / 100 * maxVoltage;
        }

        if ( voltageNoise > maxNoise ) {
            voltageNoise = maxNoise;
        }
        if ( voltageNoise < -maxNoise ) {
            voltageNoise = -maxNoise;
        }
        double voltageDisplay = trueVoltage + voltageNoise;
        return voltageDisplay;
    }

    public static void main( String[] args ) {
        System.out.println( "true voltage\tnoisy readout\tdifference\tpercentNoise" );
        double maxNoise = 0;
        for ( double trueVoltage = -40; trueVoltage <= +40; trueVoltage += 0.05 ) {
            double readout = getReadout( trueVoltage );
            double difference = Math.abs( trueVoltage - readout );
            double percentNoise = Math.abs( difference / trueVoltage * 100 );
            System.out.println( trueVoltage + "\t" + readout + "\t" + difference + "\t" + percentNoise );
            if ( percentNoise > maxNoise ) {
                maxNoise = percentNoise;
            }
        }
        System.out.println( "\t\t\t\t" + maxNoise );
    }
}

Here is a sim published with that model (May 11, 2015) https://phet-dev.colorado.edu/circuit-construction-kit/3.20.35/

Here is code from CCKModule.java that determines the timing:

    // Methods to support random fluctuations, see #3682
    public static double getTimeToNextRandomFluctuation() {
        double maxDelay = 3000;
        final double minDelay = 200;
        final double range = ( maxDelay - minDelay );
        return Math.random() * range + minDelay;
    }

    public static void fluctuateRandomly( final Runnable runnable ) {
        if ( CCKModule.randomFluctuations ) {
            final double[] timeToNextRandom = {CCKModule.getTimeToNextRandomFluctuation()};
            final double[] lastRandomUpdateTime = {System.currentTimeMillis()};
            new Timer( 100, new ActionListener() {
                @Override public void actionPerformed( ActionEvent e ) {
                    if ( System.currentTimeMillis() - lastRandomUpdateTime[0] > timeToNextRandom[0] ) {
                        runnable.run();
                        timeToNextRandom[0] = CCKModule.getTimeToNextRandomFluctuation();
                        lastRandomUpdateTime[0] = System.currentTimeMillis();
                    }
                }
            } ).start();
        }
    }

The latter is called by NonContactAmmeterNode, VoltmeterNode.UnitNode, SeriesAmmeterNode, with code at the end of their constructors that looks like this:

CCKModule.fluctuateRandomly( new Runnable() {
    @Override public void run() {
        noiseDirty = true;
        update();
    }
} );

Then their update functions have a part like so:

if ( CCKModule.randomFluctuations && noiseDirty ) {
    double readout = NoiseGenerator.getReadout( voltage );
    noise = readout - voltage;
    noiseDirty = false;
}
if ( CCKModule.randomFluctuations ) {
    voltage = voltage + noise;
}
textNode.setText( decimalFormat.format( voltage ) + " V" );
samreid commented 3 years ago

@arouinfar can you please review the behavior in https://phet-dev.colorado.edu/circuit-construction-kit/3.20.35/ "random fluctuations" flavor, and evaluate its design before we proceed?

samreid commented 3 years ago

Non-ohmic bulbs is higher priority than this.

arouinfar commented 3 years ago

This feature will not be included in the CCK: AC 1.0 release. Adding measurement noise is still a long-term goal, but it's no a current quarterly goal, so I'm going to unassign myself and defer.

matthew-blackman commented 1 year ago

Closing this and continuing in the data fluency design epic for CCK

matthew-blackman commented 3 months ago

Reopening for renewed discussion in regard to the data fluency initiative.