Calibrating the PSLab’s Analog Features for Maximum Accuracy

The hardware design of the PSLab aims to achieve the maximum possible performance from a very conservative bill of materials. There are several analog components such as Op-amps, voltage dividers, and level-shifters involved in input signal processing that have inherent offsets and slopes that must be corrected in order get the best results. Similarly, some analog output signals from the PSLab are also modified by buffers, amplifiers, and level shifting circuits.

One way to improve the initial accuracy is to choose high performance analog components that are factory calibrated , and do not require any additional correction to achieve error margins that are less than the least count of the PSLab’s measurement capabilities. However, such components such as laser trimmed resistor pairs, and low-offset Op-Amps are quite expensive, and we must instead use software based correction methods to achieve similar performance from affordable parts.

Identifying a suitable calibrator for analog signals

In order to calibrate a device, we must first own a similar device whose measurements we can trust, and which has a finer resolution that the PSLab itself. Calibration is a one-time task that will quantify and store the gain and offset errors, and these errors are not expected to behave very differently unless a significant change in temperature, or mechanical stress is experienced.

Such a device may be as expensive as 24-bit, research-grade multimeters which generally cost upwards of $500 , or can be inexpensive analog to digital convertors that might require some expertise to extract data from them, but can still be used for calibration.

Fortunately, we have been able to identify a cheaply available device that puts the calibration process within the reach and capabilities of the end user. The ADS1115 16-bit ADC is a 4-channel, 0-3.3V ADC that can be interfaced via I2C. Typical initial accuracy of the internal voltage reference 0.01% and data rates higher than 500SPS are possible. It is cost effective, and is available in convenient module formats that can be directly plugged into the PSLab itself. It can be purchased through various vendors ( A , B , C )

Therefore, it appears to be most suited to calibrate individual PSLab devices.

Basic requirements for the calibration process

The process to calibrate the analog inputs and outputs involves looping them externally , and monitoring the actual values via the external calibrator.

We’re killing two birds with one stone by calibrating inputs and outputs in tandem, and it makes for a faster calibration process. The complete calibration process for  Digital to Analog converter outputs has enough complexity to warrant a separate blog post.

Let’s take an example; PV1 ( an analog output that can be set between -5V and +5V) can be connected to CH1 (An analog input which can read voltage values between -16 and +16 Volts) with a small segment of wire, and various voltage values can be set on PV1, and read back by CH1 . At the same time, the external calibration utility will also monitor this voltage, and store the error in PV1 (Set Voltage – Actual Voltage) as well as the error in CH1 ( Read Voltage – Actual Voltage ) .

In a similar manner , PV2 can be connected to CH2, and the second channel of the ADS1115 calibrator can be used to monitor the real value, and so on .

Deviations of various analog input channels and their different voltage ranges from the actual values. As is evident from the graph, errors can be as much as 40mV in a full scale range of +/-16,000mV . But since these errors are quite repeatable, we can apply a calibration polynomial to correct these.

 

Integral Non-linearity of the ADC

In addition to the overall slope and offset, you have probably observed in the previous image, a sawtooth pattern with an amplitude as small as the least count of the analog inputs superimposed on them. This error arises from the integral non-linearity (INL) of the analog to digital convertor of the PIC, and affects all analog inputs uniformly. While in principle we can ignore this for all practical purposes, in order to further improve the analog accuracy, we can also store this INL error of the ADC, and apply this correction to any channel after its slope and offset has been corrected.

The overall slope and offset are caused by the analog references and components, and can be corrected with a simple 3-degree polynomial. However, the sawtooth pattern is characteristics of the INL, and must be stored in a correction array with 4096 elements ( Each element represents the error of the corresponding ADC code of the 12-bit ADC )
The yellow trace represents the error in readings from the ADC after applying polynomial and table based correction. There appears to be a small offset that can be attributed to a change in ambient temperature , but can be neglected as it is in the order of 100uV

 

The following utilities and code are necessary for this process
  • An I2C communication library for ADS1115 must be present in order to acquire data from it via the PSLab
  • The library should be able to handle the following tasks
    • read single ended , and differential voltage values from any of the channels
    • Enable selection of voltage range and voltage reference
  • A graphical interface with the following features and algorithms will be required:
    • Vary the output voltages from PV1,2,3 in small, definite intervals
    • Store the errors in the analog outputs and inputs as a function of the actual voltage
    • Generate Cubic interpolation functions for each input and output channel
    • The Programmable Current Source can be calibrated using a measured Load resistor, and calibrated analog channel. Its interpolation function must also be stored.
    • Write all calibration constants into flash memory after assigning a timestamp
    • Store raw calibration data in a client-side folder
Testing of the analog inputs after applying calibration polynomials. It can be observed that the accuracy has been brought within a +/-5mV range for the wide input channels. For CH3, a +/-1mV accuracy is achieved.
Resources
Continue ReadingCalibrating the PSLab’s Analog Features for Maximum Accuracy

Implementing Experiment Functionality in PSLab Android

Using the PSLab Hardware Device, users can perform experiments in various domains like Electronics, Electrical, Physics, School Level experiments, etc. These experiments can be performed using functionalities exposed by hardware device like Programmable Voltage Sources, Programmable Current Source, etc. In this post we will try implementing the functionality to perform an experiment using the PSLab Hardware Device and the PSLab Android App.

