[JAVA] The story of making an Android application that can adjust the sampling frequency of the accelerometer

Overview

Personally, I wanted the value of the 3-axis accelerometer in the csv file. I think every Qiita fellow has this kind of experience.

So I had Xperia at hand, so I immediately searched from google play and installed the acceleration sensor logger from one end.

Then what! The sampling frequency cannot be set arbitrarily. .. ..

However, since there was an application that could be set on iOS, it is a story that I struggled to make it on Android as well.

First survey

(Caution) This chapter will be written like a study log, not a work log, so please look at it like a diary.

In common with all apps (6 or 7 samples), the sampling interval could only be adjusted roughly.

When investigating this, it seems that the acceleration sensor cannot adjust the specific sampling rate unlike other terminal sensors. Let's take a look at registerListener from SensorManager Reference image.png And the following four variables are basically given to this third argument, int sampling PeriodUs.

image.pngimage.png These are defined in the SensorEvent class (SensorEvent reference)

However, you are wondering what happens if you enter a specific integer in this third argument. So! The following site specifically verified it ← https://akira-watson.com/android/accelerometer.html

By the way, in the actual setup, I did not carry out the preliminary survey so carefully, and I got stuck in a swamp that it did not work well even if I entered an integer, and I arrived here (sweat).

Excuse me for a long time, but as I said earlier, when this fact became clear, I had already started implementing it. I will forcibly adjust the sampling interval by filtering or whatever, I am willing

environment

windows 10 home Android Studio 3.6.3 Android Smartphone Xperia SO-01K API: 28 AVD :Nexus 5X API: 24

Implementation

As you can see from the version, just installed it and touch Android Studio for the first time As a prior knowledge, I know that buttons are easy to make

Insurance time ends, go to design

design

The API was set to 16 with the hope that it could be used on any device. Screenshot_20200419-190507 (2).png

From the conclusion, it looks like this screenshot

Sampling frequency adjustment method

It ’s an implementation method that I came up with.

-Use something like a sleep function to reduce the frame rate for each terminal -Use low / high-pass filtering to generate a threshold that gives the sampling frequency desired by the user. -Implement by thinning out the array at equal intervals and widening the sampling interval. -Write to the csv file every frame

I was able to mention this much

Well this is the order I approached during production As a result, the third one was good, so I didn't do it every frame.

First, visualize the acceleration

First is the sample code when using the accelerometer.

MainActivity.java


    private SensorManager mManager;
    private TextView mX,mY,mZ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Get an instance of the SensorManager
        mManager = (SensorManager) getSystemService(SENSOR_SERVICE);

        mX = (TextView)this.findViewById(R.id.textViewX);
        mY = (TextView)this.findViewById(R.id.textViewY);
        mZ = (TextView)this.findViewById(R.id.textViewZ);
    }

    @Override
    protected void onResume() {
        super.onResume();
        //Listener registration
        Sensor accSensor= sensorManager.getDefaultSensor(
                                Sensor.TYPE_ACCELEROMETER);

        this.mManager.registerListener((SensorEventListener) this, this.accSensor, SensorManager.SENSOR_DELAY_FASTEST);

    }

    @Override
    protected void onPause() {
        super.onPause();
        //Release Listener
        this.mManager.unregisterListener((SensorEventListener)this, this.accSensor);
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {

        mX.setText("Accelerometer X:" + String.valueOf(sensorEvent.values[0]));
        mY.setText("Accelerometer Y:" + String.valueOf(sensorEvent.values[1]));
        mZ.setText("Accelerometer Z:" + String.valueOf(sensorEvent.values[2]));

    }

    public void onAccuracyChanged(Sensor sensor, int n) {
    }
}

This works for the time being, if you want to support multiple sensors, in the onSensorChanged function if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){} Conditionally branch

