Sensor data is written multiple times when using Asynctask - android

I write an app to save sensors data into a file. Goal is to save IMU datas with 100 Hz.
I use Asynctask for the storage part. All seems well; but when i saw values in file, there's a many data written many times. Do you have any ideas:
#Override
public final void onSensorChanged(SensorEvent event) {
//timestamp = (new Date()).getTime() + (event.timestamp - System.nanoTime()) / 1000000L;
timestamp = new Date().getTime();
// Handle accelerometer reading
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
bufferData[0] = event.values[0];
bufferData[1] = event.values[1];
bufferData[2] = event.values[2];
}
// Handle a gyro reading
else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
bufferData[3] = event.values[0];
bufferData[4] = event.values[1];
bufferData[5] = event.values[2];
}
save_IMU save_imu = new save_IMU();
save_imu.execute();
}

AsyncTask is not good choice for your problem.
You'r asynctask reads shared data from the bufferData array which is overiden each time sensor value changes. The AsyncTask is not started in the moment you call execute method. It's put into a queue and than it is waiting for free thread to be executed. So it can take same time before it'll run. Writing to the storage can be slower than you need so the queue will fill up and more tasks can be run between two onSensorChanged calls. Than they can write multiple equal rows as you see.
My suggestion:
Create queue / buffer for measured values. Add new items in onSensorChanged
Use Handler to periodically (e.g. each 250ms) check buffer and write items to disk (more at on run). If you don't want to experiment with handlers it can be also done with AsyncTask.

bufferData should be a local variable of onSensorChanged() function.
You should transfer the buffer to the asynctask with new save_IMU(bufferData );.

Related

Android sensor data isn't smooth

I have an app that stores sensor data into a database every 10ms, but the signal itself has some very sharp peaks:
So it doesn't look like the signal is necessarily noisy, its just around the peaks there aren't enough data points surrounding the peak itself to smooth the peak out
I know I can apply a filter to smooth the signal out, but I'm wondering whether there is anything that I'm doing wrong when polling the sensors/storing into the database that is causing this behaviour
I would have thought that by using a short polling rate like 10ms would give me more data around the peaks to help smooth the peaks out, but reducing that value POLL_FREQUENCY doesn't seem to give me smooth data and I'm not sure why?
I'm collecting the data in a service:
public void onSensorChanged(SensorEvent event) {
sensor = event.sensor;
int i = sensor.getType();
if (i == MainActivity.TYPE_ACCELEROMETER) {
accelerometerMatrix = event.values;
} else if (i == MainActivity.TYPE_GYROSCOPE) {
gyroscopeMatrix = event.values;
} else if (i == MainActivity.TYPE_GRAVITY) {
gravityMatrix = event.values;
} else if (i == MainActivity.TYPE_MAGNETIC) {
magneticMatrix = event.values;
}
long curTime = System.currentTimeMillis();
long diffTime = (curTime - lastUpdate);
// only allow one update every POLL_FREQUENCY (10ms)
if(diffTime > POLL_FREQUENCY) {
lastUpdate = curTime;
//insert into database in background thread
try{
//this simply takes the value from accelerometerMatrix
// and the runnable just inserts into the database as a new row
executor.execute(insertHandler);
} catch (SQLException e) {
Log.e(TAG, "insertData: " + e.getMessage(), e);
}
}
}
So all this code does is wait for a sensor change event, detect the type of event it is (accelerometer, gyro etc), store the value into the appropriate matrix, and if more than 10ms has elapsed, store the matrix values into the database
Can anyone suggest why the peaks are sharp despite using a short poll frequency (10ms)?

android LinkedList , strange behavior