Let us take the Ohm’s law experiment as an example and see how it’s implement using the  PSLab Android App.

Ohm’s law states that the current through a conductor between two points is directly proportional to the voltage across the two points, effectively using a constant of proportionality called Resistance (R) where,

R = V / I

Schematic

Layout to perform Ohm’s law experiment

The Ohm’s law experiment requires a variable current, so a seekbar is provided to change the current coming from PCS channel, values of which are continuously reflected in the TextView next to it.

Implementation

The Read button has a listener attached to it. Once it is clicked, the currentValue is updated with the value parsed from the seekbar progress and the selectedChannel variable is assigned from the spinner. These variables are used by the background thread to change the current supplied by current source (PCS pin) of the device and to read the updated voltage from the selected channel of the device.

btnReadVoltage.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       selectedChannel = channelSelectSpinner.getSelectedItem().toString();
       currentValue = Double.parseDouble(tvCurrentValue.getText().toString());
       if (scienceLab.isConnected()) {
           CalcDataPoint calcDataPoint = new CalcDataPoint();
           calcDataPoint.execute();
       } else {
           Toast.makeText(getContext(), "Device not connected", Toast.LENGTH_SHORT).show();
       }
   }
});

CalcDataPoint is an AsyncTask which does all the underlying work like setting the current at the PCS channel, reading the voltage from the CH1 channel and triggering the update of the data points on the graph.

private class CalcDataPoint extends AsyncTask<Void, Void, Void> {

   @Override
   protected Void doInBackground(Void... params) {
       scienceLab.setPCS((float) currentValue);
       switch (selectedChannel) {
           case "CH1":
               voltageValue = scienceLab.getVoltage("CH1", 5);
               break;
           case "CH2":
               voltageValue = scienceLab.getVoltage("CH2", 5);
               break;
           case "CH3":
               voltageValue = scienceLab.getVoltage("CH3", 5);
               break;
           default:
               voltageValue = scienceLab.getVoltage("CH1", 5);
       }
       x.add((float) currentValue);
       y.add((float) voltageValue);
       return null;
   }

   @Override
   protected void onPostExecute(Void aVoid) {
       super.onPostExecute(aVoid);
       updateGraph();
   }
}

updateGraph() method is used to update the graph on UI thread. It creates a new dataset from the points which were added by the background thread and refreshes the graph with it using the invalidate() method.

private void updateGraph() {
   tvVoltageValue.setText(df.format(voltageValue));
   List<ILineDataSet> dataSets = new ArrayList<>();
   List<Entry> temp = new ArrayList<>();
   for (int i = 0; i < x.size(); i++) {
       temp.add(new Entry(x.get(i), y.get(i)));
   }
   LineDataSet dataSet = new LineDataSet(temp, "I-V Characteristic");
   dataSet.setColor(Color.RED);
   dataSet.setDrawValues(false);
   dataSets.add(dataSet);
   outputChart.setData(new LineData(dataSets));
   outputChart.invalidate();
}

Roadmap

We are planning to add an option to support multiple trials of the same experiment and save each trails for further reference. App flow to perform experiment is based on Science Journal app by Google.

Resources

  • Article on Ohm’s law and Power on electronics-tutorial
  • To know more about Voltage, Current, Resistance and Ohm’s law, head on to detailed tutorial on sparkfun
  • Implementation of perform experiment functionality in PSLab Desktop App
Continue ReadingImplementing Experiment Functionality in PSLab Android

Performing the Experiments Using the PSLab Android App

General laboratory experiments can be performed using core functionalities offered by the PSLab hardware device like Programmable Voltage Sources, Programmable Current Source, Analog to Digital Converter, Frequency Counter, Function Generators, etc. In this post we will  have a brief look on a general laboratory experiment and how we can perform it using the  PSLab Android App and the PSLab hardware device.

We are going to take Zener I-V Characteristics Curve experiment as an example to understand how we can perform a general experiment using the PSLab device. First, we will  look at the general laboratory experiment and it’s format. Then we will see how that experiment can be performed using the PSLab Android App and the PSLab Hardware Device.

Experiment Format of General Experiment in Laboratory

AIM: In this experiment, our aim is to observe the relation between the voltage and the corresponding current that was generated. We will then plot it to get the dependence.

Apparatus:

  • A Zener Diode
  • A DC Voltage Supplier
  • Bread Board
  • 100 ohm resistor
  • 2 multimeter for measuring current and voltages
  • Connecting wires

Theory: A Zener Diode is constructed for operation in the reverse breakdown region.The relation between I-V is almost linear in this case, Vz = Vz0 + Iz * Rz , where Rz is the dynamic resistance of the zener at the operating point and Vz0 is the voltage at which the straight-line approximation of the I-V characteristic intersects the horizontal axis. After reaching a certain voltage, called the breakdown voltage, the current increases drastically even for a small change in voltage. However, there is no appreciable change in voltage accompanying this current change. So, when we plot the graph, we get a curve which is very near to the x-axis and nearly parallel to it until a particular potential value, called the Zener potential, is reached. After the Zener potential Vz value, there will be a sudden change and the graph becomes exponential.

Source: learning about electronics

Procedure: Construct the circuit as shown in figure below

