Set axis values in AndroidPlot - android

I am trying to modify the values of my X axis when plotting with AndroidPlot.
This is because I am trying to represent the FFT of an audio spectrum and I would like the X axis to show the different frequencies.
In the documentation is it recomended to use:
SimpleXYSeries.ArrayFormat.Y_VALS_ONLY
which uses the element index as the x value, but this is not what I need.
I need to do the following operation to convert the axis
f = i * Fs / N
being Fs, the sample rate in Hz and N, the number of points in the FFT.
I know that I need to create a new formatter and I have already check several examples like this,
this.getGraphWidget().setDomainValueFormat(new GraphXLabelFormat());
// ...
private class GraphXLabelFormat extends Format {
private static LABELS = ["Label 1", "Label 2", "Label 3"];
#Override
public StringBuffer format(Object object, StringBuffer buffer, FieldPosition field) {
int parsedInt = Math.round(Float.parseFloat(object.toString()));
String labelString = = LABELS[parsedInt];
buffer.append(labelString);
return buffer;
}
#Override
public Object parseObject(String string, ParsePosition position) {
return java.util.Arrays.asList(LABELS).indexOf(string);
}
}
The problem is that I dont really understand how it works and I donĀ“t know how to adapt it to my necesities.
Thanks in advance!

By default, the "object" field of your custom Format's format(Object, StringBuffer, FieldPosition) method corresponds to 'i' in your equation. You should therefore be able to do something like this:
#Override
public StringBuffer format(Object object, StringBuffer buffer, FieldPosition field) {
int i = Math.round(Float.parseFloat(object.toString()));
// assumes 'freqHz' and 'samples' (your array or list of of underlying samples) is
// within scope of this method call:
String thisFreq = i * (freqHz / samples.length);
buffer.append(thisFreq + "Hz");
return buffer;
}

Related

Android Run Time Array Size Efficiency

My tide prediction application uses 8 double arrays for tide height calculations. Literally every tide station in the United States requires these to have 37 elements, EXCEPT Anchorage, Alaska which requires 124 elements.
Here is a declaration example
final int NUM_C = 37; //all stations except anchorage use 37
//final int NUM_C = 124; //anchorage uses 124
double a[] = new double[NUM_C + 1];
Can I efficiently specify the array size at the start up of the app? I can determine which is needed. I don't want to burden the application with inefficiency for 99% + of the users to handle this one case. The difference is only about 3K bytes.
Why don't you instantiate the variable in the constructor? It gives you more freedom to do programatic manipulation.
public class Station {
double a[];
public Station(String location) {
if(location.equals("Anchorage")) {
a = new double[124];
} else {
a = new double[37];
}
}
}
As I understand the instantiation of the object fields in the constructor is the normal case, while the instantiation with the declaration is just an additional feature of Java.
As for the speed it does not make a difference, if you specify the size by a literal value, a constant or a variable. A more interesting question is, if you should use ArrayList instead of an array. See here.
public class Station {
ArrayList<Double> a;
public Station(String location) {
if(location.equals("Anchorage")) {
a = new ArrayList<>(124);
} else {
a = new ArrayList<>(37);
}
}
}
My choice would be ArrayList as it is more flexible. Eight times 124 is not a very large number anyway. No reason to worry about performance for this.

How to handle time series in MPAndroidChart?

