When I use onSensorChanged() to test my cellphone's accelerometer, finding that it responses to fast. Almost every 1~3ms onSensorChanged() will be activated. I search for some other cellphone's information feeling that it is kind of weird, so I doubt that my code might be wrong. Here is part of my code:
public void onSensorChanged(SensorEvent se_a) { /* 取得x,y,z加速度值 */
xa = se_a.values[0];
ya = se_a.values[1];
za = se_a.values[2];
final String timeStamp_a = new SimpleDateFormat("HHmmssSSS",
Locale.UK).format(new Date());
String tmp_a = "0 " + timeStamp_a + " " + String.valueOf(xa)
+ " " + String.valueOf(ya) + " " + String.valueOf(za) + "\n";
And part of result is like:
0 160106203 9.5385 -0.6895301 1.1109096
0 160106204 9.500193 -0.5746084 1.1109096
0 160106206 9.576807 -0.5746084 1.1875241
0 160106207 9.461885 -0.6895301 1.3024458
My cellphone is LG G2. I set the accelerometer to SENSOR_DELAY_FASTEST. But using some app on google play to test my accelerometer, it shows that in SENSOR_DELAY_FASTEST the frequency is 120Hz, so it is very weird to find that onSensorChanged() response so fast(1~3ms). Where is my code can be wrong? Please help me!
If the update rate is to fast using SENSOR_DELAY_FASTEST you can set another flag which fit your needs.
See the docs for the different rates you can use:
The default data delay (SENSOR_DELAY_NORMAL) is suitable for
monitoring typical screen orientation changes and uses a delay of
200,000 microseconds. You can specify other data delays, such as SENSOR_DELAY_GAME (20,000 microsecond delay), SENSOR_DELAY_UI
(60,000 microsecond delay), or SENSOR_DELAY_FASTEST (0
microsecond!!!! delay). As of Android 3.0 (API Level 11) you can
also specify the delay as an absolute value (in microseconds).
Edit: Have a look at this method SensorManager.registerListener(SensorEventListener, Sensor, int) where you can specify your delay in ms if no flag supports your needs. This is available since API 9. If you want a specific frequenzy provide it as a parameter.
Related
TL;DR version
I need to scan and get the BSSID / M.A.C address and Signal Level of the nearby Access Points several times a second. WifiManager.startScan() scans about 3.5 seconds which is a bit slow. (better than 6 seconds for others but still too slow for me).
I'm looking for a way to get results every 200ms or maybe even less.
The more detailed version.
I'm trying to build a location finding app that uses WiFi signals instead of the GPS. So far so good with the exception that i need to get a lot of data in order to have accurate and consistent results.
I need to get the BSSID and the Signal Level from every Access Point I can find and than store this data for later use.
I've tried using the WifiManager and the BroadcastReceiver to scan and get the scan results. The problem with them is that they are really slow. It takes at least 3 seconds for a single scan. In 3 seconds signal level value will change , leading to inaccurate results. I also need to have several thousand scans which will take an awful loooot of time. So far I haven't found an alternative.
My phone is currently running Android 8.0.0
Perhaps if I optimise my code the scan will perform faster?
onCreate method:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sensor);
btnMainActivity = (Button) findViewById(R.id.button_ToMainActivity);
btnGetWifiInfo = (Button) findViewById(R.id.button_GetWifiInfo);
textWifiInfo = findViewById(R.id.textView_wifiInfo);
textWifiNr = findViewById(R.id.textView_wifiNr);
mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
mWifiReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context c, Intent intent) {
getScanResultInfo();
timeDifference = SystemClock.elapsedRealtime() - startTime;
textWifiInfo.setText("Seconds elapsed: "+Double.toString(timeDifference /1000.0));
nrOfScans++;
if (nrOfScans < 10){
mWifiManager.startScan();
}
}
};
getWifiInfo();
toMainActivity();
}
public void getScanResultInfo(){
int level;
List<ScanResult> wifiScanList = mWifiManager.getScanResults();
textWifiNr.setText("Nr of detected APs: "+ wifiScanList.size());
for (ScanResult scanResult : wifiScanList) {
level = WifiManager.calculateSignalLevel(scanResult.level, 5);
Log.d("WIFI","Level is " + level + " out of 5 " + scanResult.level + " on " + scanResult.BSSID + " ");
}
}
And when I press the button the scan starts.
public void getWifiInfo(){
btnGetWifiInfo.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
finePermission = false;
startTime = SystemClock.elapsedRealtime();
nrOfScans = 0;
checkPermissions();
if ( finePermission == true){
((WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE)).startScan();
mWifiManager.startScan();
}
else {
Log.d("WIFI"," Missing Permissions: "+finePermission);
}
}
}
);
}
Thank you in advance for your time!
You can skip passive channel scanning by using the hidden API, startscanActive.
startScanActive is not an exposed API in android reference; so use it at your own risk. If you must use it, refer this - https://github.com/mozilla/MozStumbler/issues/40
Also, note that if the API indeed scans only active channels as the name suggests, you will not be able to get APs present on passive channels in your scan results
Bad news from official Android side
https://android.googlesource.com/platform/frameworks/base/+/478ee74428e04522d6ac0bf10c30ddaaf62028a4
and
https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/4f11976612567e57eefb0b58c7aef1059f52b45c
announce (or propose?) to significantly limit scanResult requests per time from v9 Pie on.
In concrete values, your app should be limited to max 4 scanResult requests in 2 minutes.
This will be a disaster/nightmare for all existing WiFi-Tool apps.
Official reason: safe battery.
Let's unite our voices and let them know we want Android as a Swiss Army knife and not let it become another white brick.
I am using FFmpeg in my application to extract frames from a video, the frames will be added to a trim video view where you get an illustration as to what is happening in the video at a specific time within the video. So each frame needs to represent some time within the video.
I dont quite understand how FFmpeg is producing the frames. Here is my code:
"-i",
videoCroppedFile.getAbsolutePath(),
"-vf",
"fps=1/" + frameSeperation,
mediaStorageDir.getAbsolutePath() +
"/%d.jpg"
My app allows you to record a video at a max length of 20s. The number of frames extracted from the video depnds on how long the captured video is. frameSeperation is calculated doing the below code.
String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long videoLength = Long.parseLong(time) / 1000;
double frameSeperationDouble = (double) videoLength;
// Divide by 11 because there is a maximum of 11 frames on trim video view
frameSeperationDouble /= 11;
frameSeperationDouble = Math.ceil(frameSeperationDouble);
int frameSeperation = (int) frameSeperationDouble;
Maybe the above logic is very bad, if there is a better way please can somebody tell me.
Anyway I run the code and below are a few test cases:
A video captured with a length of 6 seconds has 7 frames.
A video captured with a length of 2 seconds has 3 frames.
A video captured with a length of 10 seconds has 12 frames.
A video captured with a length of 15 seconds has 9 frames.
A video captured with a length of 20 seconds has 11 frames.
There is no consistency, and I find it hard to put timestamps against each frame because of this. I feel like my logic is wrong or im not understanding. Any help is much appreciated
Update 1
So I did what you said in comments:
final FFmpeg ffmpeg = FFmpeg.getInstance(mContext);
final File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ mContext.getPackageName()
+ "/vFrames");
if (!mediaStorageDir.exists()){
mediaStorageDir.mkdirs();
}
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(mContext, Uri.fromFile(videoCroppedFile));
String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long videoLength = Long.parseLong(time) / 1000;
double frameSeperationDouble = (double) videoLength / 8;
retriever.release();
final String cmd[] = {
"-i",
videoCroppedFile.getAbsolutePath(),
"-vf",
"fps=1/" + frameSeperationDouble,
"-vframes," + 8,
mediaStorageDir.getAbsolutePath() +
"/%d.jpg"
};
I also tried "-vframes=" + 8 at the same point where I put vFrames in cmd. It doesnt seem to work at all now no frames are being extracted from the video
This is the effective flow for fps=x, with the default rounding method near,
Generate intervals of 1/x seconds, e,g. for x=1/3, intervals are 0-3s, 3-6s, 6-9s... Within each interval, pick an earlier frame whose timestamp is nearest to the midpoint of that interval. This may lead to duplicate frames, when that nearest frame belongs to an earlier interval, and was already picked for that interval. Likely to happen if source is variable frame-rate.
In your case, I would suggest to avoid rounding or stripping fractional values, if possible. Or do it at the end.
I want to write a rule that fires when the heart rate is above 160 for 5 minutes. The rule I came up with is the following:
EPAdministrator cepRule3 = cep.getEPAdministrator();
EPStatement cepStatementRule3 = cepRule3.createEPL("select * from "
+ "HeartRate.win:time(5 min) "
+ "group by macAddress "
+ "having min(heartrate) > 160");
cepStatementRule3.addListener(new rule3Listener());
My HeartRate class has the following fields:
int heartrate;
String heartratesTimestamp;
String macAddress;
The problem i'm facing is that this rule fires every time there is a heart rate above 160. Instead I want it to only fire when the heart rate remains above 160 for 5 minutes. How can I adjust this rule?
EPL:
every(HeartRate(heartrate>160) -> (timer:interval(5 min) and not HeartRate(heartrate<=160))
or simply with and in Java code:
EPStatement cepStatementRule3 = cepRule3.createEPL("every(HeartRate(heartrate>160) -> (timer:interval(5 min) and not HeartRate(heartrate<=160))");
cepStatementRule3.addListener(new rule3Listener());
Look up the EPL pattern syntax in the Esper documentation.
For my thesis I need to measure how long in each stage it takes to connect to a WiFi AP.
I can easily measure everything using SUPPLICANT_STATE_CHANGED_ACTION, but I'm having trouble figuring out how I can measure the time it takes to get the DHCP information.
I just really need to know with a certain precision when the android device gets a new IP. I've tried using CONNECTIVITY_ACTION and inside the BroadcastReceiver checking the IP address, but it's off by at least 1 second, so not too precise.
One more thing if it's relevant: The AP on which I will do the tests won't have internet connection.
Any ideas how this can be done?
Thanks in advance
I managed to solve this problem the following way:
Created a filter with WifiManager.NETWORK_STATE_CHANGED_ACTION
And when there is a new event, I check it the following way:
if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)){
elapseTime = System.currentTimeMillis() - startTime;
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
if (ipAddress != 0 && !wifiConnected) {
wifiConnected = true;
wifiTimeLog = wifiTimeLog + elapseTime + "," + "DHCP Done" + "\n";
state.setText(wifiTimeLog);
}
wifiConnected is a boolean that is set to false before the test. There were some other triggers happening after getting the IP.
Can I use light sensor to measure period between flashes of light? Is there any class that I can use or should I code it by myself? Can anyone provide me with something to start with?
public void onSensorChanged(SensorEvent event) {
difference = System.nanoTime() - startTime;
if (event.values[0] >= 50) {
newdifference = System.nanoTime() - (startTime + difference);
if (newdifference >= 2450 && newdifference < 2550) {
dotordash = ".";
}
else if (newdifference > 7450 && newdifference < 7550) {
dotordash = "-";
}
code += dotordash;
}
show.setText(" " + code);
}
What you do with nanoTime() is basically totally random regarding to get a dot or a hash. There're two things you're interested in:
If the light gets bright enough to count as "flash is on" or "flash is off". This is in the value of the SensorEvent and you already check that with event.values[0] >= 50. To put it in one line of code:
boolean isFlashOn = (event.values[0] >= 50)
Second is to count the time between changes of isFlashOn. You get the actual time of a event only from the SensorEvent itself as it might take some time, till the event is delivered to you. So never try to compare with the current system time.
Saying all that there's still a chance, that the light sensor delivers noise, which would be measure of darkness during a flash. If this is the case, you would need some kind of noise filtering which can get tricky, especially with something with very short durations like a flash. See Signal noise for a discussion about noise and noise filtering.