Reducing UI lags with AsyncTask in PSLab Android

In the Oscilloscope Activity, communication with the PSLab device goes in parallel with updations of the graph which result in inoperable UI if both these functions are performed in the main thread. This would severely degrade the user experience. In order to avoid this, we simply used AsyncTask. AsyncTasks are used to perform communications with the device in the background thread and update UI when the task in background thread completes. AsyncTask thus solves the problem of making UI super laggy while performing certain time-consuming functions. The UI remains responsive throughout.

More about AsyncTask

AsyncTask is an abstract Android class which helps the Android applications to handle the Main UI thread in a more efficient way. AsyncTask class allows to perform long lasting background operations and update the results in UI thread without affecting the main thread.

Implementing AsyncTask in Android applications

  • Create a new class inside Activity class and extend AsyncTask:

private class Task extends AsyncTask<Void, Void, Void> {
  	protected Long doInBackground(aVoid) {
     	}
 	protected void onProgressUpdate(aVoid) {
     	}
 	protected void onPostExecute(aVoid) {
     	}
}
  • Execute the task:

new Task().execute();

How they are used in Oscilloscope Activity?

The following diagram explains how AsyncTasks are used in Oscilloscope Activity. 

AsyncTask in PSLab Android App

A public class extending AsyncTask is defined, this task is executed from another thread.

public class Task extends AsyncTask<String, Void, Void> {
   ArrayList<Entry> entries;
   String analogInput;

 

doInBackgroundMethod performs the part related to communication with the PSLab device.

Here we are capturing the data from the hardware using captureTraces and fetchTraces method.

 @Override
   protected Void doInBackground(String... params) {
       try {
           analogInput = params[0];
           //no. of samples and timegap still need to be determined
           scienceLab.captureTraces(1, 800, 10, analogInput, false, null);
           Log.v("Sleep Time", "" + (800 * 10 * 1e-3));
           Thread.sleep((long) (800 * 10 * 1e-3));
           HashMap<String, double[]> data = scienceLab.fetchTrace(1); //fetching data
           double[] xData = data.get("x");
           double[] yData = data.get("y");
           entries = new ArrayList<Entry>();
           for (int i = 0; i < xData.length; i++) {
               entries.add(new Entry((float) xData[i], (float) yData[i]));
           }
       }
       catch (NullPointerException e){
           cancel(true);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       return null;
   }

 

After the thread, completely executed onPostExecute is called to update the UI/graph. This method runs on the main thread.

 @Override
   protected void onPostExecute(Void aVoid) {
       super.onPostExecute(aVoid);
       LineDataSet dataset = new LineDataSet(entries, analogInput);
       LineData lineData = new LineData(dataset);
       dataset.setDrawCircles(false);
       mChart.setData(lineData);
       mChart.invalidate();    //refresh the chart
       synchronized (lock){
           lock.notify();
       }
   }
}

 

This simply solves the problem of lags and the Oscilloscope works like a charm.

Resources

Continue ReadingReducing UI lags with AsyncTask in PSLab Android

Adding Tablet support for PSLab Android App

Making layouts compatible with tablet definitely, helps in increasing the target audience. Tablets are different than smartphones, they available in size as big as 7’’ and 10’’. This gives developers/designers a lot of screen space to work on which in turn can be utilized in a way different than smartphones. In the PSLab Oscilloscope Activity and in fact the entire application needs to have tablet support. To achieve these two approaches are used. They are as follow:

  1. Creating layouts compatible with the tablet
  2. Programmatically differentiate between phone and tablet

Creating layouts compatible with the Tablet

A series of following steps help to create layouts for the tablet with much ease

  1. Right click on layouts. Then move the cursor to new and select Layout resource file.

  1. A new resource file dialog box will appear. Under filename type the same name of the file for which you want to create tablet layout. Under directory name type layout-sw600dp for the layout of 7’’ tablet and layout-sw720dp for layout of 10’’ tablet.

  1. The Android Studio will automatically create a folder with two layouts, one for phone and another for tablet inside layouts folder. Now you can work on tablet layout and make the app compatible with the tablet.

Programmatically differentiate between Phone and Table

In Oscilloscope Activity of PSLab Android App, the dimensions of the layout are programmatically set. These dimensions are different from that should be used for the tablet. So, it is important for the app to know whether it’s operating on a phone or a tablet.

This can be achieved using the following steps.