Now, start increasing the voltage until a reading in the multimeter for current can be obtained. Note that reading. Now, start increasing the input voltage and take the corresponding current readings. Using the set of readings observed,  construct a V vs I graph. This graph gives us the I-V characteristics. The slope of the curve at any point gives the dynamic resistance at that voltage.

Result: The Characteristic curve has been verified after plotting V-I data points on the graph.

Experiment format in PSLab Android App

We have a ViewPager that renders two fragments:

  1. Experiment Doc– It consists of information like the Aim of experiment, Schematic, Output screenshot that we will get after the experiment has been performed.
  2. Experiment Setup– It consists of the setup to configure the PSLab device. This fragment is analogous to the experiment apparatus of the laboratory.  

Below is a gif showing the experiment doc of the Zener I-V experiment which is to be performed using the PSLab device. It consists of a schematic and a screenshot of the output that we get after performing the experiment.

Source: PSLab Android

Make the circuit connections on a breadboard as shown in the schematic. After the circuit is complete we need to configure experiment.

Source: PSLab Android

To configure the experiment, we give the initial voltage, the final voltage and the step size. After clicking on START EXPERIMENT, the voltage is varied on the PV1 channel from the initial voltage to final voltage by increasing the voltage in step size. At each variation of voltage, the current is calculated by dividing the voltage difference between resistor by its resistance value i.e

I = ( VPV1 - VCH1 ) / R

As soon as the initial voltage reaches the final voltage, the experiment stops and data points are plotted on the graph. From the graph we can see the change in the current through a zener diode when the voltage varies across it’s terminals.

The output that was obtained after the experiment is I-V characteristic curve for Zener Diode as shown in the image below.

It can be clearly seen that after the breakdown voltage (~0.7V) the  current increases drastically with respect to the  increase in the voltage. After this point, the voltage can be considered  nearly constant unlike the current which varies exponentially.

In the PSLab Android App, there are read-back errors while reading bytes serially from the PSLab Hardware Device. As a result, the data points are not read accurately and an inaccurate plot is generated on the graph as shown in the image below.

Source: PSLab Android

Resources

Continue ReadingPerforming the Experiments Using the PSLab Android App

SPI Communication in PSLab

PSLab supports communication using the Serial Peripheral Interface (SPI) protocol. The Desktop App as well as the Android App have the framework set-up to use this feature. SPI protocol is mainly used by a few sensors which can be connected to PSLab. For supporting SPI communication, the PSLab Communication library has a dedicated class defined for SPI. A brief overview of how SPI communication works and its advantages & limitations can be found here.

The class dedicated for SPI communication with numerous methods defined in them. The methods required for a particular SPI sensor may differ slightly, however, in general most sensors utilise a certain common set of methods. The set of methods that are commonly used are listed below with their functions.

In the setParameters method, the SPI parameters like Clock Polarity (CKP/CPOL), Clock Edge (CKE/CPHA), SPI modes (SMP) and other parameters like primary and secondary prescalar which are specific to the device used.

Primary Prescaler (0,1,2,3) for 64MHz clock->(64:1,16:1,4:1,1:1)

Secondary prescaler (0,1,..7)->(8:1,7:1,..1:1)

The values of CKP/CPOL and CKE/CPHA needs to set using the following convention and according to our requirements.

  • At CPOL=0 the base value of the clock is zero, i.e. the idle state is 0 and active state is 1.
    • For CPHA=0, data is captured on the clock’s rising edge (low→high transition) and data is changed at the falling edge (high→low transition).
    • For CPHA=1, data is captured on the clock’s falling edge (high→low transition) and data is changed at the rising edge (low→high transition).
  • At CPOL=1 the base value of the clock is one (inversion of CPOL=0), i.e. the idle state is 1 and active state is 0.
    • For CPHA=0, data is captured on the clock’s falling edge (high→low transition) and data is changed at the rising edge (low→high transition).
    • For CPHA=1, data is captured on the clock’s rising edge (low→high transition) and data is changed at the falling edge (high→low transition).

public void setParameters(int primaryPreScalar, int secondaryPreScalar, Integer CKE, Integer CKP, Integer SMP) throws IOException {
        if (CKE != null) this.CKE = CKE;
        if (CKP != null) this.CKP = CKP;
        if (SMP != null) this.SMP = SMP;

        packetHandler.sendByte(commandsProto.SPI_HEADER);
        packetHandler.sendByte(commandsProto.SET_SPI_PARAMETERS);
        packetHandler.sendByte(secondaryPreScalar | (primaryPreScalar << 3) | (this.CKE << 5) | (this.CKP << 6) | (this.SMP << 7));
        packetHandler.getAcknowledgement();
    }

 

The start method is responsible for sending the instruction to initiate the SPI communication and it takes the channel which will be used for communication as input.

public void start(int channel) throws IOException {
        packetHandler.sendByte(commandsProto.SPI_HEADER);
        packetHandler.sendByte(commandsProto.START_SPI);
        packetHandler.sendByte(channel);
    }

 

The setCS method is responsible for selecting the slave with which the SPI communication has to be done. This feature of SPI communication is known as Chip Select (CS) or Slave Select (SS). A master can use multiple Chip/Slave Select pins for communication whereas a slave utilises just one pin as SPI is based on single master multiple slaves principle. The capacity of PSLab is limited to two slave devices at a time.

