Accelerometer Raw Data?

I’m currently transferring an Xcode project to Corona that requires full access to accelerometer data. Xcode, it seems, provides RAW accelerometer data, such that GRAVITY and instantaneous acceleration are combined in each X,Y, Z accel value.  That is, with no movement, and the phone in a vertical or horizontal orientation, ONE of the readings will be close to “1.00”, because of the effect of gravity.

Most people probably don’t want this, being either interested in the direction of the GRAVITY vector (obtainable through low-pass filtering of the accel signals), or in the INSTANTANEAOUS CHANGE OF ACCELERATION data, being a HIGH PASS filtering to exclude the near-constant gravity signal.

CORONA seems to apply filtering to the accelerometer signals… the xGravity, yGravity, zGravity signals appear to have lag, so presumably a LOW PASS FILTER is being applied to raw accelerometer dat before being supplied to us.

On the other hand the “instantaneous” values xInstant, yInstant, zInstant are all centred around zero (z=0.00, y=0.00, z=0.00) if the device is not moved, indicating that the steady state values (e.g. GRAVITY, 1.00) is being removed before transmission to us. This is typically done with a HIGH PASS FILTER.

(Normally, I’d expect raw data to include the GRAVITY effect, giving you something like x=0.01, y=0.99, z=0.01, thereby indicating device orientation in the raw data.  This does NOT seem to be what happens).

The xGravity values are not sufficient, as they have been filtered and therefore delays in the data are apparent (an effect of Low Pass filtering).

My question, given I would like to filter the raw data myself rather than have it done for me… can I access RAW ACCELEROMETER DATA directly through Corona, as I can through Xcode?

The CORONA docs are a little light in the technical details about exactly what is being provide by the accelerometer API.

Does anybody know… Can I access the raw accelerometer data without filtering applied to it first?</p>

Thanks and regards…
 

Hi Doug,

Corona is actually returning the raw values to you. The reason the samples are received “slowly” is because the sample frequency is 10 Hz by default, which means that the sensor will only provide samples every 100 milliseconds. This is the default because it helps conserves battery life. To increase the sampling rate, you can increase the frequency by calling the “system.setAccelerometerInterval()” function.

http://docs.coronalabs.com/api/library/system/setAccelerometerInterval.html

I recommend that you set it to the FPS of your app, like 60. If you set it higher, you’ll receive accelerometer samples faster than the frame rate, which doesn’t provide any real benefit.

Best regards,

Brent Sorrentino

Ideally I’d like the raw accelerometer data so I can filter it myself and make certain inferences from that raw data.

However, I am wondering if simply adding the Instant and Gravity values will get somewhere close to the raw data.  This will depend on the question of whether the LOW PASS cutoff for the built-in GRAVITY filter is the same frequency as the HIGH PASS cutoff for the INSTANT filter and, of course, the quality of the filtering applied (i.e. the sharpness of the cutoff, and any ripples applied by the filtering algorithm).

Does anybody have any thoughts on this?

Oh, thanks Brett… made my last post on this topic before seeing your reply.

The reason it seems that Corona is filtering the accelerometer data is that the Instant x,y,z values are all, at rest, 0.0, 0.0, 0.0,  so the gravity appears to be being filtered out.

So what you are saying is that the xGravity, yGravity and zGravity values are the RAW accelerometer data?  Very good, although I had already set my accelerometer sample rate to 30Hz so I don’t think the 10Hz default is being used.  It certainly does look filtered…

Anyway, thanks very much for your input. I shall keep experimenting.

I’m afraid, whichever way I look at it, that the accelerometer data appears filtered. The GRAVITY values do not jitter with small accelerations, showing that they are being LOW PASS FILTERED, and the jittery INSTANT values do not show the underlying gravity vector (e.g. approx 1.0 on on of the axes, depending on orientation).

Is there any way to access the raw accelerometer data from the API?  The data must be accessible to the API, so that it can filter it.  Is there an undocumented handle which would allow accessing the raw data?  (e.g. is there an “event.xRaw, event.yRaw, event.zRaw” way of accessing data)

– living in hope, I tried “event.xRaw” and “event.x” in hope that it might spit out raw accelerometer values… but no luck. :wink:

Hi Doug,

The engineers tell me that the signals are not being filtered, but I would need to investigate this further and perhaps see your test case to see what’s being reported and when. Did you increase the FPS of your app to 60 in the config.lua file, and match the accelerometer interval to 60? Which devices are you testing on? Does it occur across many different devices?

Best regards,

Brent

Hi again Brent,

Yes, tried increasing to 60Hz on the accelerometer.  Same result…