  1. Right click on resources, move the cursor on new and select Android resource file.

  1. A new resource file dialog will appear, under file name type isTablet and press OK. Here we are creating a resource for a phone.

  1. In the XML file isTablet write the following code.

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <bool name="isTablet">false</bool>
</resources>

This resource returns false when accessed.

  1. Repeat 1, 2 step and under new resource file dialog box type values-600dp. Then write the following code.

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <bool name="isTablet">true</bool>
</resources>

This resource returns true when accessed.

  1. Now you can access this resource in Activity simply writing the following code.

boolean tabletSize = getResources().getBoolean(R.bool.isTablet);

tabletSize will be true if accessed in a tablet otherwise it will be false. Hence code can written accordingly.

By this way, we can find whether the application is running on tablet or phone programmatically.

Resources

 

Continue ReadingAdding Tablet support for PSLab Android App

Developing Oscilloscope UI in PSLab Android App

User Interface (UI) is one of the most important part of any software development. In PSLab while developing the UI of the Oscilloscope the following points are very critical.

  1. The UI should expose all the functionalities of Oscilloscope that can be performed using PSLab.
  2. The UI should be very convenient to use. It should allow the user to access functionalities of the PSLab with ease.
  3. The UI should be attractive.

Since Android smartphones come with relatively small size, it was a challenge to develop a UI for Oscilloscope. In this blog, I am going to mention the steps involved in developing the Oscilloscope UI.

Step 1: Creating a mockup

Initially, a mock-up for Oscilloscope UI is created using moqups tool. Later, the mock-up was discussed in public channel where fellow developers and mentors approved it. Let’s discuss some benefits of adopting this layout for Oscilloscope Activity.

  • The graph is ensured maximum screen space as it is the most important component/section of the Oscilloscope. This is also the reason why we kept the screen orientation to landscape.
  • The widgets don’t populate the screen, make the UI look clean.
  • The UI is comparable to basic app’s people use in their daily lives hence very convenient to use.

Mockup of Oscilloscope UI developed using moqups tool

Step 2: Deciding the API to be used

In Oscilloscope Activity, the main component is the graph. The captured data from the PSLab device is plotted on the graph. We decided to use MPAndroidCharts for the same.

Step 3: Deciding the space given to different sections of the UI

The next step was to decide how much screen space each section of Oscilloscope should acquire. There are 3 sections of the Oscilloscope UI.

  1. Graph
  2. Side panel consisting of buttons, each button loads a different set Oscilloscope controls and features in 3.
  3. A lower panel which is basically a fragment displaying controls and features corresponding to the button selected in 2.

By trying different dimensions and arrangements the following configuration fits the best.

To achieve this, the dimensions of different sections is set programmatically. This makes the UI compatible with different screen sizes.

public void onWindowFocusChanged() {

       RelativeLayout.LayoutParams lineChartParams = (RelativeLayout.LayoutParams) mChartLayout.getLayoutParams();
       lineChartParams.height = height * 2 / 3;
       lineChartParams.width = width * 5 / 6;
       mChartLayout.setLayoutParams(lineChartParams);
       RelativeLayout.LayoutParams frameLayoutParams = (RelativeLayout.LayoutParams) frameLayout.getLayoutParams();
       frameLayoutParams.height = height / 3;
       frameLayoutParams.width = width * 5 / 6;
       frameLayout.setLayoutParams(frameLayoutParams);
   
}

onWindowFocusChanged method is called in onCreate method. Here we are first receiving current layout parameters and then setting new layout parameters.

Step 4: Developing each section

  1. Graph

The graph needs to be customized concerning following requirements