I want to add the following sort of data (can be any number of such pairs under 1000) to the newly introduced timeseries chart in MPAndroidChart library
Value : 50.0 at 1472112259
Value : 49.0 at 1472112294
Value : 50.0 at 1472112329
Value : 50.0 at 1472112360
Value : 50.0 at 1472112392
The following data will be fetched from the array.
Right now, I guess there is some mess up with the timestamps.
Here is the complete code: https://gist.github.com/utkarshns/e1723dcc57022fcd392bc3b127b6c898
UNIX timestamps will be parsed to required time format after I can successfully add values to the graph.
Currently, the problem I face is that the timestamps probably get clipped and values are overwritten which leads to a pretty messed up graph with really weird x-axis values.
Update:
Screenshots:
http://imgur.com/a/dGfmz
The problem is that Float values can't hold very big numbers and still be accurate, so you need a separate List with these timestamp values. BigDecimal should be ok for this purpose. Your distances must be in accordance to the time gaps between your events. Just iterate from the start date to end date keeping count of how many timestamps you have and add Entry with count from the timestamps you wish your value to be.
Long myValues[] = {1472112259L, 1472112294L, 1472112329L, 1472112360L, 1472112392L};// your values
ArrayList<Entry> values = new ArrayList<>();// Entry List
Long start = 1472112259L;//start
Long end = 1472112392L;//end
List<BigDecimal> mList = new ArrayList<>(); //Decimal list which holds timestamps
int count = 0;
for (Long i = start; i <= end; i++) {
mList.add(new BigDecimal(i));
if (myValues.equals(i)) {
values.add(new Entry(count, 50));
}
count++;//always increment
}
And your ValueFormatter should look like this:
AxisValueFormatter() {
private FormattedStringCache.Generic<Long, Date> mFormattedStringCache = new FormattedStringCache.Generic<>(new SimpleDateFormat("HH:mm:ss"));
#Override
public String getFormattedValue ( float value, AxisBase axis){
return mFormattedStringCache.getFormattedValue(new Date(mList.get((int)value).longValueExact()*1000), value);
}
#Override
public int getDecimalDigits () {
return 0;
}
}
If you have any question or something is unclear I'll be happy to help.

How to get byte by byte from byte array

