com.kircherelectronics.accelerationexplorer.activity.NoiseActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.kircherelectronics.accelerationexplorer.activity.NoiseActivity.java

Source

package com.kircherelectronics.accelerationexplorer.activity;

import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.TextView;

import com.androidplot.xy.XYPlot;
import com.kircherelectronics.accelerationexplorer.R;
import com.kircherelectronics.accelerationexplorer.activity.config.FilterConfigActivity;
import com.kircherelectronics.accelerationexplorer.activity.config.NoiseConfigActivity;
import com.kircherelectronics.accelerationexplorer.filter.LowPassFilterSmoothing;
import com.kircherelectronics.accelerationexplorer.filter.MeanFilterSmoothing;
import com.kircherelectronics.accelerationexplorer.filter.MedianFilterSmoothing;
import com.kircherelectronics.accelerationexplorer.plot.DynamicBarPlot;

/*
 * Acceleration Explorer
 * Copyright (C) 2013-2015, Kaleb Kircher - Kircher Engineering, LLC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * A class intended to measure the noise of the sensor in terms
 * root-mean-squared (RMS). Effectively, the average deviation from the mean of
 * the sensor outputs. Multiple smoothing filters are applied simultaneously to
 * the raw sensor output and can be compared via a bar chart.
 * 
 * @author Kaleb
 *
 */
public class NoiseActivity extends Activity implements SensorEventListener {
    private final static String tag = NoiseActivity.class.getSimpleName();

    // Only noise below this threshold will be plotted
    private final static float MAX_NOISE_THRESHOLD = 0.1f;

    // Plot keys for the noise bar plot
    private final static int BAR_PLOT_ACCEL_KEY = 0;
    private final static int BAR_PLOT_LPF_KEY = 1;
    private final static int BAR_PLOT_MEAN_KEY = 2;
    private final static int BAR_PLOT_MEDIAN_KEY = 3;

    public static int STD_DEV_SAMPLE_WINDOW = 20;

    // Outputs for the acceleration and LPFs
    private float[] acceleration = new float[3];
    private float[] lpfOutput = new float[3];
    private float[] meanFilterOutput = new float[3];
    private float[] medianFilterOutput = new float[3];

    // RMS Noise levels
    private DescriptiveStatistics stdDevMaginitudeAccel;
    private DescriptiveStatistics stdDevMaginitudeLpf;
    private DescriptiveStatistics stdDevMaginitudeMean;
    private DescriptiveStatistics stdDevMaginitudeMedian;

    private DynamicBarPlot barPlot;

    // Handler for the UI plots so everything plots smoothly
    private Handler handler;

    // Low-Pass Filter
    private LowPassFilterSmoothing lpf;

    // Mean filter
    private MeanFilterSmoothing meanFilter;

    private MedianFilterSmoothing medianFilter;

    private Runnable runable;

    // Sensor manager to access the accelerometer sensor
    private SensorManager sensorManager;