  • Dual y axis, one dedicated to CH2 and another to analog input selected.
  • Black background
  • Grid lines
  • Scaling
  • Initial scale for x and y axis.

To achieve this a chartInit method is created which initializes the graph as per required. It is called in onCreate method.

2. Side Panel

It is a simple layout consisting of image buttons and text views. It is used to replace fragments in Lower Panel. To achieve this, image buttons and textviews were added to the layout and image buttons weight is set to 2. Later onClick listeners were added to both image buttons and textviews.

3. Lower Panel

The lower panel is frame layout which accommodates different fragments (one at a time). To achieve these different fragments are created that are ChannelsParametersFragment, TimebaseTriggerFragment, DataAnalysisFragment and XYPlotFragment. In ChannelsParametersFragment, TimebaseTriggerFragment and XYPlotFragment fragments, constraint views are used whereas in TimebaseTriggerFragment table layout is used. Each fragment allows the user to access different controls and features.

The Final Layout

The above is the GIF of the Oscilloscope UI.

This covers various steps for developing Oscilloscope UI in PSLab Android App.

Resources

Continue ReadingDeveloping Oscilloscope UI in PSLab Android App

Performing Fourier Transforms in the PSLab Android App

Oscilloscope is one of the key features of PSLab. When periodic signals such as sine waves are read by the Oscilloscope, curve fitting functions are used to construct a curve that has the best fit to a series of data points. In PSLab, the sine curve fitting involves the Fourier Transforms. FFT (short for “Fast Fourier Transform”) is nothing more than a curve-fit of sines and cosines to some given data. In order to understand the implementation of Fourier Transforms in PSLab Android App let’s first have a look at the Fourier transform equations.

The first equation here is the Forward Fourier transform. It converts the function of time (t) into the function of frequency (ω).
The second equation is Inverse Fourier transform. It does the opposite to first equation ie. it converts the function of frequency (ω) into the function of time (t).

So, first I will answer what is transform?
It is the mapping between two different sets of domains. In this case, the information is changed from the time domain to frequency domain. The data in these domains look different but represent the same information. A transform will get you from one representation to another.

Fourier transforms converts between the time domain f(t) and the frequency domain F(ω).
Performing Fourier Transforms in Android
Let’s perform Forward Fourier transform. This means it converts the function of time (t) into the function of frequency (ω). We will use Apache Maths Commons to perform Fourier transforms. Since we have finite input data set we will calculate Discrete Fourier Transform (DFT).
The algorithm which is being used here is Fast Fourier Transform (FFT) which is the best algorithm to calculate Fourier transforms.

FastFourierTransformer fastFourierTransformer = 
      new FastFourierTransformer(DftNormalization.STANDARD);

Here we are creating an instance of FastFourierTransformer which passed STANDARD normalization convention to its constructor. Normalization other than STANDARD is UNITARY.
Complex complex[] = fastFourierTransformer.transform(input, TransformType.FORWARD);

Here, input array and TransformType. FORWARD is also passed to transform method. Input is an array of data representing time whereas TransformType. FORWARD defines the type of Fourier transform that should be performed ie. forward or inverse.

Complex complex[] = fastFourierTransformer.transform(input, TransformType.FORWARD);

The output will be an array of complex number. Each data point will be represented like the following graph in the complex plane.

Suppose the amplitude of the data point given in above graph is 1 and phase shift is 45°. So, solving this we will get 2/√2 as both real and imaginary components. Therefore, F (ω) would be 1/√2 + (1/√2) i.
Dealing with Complex numbers in Java
A complex number has both real and imaginary part. Using Apache Maths Commons we can use Complex to represent a complex number.

Complex number = new Complex(1,2);
System.out.println(number);
Output
1.0 + 2.0i

We can also get real and imaginary parts separately of Complex numbers.

System.out.println(number.getReal());
System.out.println(number.getImaginary());
Output
1.0
2.0

The array of the Complex numbers can be implemented like the following

Complex[] number;
Complex c1 = new Complex(1, 2);
Complex c2 = new Complex(3, 4);
number = new Complex[]{c1, c2};
System.out.println(Arrays.toString(number));
System.out.println(number[1]);
Output

[(1.0, 2.0), (3.0, 4.0)]
(3.0, 4.0)

Resources

Continue ReadingPerforming Fourier Transforms in the PSLab Android App

Curve-Fitting in the PSLab Android App

One of the key features of PSLab is the Oscilloscope. An oscilloscope allows observation of temporal variations in electrical signals. Its main purpose is to record the input voltage level at highly precise intervals and display the acquired data as a plot. This conveys information about the signal such as the amplitude of fluctuations, periodicity, and the level of noise in the signal. The Oscilloscope helps us to observe varying the waveform of electronic signals, it is obvious it measures a series of data points that need to be plotted on the graph of the instantaneous signal voltage as a function of time.

When periodic signals such as sine waves or square waves are read by the Oscilloscope, curve fitting functions are used to construct a curve that has the best fit to a series of data points. Curve fitting is also used on data points generated by sensors, for example, a damped sine fit is used to study the damping of the simple pendulums. The curve fitting functions are already written in Python using libraries like numpy and scipy. analyticsClass.py provides almost all the curve fitting functions used in PSLab. For the Android, implementation we need to provide the same functionality in Java.

More about Curve-fitting

Technically speaking, Curve-fitting is the process of constructing a curve or mathematical function, that has the best fit to a series of data points, possibly subject to constraints.

Let’s understand it with an example.

Exponential Fit

The dots in the above image represent data points and the line represents the best curve fit.

In the image, data points are been plotted on the graph. An exponential fit to the given series of data can be used as an aid for data visualization. There can be many types of curve fits like sine fit, polynomial fit, exponential fit, damped sine fit, square fit etc.

Steps to convert the Python code into Java code.

1. Decoding the code

At first, we need to identify and understand the relevant code that exists in the PSLab Python project. The following is the Python code for exponential fit.

import numpy as np
def func(self, x, a, b, c):
return a * np.exp(-x/ b) + c

This is the model function. It takes the independent variable ie. x as the first argument and the parameters to fit as separate remaining arguments.

def fit_exp(self, t, v):    
    from scipy.optimize import curve_fit
    size = len(t)
    v80 = v[0] * 0.8
    for k in range(size - 1):
        if v[k] < v80:
            rc = t[k] / .223
            break
pg = [v[0], rc, 0]

Here, we are calculating the initial guess for the parameters.

po, err = curve_fit(self.func, t, v, pg) 

curve_fit function is called here where model function func, voltage array v, time array t and a list of initial guess parameters pg are the parameters.

if abs(err[0][0]) > 0.1:
    return None, None
vf = po[0] * np.exp(-t/po[1]) + po[2]
return po, vf

2. Curve-fitting in Java

The next step is to implement the functionalities in Java. The following is the code of exponential fit written in JAVA using Apache maths commons API.

ParametricUnivariateFunction exponentialParametricUnivariateFunction = new ParametricUnivariateFunction() {
        @Override
        public double value(double x, double... parameters) {
            double a = parameters[0];
            double b = parameters[1];
            double c = parameters[2];
            return a * exp(-x / b) + c;
        }
        @Override
        public double[] gradient(double x, double... parameters) {
            double a = parameters[0];
            double b = parameters[1];
            double c = parameters[2];
            return new double[]{
                    exp(-x / b),
                    (a * exp(-x / b) * x) / (b * b),
                    1
            };                                                     
        }
    };

ParametricUnivariteFunction is an interface representing a real function which depends on an independent variable and some extra parameters. It is the model function that we used in Python.

It has two methods that are value and gradient. Value takes an independent variable and some parameters and returns the function value.

Gradient returns the double array of partial derivatives of the function with respect to each parameter (not independent parameter x).

