1

I have samples of time-domain data that are constantly updating a LinkedList called "rollHistory" which is then being displayed in a plot, like so:

if (rollHistory.size() > HISTORY_SIZE) {
                        rollHistory.removeFirst(); //remove first value
                    }
                        rollHistory.addLast(sensorReading); //insert latest value


                        rollHistorySeries.setModel(rollHistory , SimpleXYSeries.ArrayFormat.Y_VALS_ONLY); //added 06/24/2013
                        aprHistoryPlot.redraw(); 

                    } 

"HISTORY_SIZE" is the max length of the data to be plotted. This code works fine. However, what I would really like to display is the FFT of the time-domain data instead of the data itself. To accomplish this, I downloaded the JTransform library. The realForwardFull() function seems to expect an array of doubles, so I tried converting the LinkedList (called rollHistory above) to an array, then passing this to the realForwardFull() function. But the rollHistorySeries.setModel command seems to expect a LinkedList. So I then tried converting the output of realForwardFull() back to a linkedlist. The code displays no errors in eclipse, but it shuts down when I try to run it on the phone.

DoubleFFT_1D fftDo = new DoubleFFT_1D(512); 
if (rollHistory.size() > HISTORY_SIZE) {
                        rollHistory.removeFirst();
                    }
                        rollHistory.addLast(sensorReading);

                        Double[] rollHistoryAr = rollHistory.toArray(new Double[0]); // convert rollHistory to array

                        double[] fft = new double[256 * 2];
                        System.arraycopy(rollHistoryAr, 0, fft, 0, 256);            //copy rollHistoryAr to fft array
                        fftDo.realForwardFull(fft);                                 //find fft of rollHistory and save to fft
                        LinkedList rollHistoryFreq = new LinkedList(Arrays.asList(fft)); //convert back to LinkedList
                        rollHistorySeries.setModel(rollHistoryFreq , SimpleXYSeries.ArrayFormat.Y_VALS_ONLY); //added 06/24/2013
                        aprHistoryPlot.redraw(); 
                        //mGraph.addDataPoint(sensorReading);
                } 

I tried wrapping a subset of the above code with a try/catch, like this:

try {
                        //jTransform Attempt
                        Double[] rollHistoryAr = rollHistory.toArray(new Double[rollHistory.size()]);
                        double[] fft = new double[256];
                        System.arraycopy(rollHistoryAr, 0, fft, 0, 256);     
                        dfft.realForward(fft); 
                        LinkedList rollHistoryFreq = new LinkedList(Arrays.asList(fft)); 
                        rollHistorySeries.setModel(rollHistoryFreq, SimpleXYSeries.ArrayFormat.Y_VALS_ONLY); 
                        } catch (Exception e)
                        { e.printStackTrace(); }

In this case, the app runs without the "Unfortunately...stopped" error, but the graph is empty, and the LogCat displays these messages:

07-13 16:18:18.509: W/System.err(11288): java.lang.ArrayStoreException: java.lang.Integer cannot be stored in an array of type java.lang.Double[]
07-13 16:18:18.509: W/System.err(11288): at java.util.LinkedList.toArray(LinkedList.java:958)
07-13 16:18:18.509: W/System.err(11288): at com.example.MyActivity$ArduinoReceiver.onReceive(MyActivity.java:166)
07-13 16:18:18.509: W/System.err(11288): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:758)
07-13 16:18:18.509: W/System.err(11288): at android.os.Handler.handleCallback(Handler.java:725)
07-13 16:18:18.509: W/System.err(11288): at android.os.Handler.dispatchMessage(Handler.java:92)
07-13 16:18:18.509: W/System.err(11288): at android.os.Looper.loop(Looper.java:137) 07-13 16:18:18.509: W/System.err(11288): at android.app.ActivityThread.main(ActivityThread.java:5293)
07-13 16:18:18.509: W/System.err(11288): at java.lang.reflect.Method.invokeNative(Native Method) 07-13 16:18:18.509: W/System.err(11288): at java.lang.reflect.Method.invoke(Method.java:511) 07-13 16:18:18.509: W/System.err(11288): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102) 07-13 16:18:18.509: W/System.err(11288): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
07-13 16:18:18.509: W/System.err(11288): at dalvik.system.NativeStart.main(Native Method)