    // Text views for real-time output
    private TextView textViewXAxis;
    private TextView textViewYAxis;
    private TextView textViewZAxis;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.layout_noise);

        textViewXAxis = (TextView) findViewById(R.id.value_x_axis);
        textViewYAxis = (TextView) findViewById(R.id.value_y_axis);
        textViewZAxis = (TextView) findViewById(R.id.value_z_axis);

        XYPlot noiseLevelsPlot = (XYPlot) findViewById(R.id.plot_noise);
        noiseLevelsPlot.setTitle("Noise");

        barPlot = new DynamicBarPlot(noiseLevelsPlot, "Sensor Noise", this);

        sensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE);

        lpf = new LowPassFilterSmoothing();
        meanFilter = new MeanFilterSmoothing();
        medianFilter = new MedianFilterSmoothing();

        initStatistics();

        handler = new Handler();

        runable = new Runnable() {
            @Override
            public void run() {
                handler.postDelayed(this, 100);

                updateBarPlot();
                updateAccelerationText();
            }
        };
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_noise, menu);
        return true;
    }

    /**
     * Event Handling for Individual menu item selected Identify single menu
     * item by it's id
     * */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {

        // Log the data
        case R.id.action_settings:

            Intent intent = new Intent(NoiseActivity.this, NoiseConfigActivity.class);
            startActivity(intent);

            return true;

        // Log the data
        case R.id.menu_settings_help:

            showHelpDialog();

            return true;

        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onPause() {
        super.onPause();

        sensorManager.unregisterListener(this);

        handler.removeCallbacks(runable);
    }

    @Override
    public void onResume() {
        super.onResume();

        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_FASTEST);

        lpf.setTimeConstant(getPrefLpfSmoothingTimeConstant());

        meanFilter.setTimeConstant(getPrefMeanFilterSmoothingTimeConstant());

        medianFilter.setTimeConstant(getPrefMedianFilterSmoothingTimeConstant());

        handler.post(runable);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // Get a local copy of the sensor values
        System.arraycopy(event.values, 0, acceleration, 0, event.values.length);

        lpfOutput = lpf.addSamples(acceleration);

        meanFilterOutput = meanFilter.addSamples(acceleration);

        medianFilterOutput = medianFilter.addSamples(acceleration);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    private float getPrefLpfSmoothingTimeConstant() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

        return Float.valueOf(prefs.getString(NoiseConfigActivity.LPF_SMOOTHING_TIME_CONSTANT_KEY, "1"));
    }

    private float getPrefMeanFilterSmoothingTimeConstant() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

        return Float.valueOf(prefs.getString(NoiseConfigActivity.MEAN_FILTER_SMOOTHING_TIME_CONSTANT_KEY, "1"));
    }

    private float getPrefMedianFilterSmoothingTimeConstant() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

        return Float.valueOf(prefs.getString(NoiseConfigActivity.MEDIAN_FILTER_SMOOTHING_TIME_CONSTANT_KEY, "1"));
    }

    /**
     * Initialize the statistics.
     */
    private void initStatistics() {
        // Create the RMS Noise calculations
        stdDevMaginitudeAccel = new DescriptiveStatistics();
        stdDevMaginitudeAccel.setWindowSize(STD_DEV_SAMPLE_WINDOW);

        stdDevMaginitudeLpf = new DescriptiveStatistics();
        stdDevMaginitudeLpf.setWindowSize(STD_DEV_SAMPLE_WINDOW);

        stdDevMaginitudeMean = new DescriptiveStatistics();
        stdDevMaginitudeMean.setWindowSize(STD_DEV_SAMPLE_WINDOW);

        stdDevMaginitudeMedian = new DescriptiveStatistics();
        stdDevMaginitudeMedian.setWindowSize(STD_DEV_SAMPLE_WINDOW);
    }

    private void showHelpDialog() {
        Dialog helpDialog = new Dialog(this);

        helpDialog.setCancelable(true);
        helpDialog.setCanceledOnTouchOutside(true);
        helpDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);

        View view = getLayoutInflater().inflate(R.layout.layout_help_noise, null);

        helpDialog.setContentView(view);

        helpDialog.show();
    }

    /**
     * Update the bar plot.
     */
    private void updateBarPlot() {
        Number[] seriesNumbers = new Number[4];

        stdDevMaginitudeAccel.addValue(Math
                .sqrt(Math.pow(acceleration[0], 2) + Math.pow(acceleration[1], 2) + Math.pow(acceleration[2], 2)));

        double var = stdDevMaginitudeAccel.getStandardDeviation();

        if (var > MAX_NOISE_THRESHOLD) {
            var = MAX_NOISE_THRESHOLD;
        }

        seriesNumbers[BAR_PLOT_ACCEL_KEY] = var;

        stdDevMaginitudeLpf.addValue(
                Math.sqrt(Math.pow(lpfOutput[0], 2) + Math.pow(lpfOutput[1], 2) + Math.pow(lpfOutput[2], 2)));

        var = stdDevMaginitudeLpf.getStandardDeviation();

        if (var > MAX_NOISE_THRESHOLD) {
            var = MAX_NOISE_THRESHOLD;
        }

        seriesNumbers[BAR_PLOT_LPF_KEY] = var;

        stdDevMaginitudeMean.addValue(
                Math.abs(meanFilterOutput[0]) + Math.abs(meanFilterOutput[1]) + Math.abs(meanFilterOutput[2]));

        var = stdDevMaginitudeMean.getStandardDeviation();

        if (var > MAX_NOISE_THRESHOLD) {
            var = MAX_NOISE_THRESHOLD;
        }

        seriesNumbers[BAR_PLOT_MEAN_KEY] = var;

        stdDevMaginitudeMedian.addValue(Math.abs(medianFilterOutput[0]) + Math.abs(medianFilterOutput[1])
                + Math.abs(medianFilterOutput[2]));

        var = stdDevMaginitudeMedian.getStandardDeviation();

        if (var > MAX_NOISE_THRESHOLD) {
            var = MAX_NOISE_THRESHOLD;
        }

        seriesNumbers[BAR_PLOT_MEDIAN_KEY] = var;

        barPlot.onDataAvailable(seriesNumbers);
    }

    private void updateAccelerationText() {
        // Update the acceleration data
        textViewXAxis.setText(String.format("%.2f", acceleration[0]));
        textViewYAxis.setText(String.format("%.2f", acceleration[1]));
        textViewZAxis.setText(String.format("%.2f", acceleration[2]));
    }

}