 public ArrayList<double[]> fitExponential(double time[], double voltage[]) {
        double size = time.length;
        double v80 = voltage[0] * 0.8;
        double rc = 0;
        double[] vf = new double[time.length]; 
        for (int k = 0; k < size - 1; k++) {
            if (voltage[k] < v80) {
                rc = time[k] / .223;
                break;
          	}
        }
        double[] initialGuess = new double[]{voltage[0], rc, 0};
        //initialize the optimizer and curve fitter.
       LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer()

LevenbergMarquardtOptimizer solves a least square problem using Levenberg Marquardt algorithm (LMA).

CurveFitter fitter = new CurveFitter(optimizer);

LevenbergMarquardtOptimizer is used by CurveFitter for the curve fitting.

 for (int i = 0; i < time.length; i++)
            fitter.addObservedPoint(time[i], voltage[i]);

addObservedPoint adds data points to the CurveFitter instance.

double[] result = fitter.fit(exponentialParametricUnivariateFunction,initialGuess);

fit method with ParametricUnivariteFunction and guess parameters as parameters return an array of fitted parameters.

  for (int i = 0; i < time.length; i++)
            vf[i] = result[0] * exp(-time[i] / result[1]) + result[2];
        return new ArrayList<double[]>(Arrays.asList(result, vf));    }

Additional Notes

Exponential fit implementation in both JAVA and Python uses Levenberg-Marquardt Algorithm. The Levenberg-Marquardt algorithm solves nonlinear least squares problems.

A detailed account about Levenberg-Marquardt Algorithm and least square problem is available here.

Least squares is a standard approach in regression analysis to the approximate solution of overdetermined systems. It is very useful in curve fitting. Let’s understand it with an example.

In the above graph blue dots represent data points, and L1 and L2 represent lines of fitted value by the models. So, what least square does is, it calculates the sum of the squares of distances between the actual values and the fitted values, and the one with least value is the line of best fit. Here, it’s clear L1 is the winner….

Resources

Continue ReadingCurve-Fitting in the PSLab Android App

Constructing and working with Polynomials in the PSLab Android App

PSLab is a device that allows the user to perform a range of science and engineering experiments. PSLab has existing communication library (PSLab Desktop) written in Python. Since we are developing an Android application to operate PSLab, the initial step was to port Python code to JAVA. In PSLab Android application we are using version 3.6.1 of Apache Maths Commons.

NumPy is the package for scientific computing with Python. Polynomials in NumPy can be created using numpy.poly1d. Since some of the files in PSLab Desktop use polynomials, it was important to find a package in JAVA that provides features equivalent to NumPy. Apache Maths Commons fulfilled our needs. It is a Mathematics Library available in JAVA, that provides the means to construct polynomials and perform a range of operations on them. A detailed documentation of the library is available here.

import numpy

p = numpy.poly1d([1, 2, 3])

print(numpy.poly1d(p))

q = p(0.5)

print q

Output:  

1 x2 + 2 x + 3

4.25

Poly1d() function converts a list into polynomials. The first element of the list is the coefficient of the highest degree of the polynomial while the last element is the coefficient of lowest degree of the polynomial. While p(0.5) evaluates polynomial at x = 0.5. 

Now let’s construct polynomials in JAVA using Apache Maths Commons

public class poly {

public static void main(String[] args){

PolynomialFunction p = new PolynomialFunction(new double[]{3, 2, 1});

System.out.println(p);

System.out.println(p.value(0.5));

    }
}

Output:  

3 + 2 x + x^2

4.25

Polynomial Function converts the double array into polynomials. The first element of the array is the coefficient of the lowest degree of the polynomial while the last element is the coefficient of the highest degree of the polynomial. p.value (0.5) evaluates polynomial at x = 0.5.

Other things we can do