public void setCS(String channel, int state) throws IOException {
        String[] chipSelect = new String[]{"CS1", "CS2"};
        channel = channel.toUpperCase();
        if (Arrays.asList(chipSelect).contains(channel)) {
            int csNum = Arrays.asList(chipSelect).indexOf(channel) + 9;
            packetHandler.sendByte(commandsProto.SPI_HEADER);
            if (state == 1)
                packetHandler.sendByte(commandsProto.STOP_SPI);
            else
                packetHandler.sendByte(commandsProto.START_SPI);
            packetHandler.sendByte(csNum);
        } else {
            Log.d(TAG, "Channel does not exist");
        }
    }

 

The stop method is responsible for sending the instruction to the stop the communication with the slave.

public void stop(int channel) throws IOException {
        packetHandler.sendByte(commandsProto.SPI_HEADER);
        packetHandler.sendByte(commandsProto.STOP_SPI);
        packetHandler.sendByte(channel);
    }

 

PSLab SPI class has methods defined for sending either 8-bit or 16-bit data over SPI which are further classified on whether they request the acknowledgement byte (it helps to know whether the communication was successful or unsuccessful) or not.

The methods are so named send8, send16, send8_burst and send16_burst . The burst methods do not request any acknowledgement value and as a result work faster than the normal methods.

public int send16(int value) throws IOException {
        packetHandler.sendByte(commandsProto.SPI_HEADER);
        packetHandler.sendByte(commandsProto.SEND_SPI16);
        packetHandler.sendInt(value);
        int retValue = packetHandler.getInt();
        packetHandler.getAcknowledgement();
        return retValue;
    }

 

Resources:

Continue ReadingSPI Communication in PSLab

Implementing Tree View in PSLab Android App

When a task expands over sub tasks, it can be easily represented by a stem and leaf diagram. In the context of android it can be implemented using an expandable list view. But in a scenario where the subtasks has mini tasks appended to it, it is hard to implement it using the general two level expandable list views. PSLab android application supports many experiments to perform using the PSLab device. These experiments are divided into major sections and each experiments are listed under them.

The best way to implement this functionality in the android application is using a multi layer treeview implementation. In this context three layers are enough as follows;


This was implemented with the help from a library called AndroidTreeView. This blog will outline how to modify and implement it in PSLab android application.

Basic Idea

Tree view implementation simply follows the data structure “Tree” used in algorithms. Every tree has a root where it starts and from the root there will be branches which are connected using edges. Every edge will have a parent and child. To reach a child, one has to traverse through only one route.

Setting Up Dependencies

Implementing tree view begins with setting up dependencies in the gradle file in the project.

compile 'com.github.bmelnychuk:atv:1.2.+'

Creating UI for tree view

The speciality about this implementation is that it can be loaded into any kind of a layout such as a linearlayout, relativelayout, framelayout etc.

final TreeNode Root = TreeNode.root();
Root.addChildren(
       // Add child nodes here
);
// Set up the tree view
AndroidTreeView experimentsListTree = new AndroidTreeView(getActivity(), Root);
experimentsListTree.setDefaultAnimation(true);
[LinearLayout/RelativeLayout].addView(experimentsListTree.getView());

Creating a node holder

Trees are made of a collection of tree nodes. A holder for a tree node can be created using an object which extends the BaseNodeViewHolder class provided by the library. BaseNodeViewHolder requires a holder class which is generally static so that it can be accessed without creating an instance which nests textviews, imageviews and buttons.

Once the holder extends the BaseNodeViewHolder, it should override two methods as follows;

@Override
public View createNodeView(final TreeNode node, ClassContainingNodeData header) {

}

@Override
public void toggle(boolean active) {

}

createNodeView() which inflate the view and toggle() method which can be used to toggle clicks on the tree node in the UI.

The following code snippet shows how to create an object which extends the above mentioned class with the overridden methods.

public class ExperimentHeaderHolder extends TreeNode.BaseNodeViewHolder<ExperimentHeaderHolder.ExperimentHeader> {

    private ImageView arrow;

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

    @Override
    public View createNodeView(final TreeNode node, ExperimentHeader header) {

            final LayoutInflater inflater = LayoutInflater.from(context);
            final View view = inflater.inflate(R.layout.header_holder, null, false);

            TextView title = (TextView) view.findViewById(R.id.title);
            title.setText(header.title);

            arrow = (ImageView) view.findViewById(R.id.experiment_arrow);
        
            return view;
    }

    @Override
    public void toggle(boolean active) {
            arrow.setImageResource(active ? arrow_drop_up : arrow_drop_down);
    }

    public static class ExperimentHeader {

            public String title;

            public ExperimentHeader(String title) {
               this.title = title;
            }
    }
}

Creating a TreeNode

Once the holder is complete, we can move on to creating an actual tree node. TreeNode class requires an object which extends the BaseNodeViewHolder class as mentioned earlier. Also it requires a viewholder which it can use to inflate the view in the tree layout. The viewholder can be a different class. The importance of this different implementation can be explained as follows;

TreeNode treeNode = new TreeNode(new ExperimentHeaderHolder.ExperimentHeader(“Title”))
       .setViewHolder(new ExperimentHeaderHolder(context));

