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 Reading

Creating Multiple Device Compatible Layouts in PSLab Android

The developer’s goal is that PSLab Android App as an app should run smoothly on all the variety of Android devices out in the market. There are two aspects of it – the app should be able to support maximum number of Android versions possible which is related to the core software part and the other being the app should be able to generate the same user experience on all sizes of screens. This post focuses on the later.

There are a whole range of android devices available in the market right from 4 inch mobile phones to 12 inch tablets and the range in the screen sizes is quite large. So, the challenge in front of app designers is to make the app compatible with the maximum  number of devices without doing any specific tweaks related to a particular resolution range. Android has its mechanism of scaling the app as per the screen size and it does a good job almost all the time, however, still there are cases where android fails to scale up or scale down the app leading to distorted layout of the app.

This blog discusses some of the tricks that needs to be kept in mind while designing layouts that work independent of screen sizes.

Avoid using absolute dimensions

It is one of the most common things to keep in mind before starting any UI design. Use of absolute dimensions like px, inch etc. must be avoided every time as they are fixed in size and don’t scale up or scale down while screen sizes are changed. Instead relative dimensions like dp should be used which depend on the resolution and scale up or scale down. ( It’s a fair assumption that bigger screens will have better resolution compared to the smaller ones although exceptions do exist) .

Ensure the use of correct layout/View group

Since, android provides a variety of layouts like Linearlayout, Constrainedlayout, Relativelayout, Tablelayout and view groups like ScrollView, RecyclerView, ListView etc. it is often confusing to know which layout/viewgroup should be used. The following list gives a rough idea of when to use a particular layout or view group.

  • Linearlayout – Mostly used for simple designs when the elements are stacked in ordered horizontal/vertical fashion and it needs explicit declaration of orientation.
  • Relativelayout – Mostly used when the elements need to defined relative to the parent or the neighbouring elements. Since, the elements are relative, there is no need to define the orientation.
  • Constraintlayout – It has all the features of Relativelayout and in addition a feature of adding constraints to the child elements or neighbouring elements.
  • Tablelayout – Tablelayout is helpful to when all the views/widgets are arranged in an ordered fashion.

All the above layouts can be used interchangeably most of the times, however, certain cases make some more favourable than others like when than views/ widgets are not present in an organised manner, it is better to stick to Linearlayout or Relativelayout.

  • ListView – Used when the views/ widgets in a screen are repeated, so using a listview ensures that the volume of the code is reduced and all the repetitive views are identical in nature.
  • RecyclerView – More of an improved version of ListView. It is recommended to use this view over ListView. Additionally this view group supports features like swipe to refresh.
  • ScrollView – Used when the UI screen cannot fit within the given screen space. ScrollView supports one direct child layout. So, to implement a scrollview, all the views must be under a particular layout and then masked by scrollview.

Choosing the correct layout or view group would help to create a better UI.

Use of layout_weight

Ensuring the layout width assigned in XML file covers the entire width on the screen. For ensuring this, one possible solution is to use layout_weight instead of layout_width.

Example –

<TextView
   android:id="@+id/tv_control_read9"
   android:layout_width="0dp"
   android:layout_weight="1"
   android:layout_height="30dp"
   android:layout_marginTop="10dp"
/>

 

In order to use layout_weight, layout_width must be set to 0 else it would interfere with the width and as layout_width is a compulsory parameter it cannot be omitted. Layout weight can be any number and the space is allocated to each view in proportion to the weights assigned. Since it does not involve numerical dimensions, the distribution would be uniform for all types of screens. The result is clearly evident here. The same UI in different screen sizes is displayed below.

blog_post_8_2

Fig: Screenshot taken on a 6” phone and on a 4” phone. Although the screen area of 4” phone is 44% that of the 6” phone, the UIs are identically the same.