  • Find the degree of the polynomial.

Continuing with the above example where polynomial was 3 + 2 x + x^2. p.degree() gives 2 as output which is the degree of the given polynomial.

  • Get the coefficients of the polynomial

p.getCoefficients() returns a double array of the coefficients of the given polynomial. In the above case [3.0, 2.0, 1.0] will be returned.

  • Find derivatives of the polynomial

p.derivative() returns 2 + 2 x which is derivative of polynomial 3 + 2 x + x^2.

  • Add, subtract and multiply two polynomials.

We can add, subtract and multiply 2 polynomials. For example p.multiply(new  Polynomial Function(new double[]{1,2})) returns 3 + 8 x + 5 x^2 + 2 x^3 which is  the product of 3 + 2 x + x^2 and 1 + 2 x

Where are they are used in PSLab?

Polynomials are used in AnalogInputSource.java  to convert raw ADC codes (0=0V , 1023=3.3V ) to voltage values. 

  • calPoly10 = new PolynomialFunction(new double[]{0., 3.3 / 1023, 0.});
  • calPoly12 = new PolynomialFunction(new double[]{0., 3.3 / 4095, 0.});

    Polynomials are also used in DACChannel.java to convert DAC codes to voltage values and vice versa.

  • VToCode = new PolynomialFunction(new double[]{-4095. * intercept / slope, 4095. / slope});                                                    
  • CodeToV = new PolynomialFunction(new double[]{intercept, slope / 4095.});

Continue ReadingConstructing and working with Polynomials in the PSLab Android App