The basic issue, unless I am mistaken, is that the signals MUST be being filtered because:

  1. The INSTANTANEOUS values do not show a value something like “1.00” (I would, depending on device orientation that one of the values be close to 1.00, indicating the force of gravity.  Of course, change the device orientation and the x, y, z values change, but they should geometrically add up to 1 in steady state due to gravity.)  Instead, the INSTANT values show 0.00 at rest, and then rapidly changing values when the device is moved.  This is what you would expect if the data were being HIGH PASS FILTERED, removing the steady (gravity) component of the acceleration.

These INSTANT values are fine for detecting a direction of movement in relation to the device’s current orientation, as the problematical fact of the overall gravity vector component has been removed.  Good for some uses/users, I am sure…

  1. The GRAVITY values exhibit a delay when the device is moved, or it’s orientation changed.  This suggests to me that the GRAVITY values are the raw data passed through a LOW PASS FILTER, which gives a reliable direction indicator for the gravity vector with the jitter of minor movement removed.  The delay is a natural byproduct of the application of a LOW PASS filter, as high frequency changed (i.e. from rapid movement or jitter) are removed… but this also means rapid orientation/position changes cannot be captured.

Because the Corona API provides 2 different options, INSTANT and GRAVITY, their MUST be some difference in pre-processing of the data (or there wouldn’t be a need to provide them).  

I believe this is done by Corona for user simplicity as, with xCode for example, the user is otherwise required to apply their own filtering to the signals to derive a gravity vector, or to exclude the gravity vector… a reasonably simple task following Googled techniques or existing xCode examples, but a pain in the neck to most I am sure. In that context, Corona providing pre-filtered values is a great idea, except for users who NEED to do their own filtering.

(I am creating an app to measure vehicle movement, and need to relate the data to existing movement models in a mathematical sense that requires me to control the maths applied to the filtering process, and remove or extract the gravity component or steady state acceleration in a precise and measurable way.  Different filters have different mathematical baggage, and not knowing the filtering type and filter parameters used renders the values obtained from the accelerometers via Corona, if they are being pre-filtered, to be useless from a scientific/measurement perspective).

Cheers,

Doug

Doug,

You’re right.  The accelerometer values are filtered.  I misled Brent on this and I apologize for it.

(I wasn’t aware of the filtering myself until digging really deep into the code.)

The filtering is very simplistic and is based on the previous value.  The algorithm is this…

gravityX = (currentAccelerationX * 0.1) + (lastGravityX * 0.9)

gravityY = (currentAccelerationY * 0.1) + (lastGravityY * 0.9)

gravityZ = (currentAccelerationZ * 0.1) + (lastGravityZ * 0.9)

instantX = lastGravityX - gravityX

instantY = lastGravityY - gravityY

instantZ = lastGravityZ - gravityZ

Because of the simplistic algorithm, you’ll always get reading every time Corona receives a reading from the sensor.  So, the above algorithm will not cause any latency.  However, the sensor frequency that you set and the framerate will cause latency.  You’ll need to set the accelerometer interval to 60 Hz like how Brent suggest, *but* that’s not enough.  You’ll also need to up the framerate of your app to 60 FPS because (depending on the platform/OS) Lua events are queued and dispatched per render pass.  You can change the FPS in your “config.lua” as documented here…

   http://docs.coronalabs.com/guide/basics/configSettings/index.html#frame-rate-fps

Hi Joshua,

Thanks for the detailed reply… and for your considered thoughts on implications and work-arounds.

As I mentioned, my particular project needs access to the raw data so that I can apply specifically designed digital frequency algorithms to achieve a known frequency response in the filtering process. Unfortunately, without access to the raw data, that means Corona is unsuitable for my current project.

I understand why you provide filtered data… for most users not needing to include filtering simplifies the design process. I’m sure simplicity is one reason why we prefer Lua over Xcode!

Interestingly, by modifying the filtering algorithm you can achieve desired frequency cutoffs with different sampling rates, thereby not needing to trick the system by using an unnecessarily high sample/frame rate… but the parameters in the algorithm need to be designed based on the desired sampling rate and filter cutoff frequency.  

It isn’t rocket science… there are online calculators for working this stuff out. You would apply a Low Pass filter (which eliminates the rapid changing high frequency signals) for the G values, and a High Pass filter (cutting out the steady state and low frequency signals) for the instantaneous values.

I myself am interested in playing with the filter values to create a “Band Pass” filter (i.e. a filter that cuts out low frequency AND high frequency signals) that will give instantaneous values while removing the high frequency “jitter” that the accelerometers seem to have.