Create different layout directories for different resolutions

  • Creating different layouts for different screen sizes ensures that the limitations of smaller screen sizes are taken care of and the advantages offered by bigger screen sizes are put to the best use.
  • The Android documentation here mentions the conventions to be followed while designing.
  • Although over the years, android has become better at auto-adjusting layouts for different screen sizes. However, if the no. of views and widgets are high, auto-adjusting does not work well as in case of PSLab and it is better to create different sets of layouts.
  • As evident from the picture of the 8” tablet, although the auto-adjusted layout is manageable, the layout looks stretched and does not utilize the entire screen space, so it a better UI can be made by creating a dedicated layout directory for bigger screens.

Additional resources

 

Continue Reading

Using Sensors with PSLab Android App

The PSLab Android App as of now supports quite a few sensors. Sensors are an essential part of many science experiments and therefore PSLab has a feature to support plug & play sensors. The list of sensors supported by PSLab can be found here.

  • AD7718 – 24-bit 10-channel Low voltage Low power Sigma Delta ADC
  • AD9833 – Low Power Programmable Waveform generator
  • ADS1115 – Low Power 16 bit ADC
  • BH1750 – Light Intensity sensor
  • BMP180 – Digital Pressure Sensor
  • HMC5883L – 3-axis digital magnetometer
  • MF522 – RFID Reader
  • MLX90614 – Infrared thermometer
  • MPU6050 – Accelerometer & gyroscope
  • MPU925x – Accelerometer & gyroscope
  • SHT21 – Humidity sensor
  • SSD1306 – Control for LED matrix
  • Sx1276 – Low Power Long range Transceiver
  • TSL2561 – Digital Luminosity Sensor

All the sensors except Sx1276 communicate using the I2C protocol whereas the Sx1276 uses the SPI protocol for communication. There is a dedicated set of ports on the PSLab board for the communication under the label I2C with the ports named 3.3V, GND, SCL & SDA.

blog_post_7_1

Fig; PSLab board sketch

Any I2C sensor has ports named 3.3V/VCC, GND, SCL, SDA at least along with some other ports in some sensors. The connections are as follows:

  1. 3.3V on PSLab – 3.3V/VCC on sensor
  2. GND on PSLab – GND on sensor
  3. SCL on PSLab – SCL on sensor
  4. SDA on PSLab – SDA on sensor

The diagram here shows the connections

For using the sensors with the Android App, there is a dedicated I2C library written in communication in Java for the communication. Each sensor has its own specific set of functionalities and therefore has its own library file. However, all these sensors share some common features like each one of them has a getRaw method which fetches the raw sensor data. For getting the data from a sensor, the sensor is initially connected to the PSLab board.

The following piece of code is responsible for detecting any devices that are connected to the PSLab board through the I2C bus. Each sensor has it’s own unique address and can be identified using it. So, the AutoScan function returns the addresses of all the connected sensors and the sensors can be uniquely identified using those addresses.

public ArrayList<Integer> scan(Integer frequency) throws IOException {
	if (frequency == null) frequency = 100000;
	config(frequency);
	ArrayList<Integer> addresses = new ArrayList<>();
	for (int i = 0; i < 128; i++) {
		int x = start(i, 0);
		if ((x & 1) == 0) {
			addresses.add(i);
		}
		stop();
	}
	return addresses;
}

 

As per the addresses fetched, the sensor library corresponding to that particular sensor can be imported and the getRaw method can be called. The getRaw method will return the raw sensor data. For example here is the getRaw method of ADS1115.

public int[] getRaw() throws IOException, InterruptedException {
	String chan = typeSelection.get(channel);
	if (channel.contains("UNI"))
		return new int[]{(int) readADCSingleEnded(Integer.parseInt(chan))};
	else if (channel.contains("DIF"))
		return new int[]{readADCDifferential(chan)};
	return new int[0];
}

Here the raw data is returned in the form of voltages in mV.

Similarly, the other sensors return some values like luminosity sensor TSL2561 returns values of luminosity in Lux, the accelerometer & gyroscope MPU6050 returns the angles of the 3-axes.

In order to initiate the process of getting raw data from the sensor in Sensor Activity, the object for the sensor is created and the method of getRaw is called. The following is the implementation for ADS1115. The rest of the sensors also have an implementation similar to this. There are try-catch statements in the code to handle some of the exceptions thrown during process of method calls.