I am getting response from server in string format like
V1YYZZ0x0000010x0D0x00112050x0C152031962061900x0D410240x0E152031962061900x0F410240x1021TATADOCOMOINTERNET101
Then I am converting it in to byte array because i need to get value from this byte by byte.
I tried to use
Arrays.copyOfRange(original,
from , to);
but it work on index basis not on byte basis.
I also tried following solution but it also truncating String(if I use string instead of byte[]) on length basis.
public static String truncateWhenUTF8(String s, int maxBytes) {
int b = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
// ranges from http://en.wikipedia.org/wiki/UTF-8
int skip = 0;
int more;
if (c <= 0x007f) {
more = 1;
} else if (c <= 0x07FF) {
more = 2;
} else if (c <= 0xd7ff) {
more = 3;
} else if (c <= 0xDFFF) {
// surrogate area, consume next char as well
more = 4;
skip = 1;
} else {
more = 3;
}
if (b + more > maxBytes) {
return s.substring(0, i);
}
b += more;
i += skip;
}
return s;
}
I know how to calculate string in byte length but it giving only full string length in byte like
Here is how I need to extract packet on byte basis.
Above codes and parameters is only example. I need to get byte by byte from string/byte array.
I searched lot but didn't get any solution or link which I can refer. I am not getting how to split string using byte length because I know byte length for each parameter and for value also.
Please give me any reference or hint.
To determine what is equal to one byte in a String is not trivial. Your String contains bytes in hexadecimal text form: 0x0D (one byte, equal to 13), but also contains values as substrings. For example 1024 can be interpreted as an integer which in this case fits into 2 bytes, but could also be interpreted as a text made up by 4 chars, totaling to 8 bytes.
Anyways, I would split the string using a regular expression, and then further split the parts to length and value:
String message = "V1YYZZ0x0000010x0D0x00112050x0C152031962061900x0D41024"+
"0x0E152031962061900x0F410240x1021TATADOCOMOINTERNET101";
String regex = "(0)(x)(\\w\\w)";
String[] parts = message.split(regex);
Log.d(TAG,"HEADER = "+parts[0]);
for (int i=1; i<parts.length; i++) {
String s = parts[i];
// Only process if it has length > 0
if (s.length()>0) {
String len = "", val = "";
// String s is now in format LVVVV where L is the length, V is the value
if (s.length() < 11) {
// 1 character indicates length, up to 9 contains value
len = s.substring(0, 1);
val = s.substring(1);
} else if (s.length() > 10) {
// 2 characters indicate length, up to 99 contains value
len = s.substring(0, 2);
val = s.substring(2);
} else if (s.length() > 101) {
// 3 characters indicate length, up to 999 contains value
len = s.substring(0, 3);
val = s.substring(3);
}
Log.d(TAG, "Length: " + len + " Value: " + val);
}
}
This produces the following output:
D/Activity: HEADER = V1YYZZ
D/Activity: Length: 0 Value: 001
D/Activity: Length: 1 Value: 1205
D/Activity: Length: 15 Value: 203196206190
D/Activity: Length: 4 Value: 1024
D/Activity: Length: 15 Value: 203196206190
D/Activity: Length: 4 Value: 1024
D/Activity: Length: 21 Value: TATADOCOMOINTERNET101
Then you can check the packages (the first two package in the header is not needed), convert Strings to whatever you would like (e.g. Integer.parseInt(val))
If you explain the structure of the header (V1YYZZ0x0000010x0D0x0011205), I can improve my answer to find the message count.
I think it is doable with Scanner
import java.util.Scanner;
public class Library {
public static void main(String[] args) {
String s = "V1YYZZ0x0000010x0D0x001120"
+ "50x0C152031962061900x0D410240x0E152031962061900x0F410240x1"
+ "021TATADOCOMOINTERNET101";
// Skip first 9? bytes. I'm not sure how you define them
// so I just assumed it is 26 chars long.
s = s.substring(26, s.length());
System.out.println(s);
Scanner scanner = new Scanner(s);
// Use byte as delimiter i.e. 0xDC, 0x00
// Maybe you should use smth like 0x[\\da-fA-F]{2}
// And if you want to know that byte, you should use
// just 0x and get first 2 chars later
scanner.useDelimiter("0x\\w{2}");
// Easily extracted
int numberOfParams = scanner.nextInt();
for (int i = 0; i < numberOfParams; i++) {
String extracted = scanner.next();
// Length of message
int l = extracted.length();
boolean c = getLength(l) == getLength(l - getLength(l));
l -= getLength(l);
l = c ? l : l-1;
System.out.println("length="
+ extracted.substring(0, extracted.length()-l));
System.out.println("message="
+ extracted.substring(extracted.length()-l, extracted.length()));
}
// close the scanner
scanner.close();
}
// Counting digits assuming number is decimal
private static int getLength(int l) {
int length = (int) (Math.log10(l) + 1);
System.out.println("counted length = " + length);
return length;
}
}
We definitely need more information about rules, how string is formed. And what exactly you need to do. This code might be good enough you. And without comments it is really short and simple.
This is not a answer to accessing a byte array byte by byte, but is an answer for the situation in which you find yourself.
Your explanation and description have the appearance of being confused as to what it is that you are really getting from the server (e.g. it is quite hard to represent "V1YYZZ0x0000010x0D0x001120" as a 9 byte field (note it probably ends on the 2, not the 0)). Alternately, that you are using the wrong method to get it from the server, or not getting it as the intended data type.
Your code indicates that you believe that what you are getting is a UTF8 string. The data shown in your question does not appear to indicate that it is intended to be in that format.
Keep in mind when doing something like this that some other programmer had to create structure for the data that you are seeing. They had to define it somewhere with the intent that it be able to be decoded by their intended recipients. Unless there are other considerations (security, minimal bandwidth, etc.), such formats are usually defined in a way that is both easy to encode and decode.
The existence of the multiple "0x"-ASCII-encoded hexadecimal numbers --particularly the single byte representing the parameter (called "varam" in your graphic)-- strongly implies that this data was intended to be interpreted as a ASCII encoded string. While that might not be the case, it should be kept in mind when looking at the problem from a larger perspective.
You are having to put too much effort into decoding the information you are getting from the server. It, probably, should be relatively easy unless there are considerations why it would have intentionally been made difficult.
All of this indicates that the real problem exists in an area for which you have provided us with no information.
Step back:
Think about things like:
How are you receiving this from the server (what function/interface)?
In the call requesting the information from the server is there a way to specify the encoding type be bytes, an ASCII string, or some other format that is easier to deal with than UTF8? At a minimum, it appears to be clear that the data was not intended to be handled as a UTF8 string. There should be a way for you to get it without it having been converted to UTF8.
Also, you should try to find an actual specification for the format of the data. You have not explained much about the source, so it may be you are reverse-engineering something and have no access to specifications.
Basically, it looks like this is a problem where it might be a good idea to step back and ask if you are starting from the point that makes it easiest to solve and if you are headed in the right direction for doing so.
I'm sure I'm missing something obvious...
String.getBytes();
And if you want to process it in order taking defined objects from the array, just wrap using
ByteBuffer.wrap();
The result being something along the lines of:
String s = "OUTPUT FROM SERVER";
byte[] bytes = s.getBytes();
ByteBuffer bb = ByteBuffer.wrap(bytes);
What did I miss from the initial question? :/