In the Saved Experiments section of PSLab android application, all the three levels shouldn’t implement the toggle behavior as a user clicks on the experiment (last level item), he doesn’t expect the icon to change like the ones in headers where an arrow points up and down when he clicks on it. In this case we can reuse a holder which has the title attribute while creating only a holder which does not override the toggle function to ignore icon toggling at the last level of the tree view. This explanation can be illustrated using a code snippet as follows;

new TreeNode(new ExperimentHeaderHolder.ExperimentHeader(“Title”))
       .setViewHolder(new IndividualExperimentHolder(context));

Creating parent nodes and finally the Root node

The final part of the implementation is to create parent nodes to group up similar experiments together. The TreeNode object supports a method call addChild() and addChildren(). addChild() method allows adding one tree node to the specific tree node and addChildren() method allows adding many tree nodes at the same time. Following code snippet illustrates how to add many tree nodes to a node and make it a parent node.

treeDiodeExperiments.addChildren(treeZener, treeDiode, treeDiodeClamp, treeDiodeClip, treeHalfRectifier, treeFullWave);

Setting a click listener

Click listener is a very important implementation. Each tree node can be attached with a click listener using the interface provided by the library as follows;

treeNode.setClickListener(new TreeNode.TreeNodeClickListener() {
   @Override
   public void onClick(TreeNode node, Object value) {

   }
});

The value object is the class attached to the holder and its attributes can be retireved by casting it to the specific class using casting methods;

String title = ((ExperimentHeaderHolder.ExperimentHeader) value).title;

Resources:

Continue ReadingImplementing Tree View in PSLab Android App

Developing Control Panel for Sensor Activity in PSLab Android

Once we are able to capture data from the sensor using the PSLab device and stimulate it on PSLab Android App, we now require to provide the user various control options. These control options help the user to customize the data captures from the sensors. These options are available for all the sensors.

  • Number of samples: This allows the user to enter the number of samples he/she wants to capture.
  • Indefinite mode: This allows the user to capture indefinite samples from the sensors.
  • Play/Pause: This allows the user to start or pause the capture anytime.
  • Time-gap: User can set the time-gap between each sample capture.

Let’s discuss how to implement these control options in PSLab Android.

Creating layout for Control Panel

Initially, a control panel is created. A separate layout is created for the same in the sensor activity. Inside the layout, we added

  • An Image-Button which works as a play and pause button
  • An Edit-Text in which the user can enter the number of samples to be captured.
  • A Check-Box which enables indefinite sample capture.
  • A Seek-Bar which sets the time-gap between each sample capture.

Adding functionality to widgets.

Image-Button on-click listener has two roles to play. One role is to change the play image to pause image or vice versa and another is to set boolean variable true or false. This variable is used to stop or start the thread which is involved in fetching data from the sensor.

playPauseButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       if (play) {
           playPauseButton.setImageResource(R.drawable.play);
           play = false;
       } else {
           playPauseButton.setImageResource(R.drawable.pause);
           play = true;
       }
   }
});

The play variable can be accessed by the different fragment to pause or resume the capture of the data from the sensors.

if (scienceLab.isConnected() && ((SensorActivity) getActivity()).play) {
//rest of the code
}

The number entered in the Edit-Box work as the maximum limit of samples to be captured. For this, a simple counter function is implemented. If the count value reaches the value in Edit-Box the thread is AsyncTask for fetching sensor data is not called any further. Enabling the Check-Box, disables the Edit-Box and hence eliminate the role of counter function resulting in AsyncTask (for fetching sensor data) being called indefinitely.

Time gap Seek-Bar sets the delay between each time AsyncTask for fetching sensor data is called. The thread sleeps for  the time selected in the Seek-Bar before AsyncTask is called again. Here is the code snippet for it.

try {
   Thread.sleep(((SensorActivity) getActivity()).timegap);
} catch (InterruptedException e) {
   e.printStackTrace();
}

This implements control panel for sensor activity in PSLab Android. To follow the entire code, click here.

Resources

Stack Overflow solution on how to change Imagebutton’s image onClick.

Continue ReadingDeveloping Control Panel for Sensor Activity in PSLab Android

I2C Communication in PSLab

PSLab supports communication using the I2C protocol and both the Desktop App and the Android App have the framework set-up to use the I2C protocol. I2C protocol is mainly used by sensors which can be connected to PSLab. For supporting I2C communication, PSLab board has a separate block for I2C communication and has pins named 3.3V, GND, SCL and SDA. A brief overview of how I2C communication works and its advantages & limitations compared to SPI communication can be found here.

The PSLab Python and Java communication libraries have a class dedicated for I2C communication with numerous methods defined in them. The methods required for a particular I2C sensor may differ, however, in general most sensors utilise a certain common set of methods. The set of methods that are commonly used are listed below with their functions. For utilising the methods, the I2C bus is first notified using the HEADER byte (it is common to all the methods) and then a byte to uniquely determine the method in use.

The send method is used to send the data over the I2C bus. First the I2C bus is initialised and set to the correct slave address using I2C.start(address) followed by this method. The method takes the data to be sent as the argument.

def send(self, data):
    try:
        self.H.__sendByte__(CP.I2C_HEADER)
        self.H.__sendByte__(CP.I2C_SEND)
        self.H.__sendByte__(data)  # data byte
        return self.H.__get_ack__() >> 4
    except Exception as ex:
        self.raiseException(ex, "Communication Error , Function : " + inspect.currentframe().f_code.co_name)

 