ADS1115 ADS1115 = null;
try {
	ADS1115 = new ADS1115(i2c);
} catch (IOException | InterruptedException e) {
	e.printStackTrace();
}

int[] dataADS1115 = null;
String datadispADS1115 = null;
try {
	if (ADS1115 != null) {
		dataADS1115 = ADS1115.getRaw();
	}
} catch (IOException | InterruptedException e) {
	e.printStackTrace();
}

if (dataADS1115 != null) {
	for(int i = 0; i < dataADS1115.length; i++)
		datadispADS1115 += String.valueOf(dataADS1115[i]);
	}

tvSensorGetRaw.setText(datadispADS1115);

 

Additional Resources

  1. Sensor implementation in PSLab Python repository – https://github.com/fossasia/pslab-python/tree/development/PSL/SENSORS
  2. Using the sensors with Arduino in case you have worked with Arduino before – The basic connections are same as PSLab http://www.instructables.com/id/Arduino-MPU-6050-Getting-It-to-Work/

Continue Reading

Creating Custom Components in the PSLab Android App

PSLab Android App supports a lot of features and each of these features need components & views for their implementation. A typical UI of PSLab is shown in the figure below. Considering the number of views & components used in the figure, implementation of each view & component separately would lead to a huge volume of repetitive and inefficient code. As it is evident that the EditText and two buttons beside it keep repeating a lot, it is wiser to create a single custom component consisting of an EditText and two buttons. This not only leads to efficient code but also results in a drastic reduction of the volume of code.

Android has a feature which allows creating components. For almost all the cases, the pre-defined views in Android serve our purpose of creating the UIs. However, sometimes there is a need to create custom components to reduce code volume and improve quality. Custom components are used when a particular set of component needed by us is not present in the Android view collection or when a pattern of components is frequently repeated or when we need to reduce the code complexity.

The above set can be replaced by defining a custom component which includes an edittext and two buttons and then treating it like just any other component. To get started with creating a custom component, the steps are the following:

Create a layout for the custom component to be designed

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="horizontal" android:layout_width="match_parent"
   android:layout_height="match_parent">

   <Button
       android:id="@+id/button_control_plus"
       android:layout_width="0dp"
       android:layout_weight="0.5"
       android:layout_height="20dp"
       android:background="@drawable/button_minus" />

   <EditText
       android:id="@+id/edittext_control"
       android:layout_width="0dp"
       android:layout_weight="2"
       android:layout_height="24dp"
       android:layout_marginTop="@dimen/control_margin_small"
       android:inputType="numberDecimal"
       android:padding="@dimen/control_edittext_padding"
       android:background="@drawable/control_edittext" />

   <Button
       android:id="@+id/button_control_minus"
       android:layout_width="0dp"
       android:layout_weight="0.5"
       android:layout_height="20dp"
       android:background="@drawable/button_plus" />
</LinearLayout>

The layout file edittext_control.xml is created with three views and each one of them has been assigned an ID along with all the other relevant parameters.

Incorporate the newly created custom layout in the Activity/Fragment layout file

<org.fossasia.pslab.others.Edittextwidget
       android:id="@+id/etwidget_control_advanced1"
       android:layout_height="wrap_content"
       android:layout_width="0dp"
       android:layout_weight="2"
       android:layout_marginLeft="@dimen/control_margin_small"
       android:layout_marginStart="@dimen/control_margin_small"
/>

The custom layout can be added the activity/fragment layout just like any other view and can be assigned properties similarly.

Create the activity file for the custom layout

public class Edittextwidget extends LinearLayout{

   private EditText editText;
   private Button button1;
   private Button button2;
   private double leastCount;
   private double maxima;
   private double minima;

 
   public Edittextwidget(Context context, AttributeSet attrs, int defStyle) {
       super(context, attrs, defStyle);
       applyAttrs(attrs);
   }