Anyway Brent and Joshua… thank you both for your replies. Please let me know if Corona provides the raw data in a future update.

It would be pretty easy for us to add raw x, y, and z values for you.  In fact, I’m willing to do this today.

But since you’re a “Starter” user, this change won’t be made available to you until our next release… unless you buy a “Pro” subscription, because then you could access our daily builds.

Thanks Joshua, that’s a very “can-do” offer and much appreciated.

However, not an immediate issue for me now as I am well into porting my code into a different Lua development package which provides the raw data already. In some ways it is more difficult to use than Corona and not as polished, but it filled the immediate need…

I do think adding the raw data to your accelerometer API is a good idea though, and perhaps this discussion may be of benefit to others.

For example, from what you’ve said, adjusting the frame rate in Corona may change the frequency cutoffs of the accelerometer filtering, perhaps resulting in (apparently inexplicable until you understand the filtering) changes in accelerometer behaviour (e.g. response time, lag, jitter etc.).  With a user provides the filtering themselves, a change in frame rate could be compensated by different filter values to provide a similar response from the accelerometers.

Best regards,

Doug

Happy to help Doug.

Just to be clear, the frame rate only affects when the accelerometer events get delivered in Corona.  We still receive the accelerometer reading on-time according to the interval that you set.  For example, on Android, we obtain these readings on a separate thread and then queue them to be delivered on the Corona runtime thread on the next render pass.  So, if you set the measurement interval to 100 Hz (ie: 100 readings per second), your Lua listener will then receive multiple accelerometer events per render pass which you can differentiate using the event’s timestamp.

And we’re about finished with adding raw value support today.  It was easy enough to do.  We’re just putting some extra time in updating the accelerometer API documentation, because it is clearly lacking details.

Hi Doug,

Corona is actually returning the raw values to you. The reason the samples are received “slowly” is because the sample frequency is 10 Hz by default, which means that the sensor will only provide samples every 100 milliseconds. This is the default because it helps conserves battery life. To increase the sampling rate, you can increase the frequency by calling the “system.setAccelerometerInterval()” function.

http://docs.coronalabs.com/api/library/system/setAccelerometerInterval.html

I recommend that you set it to the FPS of your app, like 60. If you set it higher, you’ll receive accelerometer samples faster than the frame rate, which doesn’t provide any real benefit.

Best regards,

Brent Sorrentino

Ideally I’d like the raw accelerometer data so I can filter it myself and make certain inferences from that raw data.

However, I am wondering if simply adding the Instant and Gravity values will get somewhere close to the raw data.  This will depend on the question of whether the LOW PASS cutoff for the built-in GRAVITY filter is the same frequency as the HIGH PASS cutoff for the INSTANT filter and, of course, the quality of the filtering applied (i.e. the sharpness of the cutoff, and any ripples applied by the filtering algorithm).

Does anybody have any thoughts on this?

Oh, thanks Brett… made my last post on this topic before seeing your reply.

The reason it seems that Corona is filtering the accelerometer data is that the Instant x,y,z values are all, at rest, 0.0, 0.0, 0.0,  so the gravity appears to be being filtered out.

So what you are saying is that the xGravity, yGravity and zGravity values are the RAW accelerometer data?  Very good, although I had already set my accelerometer sample rate to 30Hz so I don’t think the 10Hz default is being used.  It certainly does look filtered…

Anyway, thanks very much for your input. I shall keep experimenting.

I’m afraid, whichever way I look at it, that the accelerometer data appears filtered. The GRAVITY values do not jitter with small accelerations, showing that they are being LOW PASS FILTERED, and the jittery INSTANT values do not show the underlying gravity vector (e.g. approx 1.0 on on of the axes, depending on orientation).

Is there any way to access the raw accelerometer data from the API?  The data must be accessible to the API, so that it can filter it.  Is there an undocumented handle which would allow accessing the raw data?  (e.g. is there an “event.xRaw, event.yRaw, event.zRaw” way of accessing data)

– living in hope, I tried “event.xRaw” and “event.x” in hope that it might spit out raw accelerometer values… but no luck. :wink:

Hi Doug,

The engineers tell me that the signals are not being filtered, but I would need to investigate this further and perhaps see your test case to see what’s being reported and when. Did you increase the FPS of your app to 60 in the config.lua file, and match the accelerometer interval to 60? Which devices are you testing on? Does it occur across many different devices?

Best regards,

Brent

Hi again Brent,

Yes, tried increasing to 60Hz on the accelerometer.  Same result…