The read method reads a fixed number of bytes from the I2C slave. One can also use I2C.simpleRead(address,  numbytes) instead to read from the I2C slave. This method takes the length of the data to be read as argument.  It fetches length-1 bytes with acknowledge bits for each.

def read(self, length):
     data = []
     try:
        for a in range(length - 1):
             self.H.__sendByte__(CP.I2C_HEADER)
             self.H.__sendByte__(CP.I2C_READ_MORE)
             data.append(self.H.__getByte__())
             self.H.__get_ack__()
       self.H.__sendByte__(CP.I2C_HEADER)
       self.H.__sendByte__(CP.I2C_READ_END)
       data.append(self.H.__getByte__())
       self.H.__get_ack__()
    except Exception as ex:
       self.raiseException(ex, "Communication Error , Function : " + inspect.currentframe().f_code.co_name)
   return data

 

The readBulk method reads the data from the I2C slave. This takes the I2C slave device address, the address of the device from which the data is to be read and the length of the data to be read as argument and the returns the bytes read in the form of a list.

def readBulk(self, device_address, register_address, bytes_to_read):
        try:
            self.H.__sendByte__(CP.I2C_HEADER)
            self.H.__sendByte__(CP.I2C_READ_BULK)
            self.H.__sendByte__(device_address)
            self.H.__sendByte__(register_address)
            self.H.__sendByte__(bytes_to_read)
            data = self.H.fd.read(bytes_to_read)
            self.H.__get_ack__()
            try:
                return [ord(a) for a in data]
            except:
                print('Transaction failed')
                return False
        except Exception as ex:
           self.raiseException(ex, "Communication Error , Function : " + inspect.currentframe().f_code.co_name)

 

The writeBulk method writes the data to the I2C slave. It takes address of the particular I2C slave for which the data is to be written and the data to be written as arguments.

def writeBulk(self, device_address, bytestream):
        try:
            self.H.__sendByte__(CP.I2C_HEADER)
            self.H.__sendByte__(CP.I2C_WRITE_BULK)
            self.H.__sendByte__(device_address)
            self.H.__sendByte__(len(bytestream))
            for a in bytestream:
                self.H.__sendByte__(a)
            self.H.__get_ack__()
        except Exception as ex:
  self.raiseException(ex, "Communication Error , Function : " + inspect.currentframe().f_code.co_name)

 

The scan method scans the I2C port for connected devices which utilise I2C as a communication mode. It takes frequency as an argument to set the frequency of the communication and is by default set to 100000. An array containing the addresses of the connected devices (which are integers) is returned.

def scan(self, frequency=100000, verbose=False):
        self.config(frequency, verbose)
        addrs = []
        n = 0
        if verbose:
            print('Scanning addresses 0-127...')
            print('Address', '\t', 'Possible Devices')
        for a in range(0, 128):
            x = self.start(a, 0)
            if x & 1 == 0:  # ACK received
                addrs.append(a)
                if verbose: print(hex(a), '\t\t', self.SENSORS.get(a, 'None'))
                n += 1
            self.stop()
       return addrs

 

Additional Sources

  1. Learn more about the principles behind i2c communication https://learn.sparkfun.com/tutorials/i2c
  2. A simple experiment to demonstrate use of i2c communication with Arduino http://howtomechatronics.com/tutorials/arduino/how-i2c-communication-works-and-how-to-use-it-with-arduino/
  3. Java counterpart of the PSLab I2C library https://github.com/fossasia/pslab-android/blob/master/app/src/main/java/org/fossasia/pslab/communication/peripherals/I2C.java
Continue ReadingI2C Communication in PSLab

High School Physics Practicals using PSLab Device

High school physics syllabus includes rather advanced concepts in the world of Physics; namely practicals related to sound, heat, light and electric. Almost all of these practicals are done in physics labs using conventional bulky equipments. Especially the practicals related to electrical and electronics. They use bulky oscilloscopes with complex controls and multimeter with so many controls. PSLab being a sophisticated device which integrates a whole science lab into a 2” by 2” small circuit, these practicals made easy and interesting.

There are several practicals required to be completed by a student before sitting for GCE (Advanced Level) examination. This blog post points out how to perform those experiments using PSLab device and several other tools required without having to use bulky instruments.

  • Calculating internal resistance and EMF of a dry cell

This experiment includes the above mentioned circuitry. Once the basic setup is completed using;

  • Dry cell
  • 10K variable resistor
  • 1K resistor
  • Switch/Jumper

Connect the CH1 pin and GND pin of PSLab across the dry cell and CH2 pin and GND across the Ammeter instead of the Ammeter. Once the pin connection is complete, plug the PSLab device to the computer and using the desktop application voltmeter, measure the voltage from CH1 and current from voltage value read from CH2 and the known resistance value of R. Record these data against step changes in the resistance of the variable resistor starting from a high value to a low value. Once there are sufficient data as much as 10 data set, using a graph paper draw the relation between current and voltage measured according to the equation given below.

E = V + Ir

V = -rI + E

This will produce a graph with a constant negative gradient. Gradient of the graph will produce the internal resistance of the dry cell.

  • I-V graphs for a semiconductor

This experiment will require;

  • Diode
  • 100 Ohms resistor