   public Edittextwidget(Context context, AttributeSet attrs) {
       super(context, attrs);
       applyAttrs(attrs);
   }

   public Edittextwidget(Context context) {
       super(context);
   }

  public void init(Context context, final double leastCount, final double minima, final double maxima) {
       View.inflate(context, R.layout.edittext_control, this);
       editText = (EditText) findViewById(R.id.edittext_control);
       button1 = (Button) findViewById(R.id.button_control_plus);
       button2 = (Button) findViewById(R.id.button_control_minus);

       button1.setOnClickListener(new OnClickListener() {
           @Override
           public void onClick(View v) {
               Double data = Double.valueOf(editText.getText().toString());
               data = data - leastCount;
               data = data > maxima ? maxima : data;
               data = data < minima ? minima : data;
               editText.setText(String.valueOf(data));
           }
       });

       button2.setOnClickListener(new OnClickListener() {
           @Override
           public void onClick(View v) {
               Double data = Double.valueOf(editText.getText().toString());
               data = data + leastCount;
               data = data > maxima ? maxima : data;
               data = data < minima ? minima : data;
               editText.setText(String.valueOf(data));
           }
       });
   }

   private void applyAttrs(AttributeSet attrs) {
       TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.Edittextwidget);
       final int N = a.getIndexCount();
       for (int i = 0; i < N; ++i) {
           int attr = a.getIndex(i);
           switch (attr) {
               case R.styleable.Edittextwidget_leastcount:
                   this.leastCount = a.getFloat(attr, 1.0f);
                   break;
               case R.styleable.Edittextwidget_maxima:
                   this.maxima = a.getFloat(attr, 1.0f);
                   break;
               case R.styleable.Edittextwidget_minima:
                   this.minima = a.getFloat(attr, 1.0f);
           }
       }
       a.recycle();
   }
}

In the activity file Editextwidget.java, the views of the custom layout are defined and functionalities are assigned to them. For example, here there are two buttons which work as increment/decrement buttons and an edittext which takes numeric input. The buttons are initiated just like the way they are done in other activity/fragment using OnClickListener.

Define the attributes for the custom layout

<declare-styleable name="Edittextwidget">
     <attr name="leastcount" format="float" />
     <attr name="maxima" format="float" />
     <attr name="minima" format="float" />
</declare-styleable>

The attributes for the custom layout are defined in the attrs.xml file. Each attribute is assigned a name and a format which can be int, float, double, string etc.

Finally call the methods of the custom layout from the desired activity/fragment

Edittextwidget etwidgetControlAdvanced1 = (Edittextwidget)view.findViewById(R.id.etwidget_control_advanced1);

etwidgetControlAdvanced1.init(getContext(), 1.0, 10.0, 5000.0);

The init method of Edittextwidget.java is called while passing the relevant parameters like context, least count, maxima and minima.

Additional Resources on Custom Components

  1. Official Android Guide on Custom components – https://developer.android.com/guide/topics/ui/custom-components.html
  2. Simple example of creating a custom component to get started – https://www.tutorialspoint.com/android/android_custom_components.htm
Continue Reading

Trigger Controls in Oscilloscope in PSLab

PSLab Desktop App has a feature of oscilloscope. Modern day oscilloscopes found in laboratories support a lot of advanced features and addition of trigger controls in oscilloscope was one such attempt in adding an advanced feature in the oscilloscope. As the current implementation of trigger is not robust enough, this feature would help in better stabilisation of waveforms.

Captured waveforms often face the problem of distortion and trigger helps to solve this problem. Trigger in oscilloscope is an essential feature for signal characterisation.  as it synchronises the horizontal sweep of the oscilloscope to the proper point of the signal. The trigger control enables users to stabilise repetitive waveforms as well as capture single-shot waveforms. By repeatedly displaying similar portion of the input signal, the trigger makes repetitive waveform look static. In order to visualise how an oscilloscope looks with or without a trigger see the following figures below.

blog_post_5_1

blog_post_5_2

Fig 1: (a) Without trigger  (b) With trigger