The basic issue, unless I am mistaken, is that the signals MUST be being filtered because:

  1. The INSTANTANEOUS values do not show a value something like “1.00” (I would, depending on device orientation that one of the values be close to 1.00, indicating the force of gravity.  Of course, change the device orientation and the x, y, z values change, but they should geometrically add up to 1 in steady state due to gravity.)  Instead, the INSTANT values show 0.00 at rest, and then rapidly changing values when the device is moved.  This is what you would expect if the data were being HIGH PASS FILTERED, removing the steady (gravity) component of the acceleration.

These INSTANT values are fine for detecting a direction of movement in relation to the device’s current orientation, as the problematical fact of the overall gravity vector component has been removed.  Good for some uses/users, I am sure…

  1. The GRAVITY values exhibit a delay when the device is moved, or it’s orientation changed.  This suggests to me that the GRAVITY values are the raw data passed through a LOW PASS FILTER, which gives a reliable direction indicator for the gravity vector with the jitter of minor movement removed.  The delay is a natural byproduct of the application of a LOW PASS filter, as high frequency changed (i.e. from rapid movement or jitter) are removed… but this also means rapid orientation/position changes cannot be captured.

Because the Corona API provides 2 different options, INSTANT and GRAVITY, their MUST be some difference in pre-processing of the data (or there wouldn’t be a need to provide them).  

I believe this is done by Corona for user simplicity as, with xCode for example, the user is otherwise required to apply their own filtering to the signals to derive a gravity vector, or to exclude the gravity vector… a reasonably simple task following Googled techniques or existing xCode examples, but a pain in the neck to most I am sure. In that context, Corona providing pre-filtered values is a great idea, except for users who NEED to do their own filtering.

(I am creating an app to measure vehicle movement, and need to relate the data to existing movement models in a mathematical sense that requires me to control the maths applied to the filtering process, and remove or extract the gravity component or steady state acceleration in a precise and measurable way.  Different filters have different mathematical baggage, and not knowing the filtering type and filter parameters used renders the values obtained from the accelerometers via Corona, if they are being pre-filtered, to be useless from a scientific/measurement perspective).

Cheers,

Doug

Doug,

You’re right.  The accelerometer values are filtered.  I misled Brent on this and I apologize for it.

(I wasn’t aware of the filtering myself until digging really deep into the code.)

The filtering is very simplistic and is based on the previous value.  The algorithm is this…

gravityX = (currentAccelerationX * 0.1) + (lastGravityX * 0.9)

gravityY = (currentAccelerationY * 0.1) + (lastGravityY * 0.9)

gravityZ = (currentAccelerationZ * 0.1) + (lastGravityZ * 0.9)

instantX = lastGravityX - gravityX

instantY = lastGravityY - gravityY

instantZ = lastGravityZ - gravityZ

Because of the simplistic algorithm, you’ll always get reading every time Corona receives a reading from the sensor.  So, the above algorithm will not cause any latency.  However, the sensor frequency that you set and the framerate will cause latency.  You’ll need to set the accelerometer interval to 60 Hz like how Brent suggest, *but* that’s not enough.  You’ll also need to up the framerate of your app to 60 FPS because (depending on the platform/OS) Lua events are queued and dispatched per render pass.  You can change the FPS in your “config.lua” as documented here…

   http://docs.coronalabs.com/guide/basics/configSettings/index.html#frame-rate-fps

Hi Joshua,

Thanks for the detailed reply… and for your considered thoughts on implications and work-arounds.

As I mentioned, my particular project needs access to the raw data so that I can apply specifically designed digital frequency algorithms to achieve a known frequency response in the filtering process. Unfortunately, without access to the raw data, that means Corona is unsuitable for my current project.

I understand why you provide filtered data… for most users not needing to include filtering simplifies the design process. I’m sure simplicity is one reason why we prefer Lua over Xcode!

Interestingly, by modifying the filtering algorithm you can achieve desired frequency cutoffs with different sampling rates, thereby not needing to trick the system by using an unnecessarily high sample/frame rate… but the parameters in the algorithm need to be designed based on the desired sampling rate and filter cutoff frequency.  

It isn’t rocket science… there are online calculators for working this stuff out. You would apply a Low Pass filter (which eliminates the rapid changing high frequency signals) for the G values, and a High Pass filter (cutting out the steady state and low frequency signals) for the instantaneous values.

I myself am interested in playing with the filter values to create a “Band Pass” filter (i.e. a filter that cuts out low frequency AND high frequency signals) that will give instantaneous values while removing the high frequency “jitter” that the accelerometers seem to have.

Anyway Brent and Joshua… thank you both for your replies. Please let me know if Corona provides the raw data in a future update.