Conduct the experiment as follows once the circuit is set up. Increase the voltage provided by the PV1 pin of the PSLab by 100 mV per step and measure the voltage across diode using CH3 pin of PSLab device. Using that voltage and the supply voltage, calculate the current flowing through the resistor. Note down the readings as voltage to current pairs and plot them on a graph paper. The graph will produce the following results which is identical to common IV characteristics of a semiconductor.

Start A at zero and increase by 0.1V steps while measuring voltage and current across diode. (Image from Wikipedia)

Apart from this conventional experiment, PSLab provides an inbuilt experiment students and teachers can use. In the Electronics Experiments section, Diode IV characteristics experiment is configured in such a way that this experiment can be conducted very easily. The circuit configuration is the same and R value should be 1K. Once the step size is set to an appropriate resolution, START button will begin the experiment and provide with the final graph.

  • Transfer characteristics of a transistor

Set up the above mentioned circuitry on a breadboard and connect the appropriate pins of PSLab device as mentioned. In this experiment, student need to observe the increase in current/voltage across CH1 when PV2 is varying. We need to measure CH1 parameter value against PV2 voltage value and plot these two against to obtain the transfer characteristics of a BJT.

Apart from this conventional experiment, PSLab provides an inbuilt experiment to perform this lab exercise. Using “BJT Transfer Characteristics” experiment, students and teachers can easily obtain the characteristics curves by setting step sizes and voltage values to the required pins.

  • Ohm’s law

Configure the following circuit and connect PCS, CH1 and GND pins of PSLab into relevant positions. This experiment is to measure voltage across the resistor against the variation in current through the circuit. Increase current provided to the circuit using PCS pin and measure voltage using CH1 pin and plot against the current. The gradient will produce the resistor value.

In the electrical experiments section in PSLab application has a separate experiment to perform the Ohm’s Law experiment. Using this experiment, students can change the current values using the knob and record the voltage values related to that. Finally the plot can be generated which will be of a constant gradient.

  • Kirchhoff’s Laws
  • Voltage law

Kirchhoff’s Voltage law states that the directed sum of the voltage around any closed network is zero.

This law can be proved using the following circuit with the help of PSLab device. Connect the channel pins as per the diagram and measure voltages in the three channels. They will show a relationship as the directed sum of the combination will turn into a zero.

  • Current law

Kirchhoff’s current law states that at any node in a circuit, the sum of currents flowing into that node is equal to the sum of currents flowing out of that node; which is similar to the direct summation of currents in a node is zero.

Using the same circuit as above, measure the current flowing through each node using the voltage readings of the channels and known resistor values. Considering the sign of the current which is easily readable in PSLab desktop application, the summation will produce a zero.

Resources:

Continue ReadingHigh School Physics Practicals using PSLab Device

Using the Audio Jack to make an Oscilloscope in the PSLab Android App

The PSLab Android App allows users to access functionality provided by the PSLab hardware device, but in the interest of appealing to a larger audience that may not have immediate access to the device, we’re working on implementing some additional functionalities to perform experiments using only the hardware and sensors that are available in most android phones. The mentors suggested that the audio jack (Microphone input) of phones can be hacked to make it function as an Oscilloscope. Similarly, the audio output can also be used as a 2-channel arbitrary waveform generator. So I did a little research and found some articles which described how it can be done. In this post, I will dive a bit into the following aspects –

  • AudioJack specifications for android devices
  • Android APIs that provide access to audio hardware of device
  • Integrating both to achieve scope functionality

Audio Jack specification for android devices

In a general audio jack interface, the configuration CTIA(LRGM – Left, Right, Ground, Mic) is present as shown in the image below. Some interfaces also have OMTP(LRMG – Left, Right, Mic, Ground) configuration in which the common and mic inputs are interchanged. In the image, Common refers to ground.

Source: howtogeek

If we simply cut open the wire of a cheap pair of earphones (stolen from an airplane? 😉 ) , we  will gain access to all terminals (Left, Right, Common, Mic Input) illustrated in the image below

Source: flickr

Android APIs that provide access to audio hardware of device

AudioRecord and AudioTrack are two classes in android that manage recording and playback respectively. We require only AudioRecord to implement scope functionality. We shall first create an object of the AudioRecord class, and use that object to read the audio buffer as and when required.

Creating an AudioRecord object: we need the following parameters to initialise an AudioRecord object.

SAMPLING_RATE: Almost all mobile devices support sampling rate of 44100 Hz. In this context, the definition is number of audio samples taken per second.

RECORDER_AUDIO_ENCODING: Audio encoding describes bit representation of audio data. Here we used PCM_16BIT encoding this means stream of bits generated from PCM are segregated in a set of 16 bits.

getMinimumBufferSize() returns minimum buffer size in byte units required to create an AudioRecord object successfully.

private static final int SAMPLING_RATE = 44100;
private static final int RECORDING_CHANNEL = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private AudioRecord audioRecord = null;
private int minRecorderBufferSize;
minRecorderBufferSize = AudioRecord.getMinBufferSize(SAMPLING_RATE, RECORDING_CHANNEL, RECORDER_AUDIO_ENCODING);
audioRecord = new AudioRecord(
       MediaRecorder.AudioSource.MIC,
       SAMPLING_RATE,
       RECORDING_CHANNEL,
       RECORDER_AUDIO_ENCODING,
       minRecorderBufferSize);