Is my target selection AI efficient?

quick question. I am developing a top-down 2d Platformer game with lots of enemies in the map (at least a hundred spawn at the start of each level). Each enemy uses an AI that searches the map for objects with a specified tag, sorts each object into a list based on their distance, then reacts to the object closest to them.
My code works, but the thing is, if the machine my game is running on is slow, then my game lags. I want to be able to port my game to Android and iOS with low end specs.
In pursuit of putting less strain on the CPU, is there a better way to write my AI?
Here is my code:
void Start () {
FoodTargets = new List<Transform>(); // my list
SelectedTarget = null; // the target the enemy reacts to
myTransform = transform;
AddAllFood ();
}
public void AddAllFood()
{
GameObject[] Foods = GameObject.FindGameObjectsWithTag("Object");
foreach (GameObject enemy in Foods)
AddTarget (enemy.transform);
}
public void AddTarget(Transform enemy)
{
if (enemy.GetComponent<ClassRatingScript>().classrating != 1) { // classrating is an attribute each enemy has that determines their identity (like if they are a plant, a herbivore or a carnivore)
FoodTargets.Add (enemy); // adds the object to the list
}
}
private void SortTargetsByDistance() // this is how I sort according to distance, is this the fastest and most efficient way to do this?
{
FoodTargets.Sort (delegate(Transform t1, Transform t2) {
return Vector3.Distance(t1.position, myTransform.position).CompareTo(Vector3.Distance(t2.position, myTransform.position));
});
}
private void TargetEnemy() // this is called every 4 frames
{
if (SelectedTarget == null) {
SortTargetsByDistance ();
SelectedTarget = FoodTargets [1];
}
else {
SortTargetsByDistance ();
SelectedTarget = FoodTargets [1];
}
}
if (optimizer <= 2) { // this is a variable that increments every frame and resets to 0 on the 3rd frame. Only every 3rd frame is the target enemy method is called.
optimizer++;
} else {
TargetEnemy ();
// the rest are attributes that the AI considers when reacting to their target
targetmass = SelectedTarget.GetComponent<MassScript> ().mass;
targetclass = SelectedTarget.GetComponent<ClassRatingScript> ().classrating;
mass = this.GetComponent<MassScript> ().mass;
classrating = this.GetComponent<ClassRatingScript> ().classrating;
distance = Vector3.Distance (transform.position, SelectedTarget.transform.position);
optimizer = 0;
}
Is there a more optimized way of doing this? Your help will be much appreciated. Thanks in advance!
I'm not awfully familiar with C# or Unity but I would look very carefully at what sorting algorithm your sorting method is using. If all you want is the closest Game Object, then sorting isn't necessary.
The fastest sorting algorithms, such as Quicksort, are O(n*log(n)). That is to say that the time it takes to sort a collection of n objects is bounded by some constant multiple of n*log(n). If you just want the k closest objects, where k << n, then you can perform k iterations of the Bubble Sort algorithm. This will have time-complexity O(k*n), which is much better then before.
However, if you only need the single closest object, then just find the closest object without sorting (pseudocode):
float smallestDistance = Inf;
object closestObject = null;
foreach object in objectsWithTag {
float d = distance(object, enemy);
if (d < smallestDistance) {
smallestDistance = d;
closestObject = object;
}
}
This extremely simple algorithm has time complexity O(n).