The Fig:1(a) is the actual waveform received by the oscilloscope and it can be easily noticed that interpreting it is confusing due to the overlapping of multiple waveforms together. So, in Fig:1(b) the trigger control stabilises the waveforms and captures just one waveform.

In general the commonly used trigger modes in laboratory oscilloscopes are:-

  • Auto – This trigger mode allows the oscilloscope to acquire a waveform even when it does not detect a trigger condition. If no trigger condition occurs while the oscilloscope waits for a specific period (as determined by the time-base setting), it will force itself to trigger.
  • Normal – The Normal mode allows the oscilloscope to acquire a waveform only when it is triggered. If no trigger occurs, the oscilloscope will not acquire a new waveform, and the previous waveform, if any, will remain on the display.
  • Single – The Single mode allows the oscilloscope to acquire one waveform each time you press the RUN button, and the trigger condition is detected.
  • Scan – The Scan mode continuously sweeps waveform from left to right.

Implementing Trigger function in PSLab

PSLab has a built in basic functionality of trigger control in the configure_trigger method in sciencelab.py. The method gets called when trigger is enabled in the GUI. The trigger is activated when the incoming wave reaches a certain voltage threshold and the PSLab also provides an option of either selecting the rising or falling edge for trigger. Trigger is especially useful in experiments handling waves like sine waves, square wave etc. where trigger helps to get a clear picture.

In order to initiate trigger in the PSLab desktop app, the configure_trigger method in sciencelab.py is called. The configure_trigger method takes some parameters for input but they are optional. If values are not specified the default values are assumed.

def configure_trigger(self, chan, name, voltage, resolution=10, **kwargs):
        
  prescaler = kwargs.get('prescaler', 0)
        try:
            self.H.__sendByte__(CP.ADC)
            self.H.__sendByte__(CP.CONFIGURE_TRIGGER)
            self.H.__sendByte__(
                (prescaler << 4) | (1 << chan))  
            if resolution == 12:
                level = self.analogInputSources[name].voltToCode12(voltage)
                level = np.clip(level, 0, 4095)
            else:
                level = self.analogInputSources[name].voltToCode10(voltage)
                level = np.clip(level, 0, 1023)

            if level > (2 ** resolution - 1):
                level = (2 ** resolution - 1)
            elif level < 0:
                level = 0

            self.H.__sendInt__(int(level))  # Trigger
            self.H.__get_ack__()
        
        except Exception as ex:
  	    self.raiseException(ex, "Communication Error , Function : " + inspect.currentframe().f_code.co_name)

The method takes the following parameters in the method call

  • chan – Channel . 0, 1,2,3. corresponding to the channels being recorded by the capture routine(not the analog inputs).
  • name – The name of the channel. ‘CH1’… ‘V+’.
  • voltage – The voltage level that should trigger the capture sequence(in Volts).

The similar feature will also be used in oscilloscope in the Android app with the code corresponding to this method  in ScienceLab written in Java.

Additional Resources

  1. Read more about Trigger here – http://www.radio-electronics.com/info/t_and_m/oscilloscope/oscilloscope-trigger.php
  2. Learn more about trigger modes in oscilloscopes – https://www.picotech.com/library/oscilloscopes/advanced-digital-triggers
  3. PSLab Python repository to know the underlying code – https://github.com/fossasia/pslab-python

 

Continue Reading

Establishing Communication between PSLab and an Android Device using the USB Host API

In this post, we are going to learn how to establish communication between the PSLab USB device and a connected Android device. We will implement our own custom read & write methods by using functions provided by USB Host API of Android SDK.

At first we need to enable communication to PSLab device by connecting it to Android Phone by an On-The Go (OTG) cable. We are communicating via the USB Host API of Android.

About Android USB

Android supports USB peripherals through two modes:

  • Android Accessory: In this mode external USB device acts as host.
  • Android Host: In this mode Android Device acts as host and powers the external device.
Source : Android Developers Docs

Obtaining Permission to access USB device