Does anyone have any ideas as to what I'm doing wrong? I can post more code if necessary. Thanks!

user2517875
  • 103
  • 1
  • 6

1 Answers1

2

When you say the code shuts down, what do you mean? Does it freeze indefinitely and no stack trace is produced or does the application actually crash and produce a stack trace? If it's the former, can you run the app in debug mode and check whether or not its freezing somewhere in the Androidplot library? If it's the latter, could you provide the stack trace?

A couple thoughts on the code above: First, from what I remember, FFT's can be -very- cpu intensive operations. Maybe not as bad as their DFT counterparts, but from the CPU/main thread's perspective still very heavy duty. I can't tell for sure but appears that you are doing all your FFT processing on the main thread, which is bad. I'd strongly suggest doing those calculations on a background thread. There's a fair chance this could resolve your primary issue.

I also noticed a completely optional optimization you might consider: You are using SimpleXYSeries as your Series implementation and you mention above that it's setModel(...) method expects a LinkedList, which is not quite true. It's capable of accepting a LinkedList but will also accept any List. A LinkedList is a good all purpose choice for dynamic implementations that need to grow and shrink arbitrarily. What makes a specific Series implementation performant though is whether or not it matches the application's data model and avoids the need for expensive copy/new operations. Given your use of a FFT library that takes a double[], I think a more efficient design is to write your own XYSeries implementation around a double[] so the data can be shared by both the plot and the fft code. To get the same kind of dynamic scrolling effect in your visible plot you'll unfortunately probably need to implement your double[] as a ring buffer. SimpleXYSeries is just a convenience implementation to help give you started but it's almost never optimal because it tries to cater to the lowest common denominator. Again, this is a totally optional performance optimization which depending on the number of points and frequency you are plotting at could be a total waste of time.

Nick
  • 8,181
  • 4
  • 38
  • 63
  • Thanks for the response, Nick. I can run the app and it won't crash, until I connect to the bluetooth device. Then a popup message says that the app is unresponsive and forces it closed. I unfortunately don't have the bluetooth sensor here, so I won't be able to reproduce the error until Monday. Until then I will research your suggestions, thanks! – user2517875 Jun 28 '13 at 16:02
  • Nick, I reproduced the error in attempt to gather some more information. I don't know what a stack trace is, but essentially the main activity fails to load and an error pops up on the phone saying "Unfortunately, microPlot has stopped." In eclipse, this is then displayed in the console: "[2013-07-13 13:19:46 - ddmlib] An established connection was aborted by the software in your host machine java.io.IOException: An established connection was aborted by the software in your host machine..." – user2517875 Jul 13 '13 at 19:17
  • Diagnostic note: I commented out all the JTransform code, then uncommented the lines one-by-one and reran the app each time. It seems to force-stop once I uncomment this line: "Double[] rollHistoryAr = rollHistory.toArray(new Double[0]); // convert rollHistory to array". Is this conversion incorrect? – user2517875 Jul 13 '13 at 19:35
  • For efficiency, I'd use rollHistory.toArray(new Double[rollHistory.size()] instead. This wont resolve your crash issue though. In order to help further we really do need to see the stack trace. You're already using ddms/adb so you are 99% of the way there...you just need to know what to look for. There's an example of a stack trace for an ArithmeticException in this thread: http://stackoverflow.com/questions/8217500/how-to-print-stacktrace-for-an-exception-android – Nick Jul 13 '13 at 20:30
  • I see. I used the comment by AlexR in the thread you posted to amend my code. It now runs, but the graph doesn't update and multiple warnings are displayed in LogCat. Is this the correct use of a stack trace? Thanks so much for helping, Nick! P.S I edited my original post to include the warnings rather than posting them in here, so that they're easier to read. – user2517875 Jul 13 '13 at 21:24
  • The ArrayStoreException you are getting is a serious one. Basically it's telling you that you need to pass in a Number[], not a Double[]. Not to be crass but these are not Androidplot issues and I unfortunately don't currently have the extra bandwidth to assist further. My suggestion going forward would be to create separate SOF questions for each new Stack Trace that you get as you unravel the bugs in your code. If at some point you land on one that relates specifically to Androidplot I'll be there to help. Good luck! -Nick – Nick Jul 13 '13 at 21:50