Renderscript return F64 allocation type, how do you read it in java?

I created an allocation using a F64 as the element because I need the 64 bit precision for calculations:
Allocation mOutAllocation = Allocation.createSized(mRS,Element.F64(mRS),1,Allocation.USAGE_SCRIPT);
I am trying to get the result back after calling the mScript.forEach_root(mOutAllocation). Normally you would usually copy the mOutAllocation to an array and process the array but double is not one of the available array types (only bytes[], int[], float[], short[], and bitmap).
mScript.forEach_root(mOutAllocation);
double[] x = new double[1];
mInAllocation.copyTo(x);
Any ideas please?
Can you read it as a long and convert those bits to a double?
Double.longBitsToDouble(long bits) should do the conversion assuming you don't need to byte swap.
It takes a long (64 bits) and interprets that bit pattern as an IEEE double.
EDIT: try this to convert from an int[] to a long
int[] ints = new int[]{0x01234567, 0x89abcdef};
long l = (long)ints[0] + ((long)ints[1])<<32;
double d = Double.longBitsToDouble(l);
If all you need is to copy one double to and from the RenderScript
context, you can declare a non-static variable and use the
automatically generated getters/setters:
// whatever.rs
double hopper;
void root(const double *in, //...
// Whatever.java
mScript = new ScriptC_whatever(mRS);
double hopper = 1.234;
mScript.set_hopper(hopper);
If you need a full Allocation, you can use NIO to encode your array of
doubles as an array of bytes. Then you can just copy them to an Allocation
using copyFromUncheced.
I don't know how to query byte order in the RenderScript context programmatically-
I discovered that mine needed reversal by trial and error.
// whatever.rs
double *target;
void root(const double *in, //...
// Whatever.java
public void copyDoublesTo(double[] entries, Allocation target)
throws IOException {
if (!target.getType().getElement().isCompatible(Element.F64(mRS)))
throw new RSRuntimeException("Type mismatch: Element != F64");
if (target.getType().getCount() != entries.length)
throw new RSRuntimeException("Type mismatch: wrong # of entries");
mScript.bind_target(target);
ByteArrayOutputStream bytes = new ByteArrayOutputStream(Double.SIZE * dim);
DataOutputStream longs = new DataOutputStream(bytes);
long temp;
for(int i=0; i!=dim; ++i) {
temp = Double.doubleToLongBits(entries[i]);
// reverse byte order:
temp = Long.reverseBytes(temp);
longs.writeLong(temp);
}
target.copyFromUnchecked(bytes.toByteArray());
}
You can also initialize your Allocation by binding it to a
pointer then looping through your array of double, setting
each entry:
// whatever.rs
double *target;
void setTargetEntry(int index, double entry) {
target[index] = entry;
}
void root(const double *in, //...
public void copyDoublesTo(double[] entries, Allocation target) {
if (!target.getType().getElement().isCompatible(Element.F64(mRS))) {
throw new RSRuntimeException("Type mismatch: Element != F64");
}
if (target.getType().getCount() != entries.length) {
throw new RSRuntimeException("Type mismatch: wrong # of entries");
}
mScript.bind_target(target);
for(int i=0; i!=entries.length; ++i) {
mScript.invoke_setTargetEntry(i, entries[i]);
}
}
If you need double2 or similar, just exchange double with Double2
in Java. This solves your problem a bit more naturally than the other
solutions which rely on ... creative packing schemes, so RenderScript will
figure out pesky issues like byte order for you. However, it entails
a serial loop over the Allocation, which is slow
(and you'll need another to get the data back). For comparison, when I
tested this copying 2^10 float averaged 30ms, whereas the native
copyTo method took just 0.1ms. (The NIO method takes around 2ms)

Categories

Resources