When a USB device is connected to Android device, you need to obtain permissions to access the USB device. You have two ways, I have used intent-filter method to obtain permission in PSLab project, but you can also use the approach to implement a broadcast receiver.

Option 1:

Add a intent filter in the activity which would handle that connected USB device. This is an implicit way to obtain permission.

<activity ...>
...
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
    </intent-filter>
    <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
        android:resource="@xml/device_filter" />
</activity>

And add device details like your vendor ID and product ID in device_filter.xml

<resources>

    <usb-device vendor-id="1240" product-id="223" />

</resources>

Now when you connect your USB device, permission dialog like below would pop up:

Option 2:

  • If you want to obtain permission explicitly, first create broadcastreceiver which would be broadcasted which you call requestPermission().

    private static final String ACTION_USB_PERMISSION =
        "com.android.example.USB_PERMISSION";
    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
    
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if(device != null){
                       }
                    }
                    else {
                        Log.d(TAG, "permission denied for device " + device);
                    }
                }
            }
        }
    };

    Register this broadcastreceiver in your onCreate method of your activity.

    UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
    private static final String ACTION_USB_PERMISSION =
        "com.android.example.USB_PERMISSION";
    ...
    mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
    IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
    registerReceiver(mUsbReceiver, filter);

    And call requestPermission method to show a dialog for permission

    UsbDevice device;
    ...
    mUsbManager.requestPermission(device, mPermissionIntent);

    Now when you open your App permission dialog like shown below would pop up:

Obtain Read & Write Endpoints

Now that you have permission to communicate with a USB device connected. Next step is to obtain read and write Endpoints to read and write to USB device by using bulkTransfer() function.

The definition of bulkTransfer() methods is

int bulkTransfer (UsbEndpoint endpoint, 
                byte[] buffer, 
                int length, 
                int timeout)

endpoint : Usb Endpoint ( the endpoint for this transaction )

buffer : byte ( buffer for data to send or receive )

length : int ( length of data to send/receive )

timeout : int ( in milliseconds, 0 is infinite )

For code to obtain read, write Endpoint through Data Interface of USB device. Open() method of PSLab can be referenced.

There are two ways for communication :

  • Synchronous
  • Asynchronous

In PSLab, we use synchronous communication using bulkTransfer() method. Create a USB device connection object

mConnection = mUsbManager.openDevice(mUsbDevice);

As bulkTransfer methods are exposed by USB connection object. Using these you can implement your read & write functions to meet your project’s requirements. Or use bulkTransfer() directly to read & write data.

For example:

mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, bytesToRead, timeoutMillis)

So this covers the required for obtaining permission to access USB device and basics of how you can read data from and write data to USB device.

Also if this project interest you, feel free to contribute or raise any issue. PSLab-Android.

Resources

Continue Reading

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 Reading

Android App Debugging over WiFi for PSLab

Why do WiFi debugging when you have USB cable? PSLab is an Open Source Hardware Device which provides a lot of functionality that is required to perform a general experiment, but like many other devices it  only provides an Android mini usb port. This means developers can’t connect another USB cable as the  mini port is already busy powering and communicating with the USB device that is connected.

How can developers debug our Android App over WiFi? Please follow these steps:

  • Connect your Android Device to PC through USB cable and make sure USB-Debugging is enabled in Developers Option.
  • Turn on Wifi of Android Device if its off and make sure its connected to router because that’s going to act as bridge between your Android device and PC for communication.
  • Open your terminal and type adb tcpip 5555
  • Now see the IP of your Android Device by About Phone -> Status -> IP or adb shell netcfg
  • Then type adb connect <DEVICE_IP_ADDRESS>:5555
  • Almost Done! Disconnect USB and start with wireless debugging.

Now you would see your device coming up in the prompt when clicked run from Android Studio. All the logs can be seen in Android Monitor. Similarly as you see during debugging through USB cable.

To get in touch with us or ask any question about the project, just drop a message at https://gitter.im/fossasia/pslab

Also if this project interest you, feel free to contribute or raise any issue. PSLab-Android.

Continue Reading

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 Reading
Close Menu