audioRecord object can be used to read audio buffer from audio hardware using read() method.

minRecorderBuffer size is in byte units and 2 bytes constitute a short in JAVA. Thus size of short buffer needed is half the total number of bytes.

short[] audioBuffer = new short[minRecorderBufferSize / 2];
audioRecord.read(audioBuffer, 0, audioBuffer.length);

Now audioBuffer has the audio data as a signed 16 bit values. We need to process the buffer data and plot the processed data points on chart to completely implement scope functionality. I am still looking for relation between the signed 16-bit value of audio buffer and actual mic bias voltage. According to android headset specs, Mic bias voltage is between 1.8-2.9V.

Using AudioRecord class to create a scope in PSLab Android

In PSLab Android App, there is already an Oscilloscope made to capture and plot the data received from PSLab device. To make a cheap oscilloscope, cut open the wire of a cheap headset and expose terminals as illustrated in the image above and provide input signal at microphone input terminal.

Note: Don’t provide a voltage more than 2V at mic input terminal, it can damage your android device. To be sure check peak voltage from external voltmeter of the signal that you want to apply on scope and if it’s greater than 2V, I suggest you to first make a voltage divider to lower the voltage and then you are good to go.

To integrate plotting of audio buffer, we simply need to create another thread that captures audio data and updates the UI with the processed buffer data.

public class captureAudioBuffer extends AsyncTask<Void, Void, Void> {

        private AudioJack audioJack;
        private short[] buffer; 
        public captureAudioBuffer(AudioJack audioJack) {
            this.audioJack = audioJack;
        }

        @Override
        protected Void doInBackground(Void... params) {
            buffer = audioJack.read();
            Log.v("AudioBuffer", Arrays.toString(buffer));
            audioJack.release();
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            // UPDATE UI ACCORDING TO READ BUFFER DATA 
            Log.v("Execution Done", "Completed");
        }
    }

For complete code of AudioJack class, please refer pslab-android-app.

Resources

Continue ReadingUsing the Audio Jack to make an Oscilloscope in the PSLab Android App

Characteristization of Transistors Using PSLab

Transistors are one of the key building blocks of all electronics. They are fundamentally three-terminal semiconductor devices, with the terminals being labelled as the Emitter(E), Base(B), and Collector(C). These active components are found everywhere in electronics, and all of the complex processors that power everything from cellphones to aircraft employ millions of these devices in switching and amplification roles. In this blog post, we shall use the PSLab to explore some of the fundamental properties of transistors, and their various applications.

Transistor as an amplifier

In the schematic shown, we shall try to use an NPN transistor to amplify a small signal.

A small amplitude oscillation generated by W1 with the amplitude knob turned down to a very low level is used as the input. Since transistors do not handle bipolar signals, we have mixed a constant DC voltage generated PV3 to shift this small signal into the positive domain.

The fluctuating potential difference incident at the base of the transistor creates a corresponding current flow between the Base and Emitter.

By the fundamental property of transistors, this influences the path resistance between the Collector(C) and the Emitter(E) , and the resultant amplified voltage output can be monitored at the junction between the 1K resistor and the collector.

We have used CH1 to monitor the input voltage, and CH2 for the output

In a more applied scenario, we can implement the second schematic in order to create an audio amplifier. Instead of using W1 as the input signal, a speaker is used as a microphone. When a sound signal is incident on the speaker, its membrane oscillates, and as a result , the coil attached to it also does the same. Since this coil is placed in a magnetic field , its oscillations result in a change in the magnetic flux passing through, and this change causes a voltage(EMF) induced at its output. We then use our transistor amplifier to amplify this small EMF

Figure 2 : A Transistor being used to apply a gain of 81.5x to a small amplitude sine wave. The input waveform (green) is shown on a +/-500mV full scale and the output waveform is shown on a +/-8V scale in order to be able to view both. However, due to the difference in scales, the actual difference in amplitudes is 16 times more than what is visible.
Common Emitter Characteristics
Schematic Diagram

Any introductory course on transistors includes a diagram similar to the one shown , and a description about how for any base current, the collector current eventually saturates, and that this saturation level is proportional to the base current itself.

With the PSLab’s transistor CE characterization app, we can set up this experiment, and verify this for ourselves using an NPN transistor. The results shown were gathered using a 2N2222 transistor

In the schematic , the base current is determined by the voltage source PV2, and a high value series resistor of 200 KOhms . We use an analog input CH3 to monitor the voltage present at the Base of the transistor in order to calculate the total base current.

Base current = V/R = (PV2 – CH3) / 200e3

Now that we have set a particular base current, PV1 is used to sequentially increase the voltage across the collector and emitter of the transistor. A current limiting resistor of 1K Ohm is used, and CH1 is used to monitor the voltage drop across the transistor.

Collector current = V/R = (PV1 – CH1) / 1e3

Plotting the behaviour of the collector current with respect to the collector voltage gives us the familiar current voltage characteristics of a transistor.

Figure 3: Common emitter characteristics of an NPN transistor (2N2222) for various base currents

We can now alter the base current by changing PV2, and verify that the saturation current for the collector is indeed a function of it.

Resources

 

Continue ReadingCharacteristization of Transistors Using PSLab