I have an ArrayList of LinkedList to store my sensors captured data in a thread ( using synchronized on the ArrayList object)
upon capture, sensor events are added, I can see the linkedlist increasing, but the first and last element are ALWAYS the last capture event .. something is wrong somewhere ... ?
// main thread ('samplingFifoQueues' passed as an arg to be synchronized ...)
public volatile LinkedList<SensorEvent> accelFifoQueue = new LinkedList<SensorEvent>();
public volatile LinkedList<SensorEvent> magnetFifoQueue = new
.......
public volatile ArrayList<LinkedList<SensorEvent>> samplingFifoQueues = new ArrayList<LinkedList<SensorEvent>>();
In my capture thread , I add the sensor events
LinkedList<SensorEvent> accelFifoQueue;
LinkedList<SensorEvent> magnetFifoQueue;
......
ArrayList<LinkedList<SensorEvent>> samplingFifoQueues;
.....
public void onSensorChanged(SensorEvent sensorEvent) {
...
synchronized (samplingFifoQueues) {
switch (sensorEvent.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
Log.d(TAG, "new accel sensor event at: " + sensorEvent.timestamp );
accelFifoQueue.add(sensorEvent);
SensorEvent nse = accelFifoQueue.getLast();
SensorEvent lse = accelFifoQueue.getFirst();
Log.d(TAG, "accel: " + accelFifoQueue.size() + " elements, last at: " + nse.timestamp + " , first at: " + lse.timestamp);
break;
....
The log output indicate first and last timestamp after each new event , and the first is ALWAYS = to the last, even if the size is increasing :
new accel sensor event at: 1391793870096061895
accel: 1 elements, last at: 1391793870096061895 , first at: 1391793870096061895
new accel sensor event at: 1391793870117302130
accel: 2 elements, last at: 1391793870117302130 , first at: 1391793870117302130
new accel sensor event at: 1391793870121208380
accel: 3 elements, last at: 1391793870121208380 , first at: 1391793870121208380
new accel sensor event at: 1391793870129020880
accel: 4 elements, last at: 1391793870129020880 , first at: 1391793870129020880
as per answer in post : How to make a copy of the Android Sensor SensorEvent Object
the sensorEvent is overwritten... it's a system class so I need to do my own clone object...
This is because you are using ArrayList, and ArrayList was stored sensor event objet's reference, so, all you added to this array list may be the same object's reference, this is why elements in array list are ALWAYS the last capture event.

data being over-written. Android

I am reading data from a sensor into two static double []'s called Gain and Phase. Then depending on what button the user pressed to start collecting data from the sensor, I save this data to another double [].
Ex:
if (What_Button == 1){
oGain = gain;
oPhase = phase;
output.setText("OPEN saved");
}
if (What_Button == 2){
sGain = gain;
sPhase = phase;
output.setText("SHORT saved");
}
if (What_Button == 3){
lGain = gain;
lPhase = phase;
output.setText("LOAD saved");
}
I then wish to plot the original Gain and Phase data. Before I do this I convert the gain into dB and the phase into degrees.
i.e.
for (int i=0; i<_steps; i++) {
phase[i]=Math.toDegrees(phase[i]);
gain[i]=20*Math.log10(gain[i]);
}
This plotting works fine but after gain and phase have been converted my saved data "lgain" "lphase", etc are changed. It is as if they have been reassigned to the new Gain and Phase values instantly. I surrounded the code above with System.out.pritln commands to view the lgain, lphase, etc. values before and after and this is certainly where they are being changed at. I used ctrl-f to find all instances of lgain, lphase, etc and they are not being reassigned anywhere else. Any ideas how to fix this?
C
You are copying phase array by reference rather than value.
Try looking at Arrays.CopyOf documentation to choose a static method to copy the array.
Something like:
oGain = Arrays.copyOf(gain,gain.length);

ORMLite's createOrUpdate seems slow - what is normal speed?

Calling the ORMLite RuntimeExceptionDao's createOrUpdate(...) method in my app is very slow.
I have a very simple object (Item) with a 2 ints (one is the generatedId), a String and a double. I test the time it takes (roughly) to update the object in the database (a 100 times) with the code below. The log statement logs:
time to update 1 row 100 times: 3069
Why does it take 3 seconds to update an object 100 times, in a table with only 1 row. Is this the normal ORMLite speed? If not, what might be the problem?
RuntimeExceptionDao<Item, Integer> dao =
DatabaseManager.getInstance().getHelper().getReadingStateDao();
Item item = new Item();
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
item.setViewMode(i);
dao.createOrUpdate(item);
}
long update = System.currentTimeMillis();
Log.v(TAG, "time to update 1 row 100 times: " + (update - start));
If I create 100 new rows then the speed is even slower.
Note: I am already using ormlite_config.txt. It logs "Loaded configuration for class ...Item" so this is not the problem.
Thanks.
This may be the "expected" speed unfortunately. Make sure you are using ORMLite version 4.39 or higher. createOrUpdate(...) was using a more expensive method to test for existing of the object in the database beforehand. But I suspect this is going to be a minimal speed improvement.
If I create 100 new rows then the speed is even slower.
By default Sqlite is in auto-commit mode. One thing to try is to wrap your inserts (or your createOrUpdates) using the the ORMLite Dao.callBatchTasks(...) method.
In by BulkInsertsTest android unit test, the following doInserts(...) method inserts 1000 items. When I just call it:
doInserts(dao);
It takes 7.3 seconds in my emulator. If I call using the callBatchTasks(...) method which wraps a transactions around the call in Android Sqlite:
dao.callBatchTasks(new Callable<Void>() {
public Void call() throws Exception {
doInserts(dao);
return null;
}
});
It takes 1.6 seconds. The same performance can be had by using the dao.setSavePoint(...) method. This starts a transaction but is not as good as the callBachTasks(...) method because you have to make sure you close your own transaction:
DatabaseConnection conn = dao.startThreadConnection();
Savepoint savePoint = null;
try {
savePoint = conn.setSavePoint(null);
doInserts(dao);
} finally {
// commit at the end
conn.commit(savePoint);
dao.endThreadConnection(conn);
}
This also takes ~1.7 seconds.

How to update Android textviews efficiently?

I am working on an Android app which encounters performance issues.
My goal is to receive strings from an AsyncTask and display them in a TextView. The TextView is initially empty and each time the other process sends a string concatenates it to the current content of the textview.
I currently use a StringBuilder to store the main string and each time I receive a new string, I append it to the StringBuilder and call
myTextView.setText(myStringBuilder.toString())
The problem is that the background process can send up to 100 strings per second, and my method is not efficient enough.
Redrawing the whole TextView everytime is obviously a bad idea (time complexity O(N²)), but I'm not seeing another solution...
Do you know of an alternative to TextView which could do these concatenations in O(N) ?
As long as there is a newline between the strings, you could use a ListView to append the strings and hold the strings themselves in an ArrayList or LinkedList to which you append as the AsyncTask receives the strings.
You might also consider simply invalidating the TextField less frequently; say 10 times a second. This would certainly improve responsiveness. Something like the following could work:
static long lastTimeUpdated = 0;
if( receivedString.size() > 0 )
{
myStringBuilder.append( receivedString );
}
if( (System.currentTimeMillis() - lastTimeUpdated) > 100 )
{
myTextView.setText( myStringBuilder.getChars( 0, myStringBuilder.length() );
}
If the strings come in bursts -- such that you have a delay between bursts greater than, say, a second -- then reset a timer every update that will trigger this code to run again to pick up the trailing portion of the last burst.
I finally found an answer with the help of havexz and Greyson here, and some code here.
As the strings were coming in bursts, I chose to update the UI every 100ms.
For the record, here's what my code looks like:
private static boolean output_upToDate = true;
/* Handles the refresh */
private Handler outputUpdater = new Handler();
/* Adjust this value for your purpose */
public static final long REFRESH_INTERVAL = 100; // in milliseconds
/* This object is used as a lock to avoid data loss in the last refresh */
private static final Object lock = new Object();
private Runnable outputUpdaterTask = new Runnable() {
public void run() {
// takes the lock
synchronized(lock){
if(!output_upToDate){
// updates the outview
outView.setText(new_text);
// notifies that the output is up-to-date
output_upToDate = true;
}
}
outputUpdater.postDelayed(this, REFRESH_INTERVAL);
}
};
and I put this in my onCreate() method:
outputUpdater.post(outputUpdaterTask);
Some explanations: when my app calls its onCreate() method, my outputUpdater Handler receives one request to refresh. But this task (outputUpdaterTask) puts itself a refresh request 100ms later. The lock is shared with the process which send the new strings and sets output_upToDate to false.
Try throttling the update. So instead of updating 100 times per sec as that is the rate of generation. Keep the 100 strings in string builder and then update once per sec.
Code should like:
StringBuilder completeStr = new StringBuilder();
StringBuilder new100Str = new StringBuilder();
int counter = 0;
if(counter < 100) {
new100Str.append(newString);
counter++;
} else {
counter = 0;
completeStr.append(new100Str);
new100Str = new StringBuilder();
myTextView.setText(completeStr.toString());
}
NOTE: Code above is just for illustration so you might have to alter it as per your needs.

Categories

Resources