As you can see from the onSensorChanged method, the values [0]-[2] in the sensorEvent class contain the accelerations of x, y, z [(see SensorEvent reference)](https: // developer. android.com/reference/android/hardware/SensorEvent.html#values)

Therefore, if you add the measurement date and time to this and output it to csv, you can obtain a csv file with the maximum sampling frequency.

There are two methods for detecting the sampling frequency (also described in the last reference material). https://qiita.com/taittide/items/2f6a70eae22117266a66 https://akihito104.hatenablog.com/entry/2013/07/22/013000

The csv output is not the heart of this app, so I will omit it.

Thinning out

The overall flow of this app is

① The START button is pressed       ↓ ② Save x, y, z acceleration in a new list       ↓ ③ The STOP / SAVE button is pressed       ↓ ④ Copy the saved acceleration to csv to the output list       ↓ ⑤ Output to csv from the list for csv output       ↓ ⑥ Discard all list data. Wait for ①

Therefore, the sampling frequency can be adjusted by thinning out to an appropriate size in step (4).

First is the sample code

MainActivity.java



public void changeandcopy_information() {

        accX_w = new ArrayList();
        accY_w = new ArrayList();
        accZ_w = new ArrayList();
        timeStamp_Time_forAcc_w = new ArrayList(timeStamp_Time_forAcc);
        int temp_size = timeStamp_Time_forAcc_w.size();
        boolean once = false;

        //Variables for thinning the array to the desired sampling rate
        int AdjustI = (int)(input_sampling_rate/wantConverting_sampling_rate);

        for (int i = 0; AdjustI*i < temp_size; i++) {
            if(!once){
                timeStamp_Time_forAcc_w.clear();
                once=true;
            }
            accX_w.add(accX.get(AdjustI*i));
            accY_w.add(accY.get(AdjustI*i));
            accZ_w.add(accZ.get(AdjustI*i));
            timeStamp_Time_forAcc_w.add(timeStamp_Time_forAcc.get(AdjustI*i));
        }
}

Description of new character variables Acceleration is stored in accX, axxY, accZ, and it is defined first to copy it to accX_w, axxY_w, accZ_w for csv output. timeStamp_Time_forAcc_w stores the measurement date and time of the frame The maximum sampling frequency of the user's terminal is stored in input_sampling_rate, and the sampling frequency desired by the user is stored in wantConverting_sampling_rate as an integer type. Adjust I and once are as you see the code

If you give a concrete example and explain what you are doing Suppose the maximum sampling frequency of the terminal is 400 (Hz) and the sampling frequency desired by the user is 100 (Hz). Here, if you copy it purely as it is, the array size of the variables _w will increase by 400 per second. Therefore, if the value of 400/100 (maximum sampling frequency (Hz) of the user's terminal / sampling frequency (Hz) desired by the user) is multiplied by i in the for statement, i is 0,1 * 400/100, 2 * 400/100, .., and the size of the array per second is 100, which is 1/4.

Successful sampling frequency adjustment! !! !! When it's not divisible? It can't be helped. Errors are inherent

Actual csv file

image.png image.png image.png

This is the output when the sampling frequency of the actual machine is 423 (Hz) and the sampling frequency you want to convert is 10 (Hz).

The difference from the theoretical value of 0.1 seconds was -0.001 and 0.000, and the maximum error was ± 0.001 as a whole.

I'm wondering why there is no error so far, but it's a happy ending anyway.

Source code

I posted it on github. The usage is a little complicated, so please refer to READ ME.txt. https://github.com/miwazawa/accelerator-logger It has been confirmed to work with Xperia and Nexus mentioned in the environment.

at the end

Thank you for staying with us for a long time.

From around the implementation, I felt like I should give it to github, and I wrote it while feeling that it was a bad sentence (laugh)

Regarding the source code, I'm getting a great warning around activity_main.xml, but it's working so I probably won't fix it!

Probably all the sites I used this time are listed in the reference material, so I think that you can implement it just by looking at it.

It was almost the first time for me to write a proper program in java, so I hope that beginners can refer to it as much as possible in terms of study methods.

From the middle, I realized that it is faster to do it from VBA if you want to play with the array, which is another story.

Reference material

About Java syntax

Type conversion method https://eng-entrance.com/java-var-change https://www.sejuku.net/blog/14531 Integer judgment of string https://techacademy.jp/magazine/19075 How to use Thread.sleep https://engineer-club.jp/java-sleep About csv output https://tech.pjin.jp/blog/2017/10/17/%E3%80%90java%E3%80%91csv%E5%87%BA%E5%8A%9B%E3%81%AE%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89/ https://teratail.com/questions/25005?link=qa_related_pc_sidebar https://teratail.com/questions/49794 list / around array https://www.javadrive.jp/start/linkedlist/index2.html

About accelerometer

Accelerometer mounting https://akira-watson.com/android/accelerometer.html Sampling frequency detection method http://akihito104.hatenablog.com/entry/2013/07/22/013000 https://qiita.com/taittide/items/2f6a70eae22117266a66

About Android Studio

From installation of android studio to Hello World https://akira-watson.com/android/helloworld.html layout https://qiita.com/mii-chang/items/ee965c1e8826d4e59414 edittext input judgment https://qiita.com/HALU5071/items/640652de9e31d4bbdbeb Create text box http://mitoavadn.hatenablog.com/entry/2017/03/11/224529 Button layout https://teratail.com/questions/19171 SharedPreferences https://akira-watson.com/android/sharedpreferences.html External storage request method https://qiita.com/folivora/items/f17a125e0bc88c17a6d3

Knowledge supplement

Activity life cycle https://developer.android.com/guide/components/activities/activity-lifecycle?hl=ja How to use the sensor listener https://techbooster.org/android/device/12524/ https://www.atmarkit.co.jp/ait/articles/1001/15/news119.html How to push from android studio to github https://blog.codecamp.jp/programming-androidstudio-github

Recommended Posts

The story of making an Android application that can adjust the sampling frequency of the accelerometer
An application that acquires the value of the accelerometer by UDP communication between C # and Android
The basics of the process of making a call with an Android app
The story of making an electronic New Year's card app with Vue.js + Rails
The strongest Omikuji app that only I, an EKS Lover, can think of
The story of making ordinary Othello in Java
The story of making the existing Dockerfile GPU compatible
The story of tuning android apps with libGDX
A story about making a Builder that inherits the Builder
The story of making a reverse proxy with ProxyServlet
The story of an Illegal State Exception in Jetty.
I made an Android application that GETs with HTTP
The story of making Dr. Oakid using LINE BOT
The story of making dto, dao-like with java, sqlite
Story of making a task management application with swing, java
[Docker] The story that an error occurred in docker-compose up
The story of dieting the container of the Elixir application as much as possible
The story of making a binding for libui, a GUI library for Ruby that is easy to install
A story that made me regret when a "NotReadablePropertyException" occurred during the development of the Spring Boot application.