Voltage Measurement through Channels in PSLab

The Pocket Science Lab multimeter has got three channels namely CH1,CH2 and CH3 with different ranges for measuring the voltages.This blog will give a brief description on how we measure voltages in channels.

Measuring Voltages at channels can be divided into three parts:-

        1. Communication between between device and Android.
        2. Setting up analog channel (analog constants)
        3. Voltage measuring function of android.

Communication between PSLab device and Android App

The communication between the PSLab device and  Android occurs through the help of UsbManger package of CommunicationHandler class of the app. The main two functions involved in the communication are read and write functions in which we send particular number of bytes and then we receive certain bytes.

The read function :-

public int read(byte[] dest, int bytesToBeRead, int timeoutMillis) throws IOException {
    int numBytesRead = 0;
    //synchronized (mReadBufferLock) {
    int readNow;
    Log.v(TAG, "TO read : " + bytesToBeRead);
    int bytesToBeReadTemp = bytesToBeRead;
    while (numBytesRead < bytesToBeRead) {
        readNow = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, bytesToBeReadTemp, timeoutMillis);
        if (readNow < 0) {
            Log.e(TAG, "Read Error: " + bytesToBeReadTemp);
            return numBytesRead;
        } else {
            //Log.v(TAG, "Read something" + mReadBuffer);
            System.arraycopy(mReadBuffer, 0, dest, numBytesRead, readNow);
            numBytesRead += readNow;
            bytesToBeReadTemp -= readNow;
            //Log.v(TAG, "READ : " + numBytesRead);
            //Log.v(TAG, "REMAINING: " + bytesToBeRead);
        }
    }
    //}
    Log.v("Bytes Read", "" + numBytesRead);
    return numBytesRead;
}

Similarly the write function is –

public int write(byte[] src, int timeoutMillis) throws IOException {
    if (Build.VERSION.SDK_INT < 18) {
        return writeSupportAPI(src, timeoutMillis);
    }
    int written = 0;
    while (written < src.length) {
        int writeLength, amtWritten;
        //synchronized (mWriteBufferLock) {
        writeLength = Math.min(mWriteBuffer.length, src.length - written);
        // bulk transfer supports offset from API 18
        amtWritten = mConnection.bulkTransfer(mWriteEndpoint, src, written, writeLength, timeoutMillis);
        //}
        if (amtWritten < 0) {
            throw new IOException("Error writing " + writeLength +
                " bytes at offset " + written + " length=" + src.length);
        }
        written += amtWritten;
    }
    return written;
}

Although these are the core functions used for communication but the data received through these functions are further processed using another class known as PacketHandler. In the PacketHandler class also there are two major functions i.e sendByte and getByte(), these are the main functions which are further used in other classes for communication.

The sendByte function:-

public void sendByte(int val) throws IOException {
    if (!connected) {
        throw new IOException("Device not connected");
    }
    if (!loadBurst) {
        try {
            mCommunicationHandler.write(new byte[] {
                (byte)(val & 0xff), (byte)((val >> 8) & 0xff)
            }, timeout);
        } catch (IOException e) {
            Log.e("Error in sending int", e.toString());
            e.printStackTrace();
        }
    } else {
        burstBuffer.put(new byte[] {
            (byte)(val & 0xff), (byte)((val >> 8) & 0xff)
        });
    }
}

As we can see that in this function also the main function used is the write function of communicationHandler but in this class the data is further processed.

Setting Up the Analog Constants

For setting up the ranges, gains and other properties of channels, a different class of AnalogConstants is implemented in the android app, in this class all the properties which are used by the channels are defined which are further used in the sendByte() functions for communication.

public class AnalogConstants {

    public double[] gains = {1, 2, 4, 5, 8, 10, 16, 32, 1 / 11.};
    public String[] allAnalogChannels = {"CH1", "CH2", "CH3", "MIC", "CAP", "SEN", "AN8"};
    public String[] biPolars = {"CH1", "CH2", "CH3", "MIC"};
    public Map<String, double[]> inputRanges = new HashMap<>();
    public Map<String, Integer> picADCMultiplex = new HashMap<>();

    public AnalogConstants() {

        inputRanges.put("CH1", new double[]{16.5, -16.5});
        inputRanges.put("CH2", new double[]{16.5, -16.5});
        inputRanges.put("CH3", new double[]{-3.3, 3.3});
        inputRanges.put("MIC", new double[]{-3.3, 3.3});
        inputRanges.put("CAP", new double[]{0, 3.3});
        inputRanges.put("SEN", new double[]{0, 3.3});
        inputRanges.put("AN8", new double[]{0, 3.3});

        picADCMultiplex.put("CH1", 3);
        picADCMultiplex.put("CH2", 0);
        picADCMultiplex.put("CH3", 1);
        picADCMultiplex.put("MIC", 2);
        picADCMultiplex.put("AN4", 4);
        picADCMultiplex.put("SEN", 7);
        picADCMultiplex.put("CAP", 5);
        picADCMultiplex.put("AN8", 8);

    }
}

Also in the AnalogInput sources class many other properties such as CHOSA( a variable assigned to denote the analog to decimal conversion constant of each channel) are also defined

public AnalogInputSource(String channelName) {
    AnalogConstants analogConstants = new AnalogConstants();
    this.channelName = channelName;
    range = analogConstants.inputRanges.get(channelName);
    gainValues = analogConstants.gains;
    this.CHOSA = analogConstants.picADCMultiplex.get(channelName);
    calPoly10 = new PolynomialFunction(new double[] {
        0.,
        3.3 / 1023,
        0.
    });
    calPoly12 = new PolynomialFunction(new double[] {
        0.,
        3.3 / 4095,
        0.
    });
    if (range[1] - range[0] < 0) {
        inverted = true;
        inversion = -1;
    }
    if (channelName.equals("CH1")) {
        gainEnabled = true;
        gainPGA = 1;
        gain = 0;
    } else if (channelName.equals("CH2")) {
        gainEnabled = true;
        gainPGA = 2;
        gain = 0;
    }
    gain = 0;
    regenerateCalibration();
}

Also in this constructor a polynomial function is also called which further plays an important  role in measuring voltage as it is through this polynomial function we get the voltage of channels in the science lab class , also it is also used in oscilloscope for plotting the graph . So this was the setup of analog channels.

Voltage Measuring Functions

There are two major functions for measuring voltages which are present in the scienceLab class

  • getAverageVoltage
  • getRawableVoltage

Here are the functions

private double getRawAverageVoltage(String channelName) {
    try {
        int chosa = this.calcCHOSA(channelName);
        mPacketHandler.sendByte(mCommandsProto.ADC);
        mPacketHandler.sendByte(mCommandsProto.GET_VOLTAGE_SUMMED);
        mPacketHandler.sendByte(chosa);
        int vSum = mPacketHandler.getVoltageSummation();
        mPacketHandler.getAcknowledgement();
        return vSum / 16.0;
    } catch (IOException | NullPointerException e) {
        e.printStackTrace();
        Log.e(TAG, "Error in getRawAverageVoltage");
    }
    return 0;
}

This is the major function which takes the data from the communicationHandler class via packetHandler. Further this function is used in the getAverageVoltage function.

private double getAverageVoltage(String channelName, Integer sample) {
    if (sample == null) sample = 1;
    PolynomialFunction poly;
    double sum = 0;
    poly = analogInputSources.get(channelName).calPoly12;
    ArrayList < Double > vals = new ArrayList < > ();
    for (int i = 0; i < sample; i++) {
        vals.add(getRawAverageVoltage(channelName));
    }
    for (int j = 0; j < vals.size(); j++) {
        sum = sum + poly.value(vals.get(j));
    }
    return sum / vals.size();
}

This function uses the data from the getRawableVoltage function and uses it the polynomial generated in the analog lasses to calculate the final voltage. Thus this was the core backend of calculating the voltages through channels in PSLab.

Resources:

Continue ReadingVoltage Measurement through Channels in PSLab

Using Multimeter in PSLab Android Application

The Pocket Science Lab as we all know is on the verge of development and new features and UI are added almost every day. One such feature is the implementation of multimeter which I have also discussed in my previous blogs.

Figure (1) : Screenshot of the multimeter

But although many functionality of multimeter such as resistance measurement are working perfectly, there are still various bugs in the multimeter. This blog is dedicated to using multimeter in the android app.

Using the multimeter

Figure (2): Screenshot showing guide of multimeter

Figure (2) shows the guide of the multimeter, i.e how basic basic elements such as resistance and voltage are measured using the multimeter. The demonstration of measuring the resistance and voltage are given below.

Measuring the resistance

The resistance is measure by connecting the SEN pin to the positive end of resistor and the GND pin to the negative end of resistor and then clicking the RESISTANCE button.

                   Figure (3) : Demonstration of resistance measurement

Measuring the voltage

To measure the voltage as said in the Guide, directly connect the power source to the the channel pins, although currently only the CH3 pin will show the most accurate results, work is going on other channel improvisation as well.

Figure (4) : Demonstration of Voltage measurement

 

And thus this is how the multimeter is used is used in the android app.  Of course there are still many many features such as capacitance measurements which are yet to be implemented and the work is going on them

Resources:

Continue ReadingUsing Multimeter in PSLab Android Application

Implementing Multimeter in PSLab Android App

The Pocket Science Lab Android app being on the verge of development have various new features adding up per day. One of the new things added up recently is the splitting of the control section in three different instruments and implementing the control read section into a multimeter. This blog will be discussing about how the multimeter is implemented.

The different instruments are power section, multimeter and wave generator. While in the previous implementation of control section it was divided into three parts namely control main, control read and control advanced as shown in figure (1). The control is the power source, read is the multimeter and advanced section is the wave generator.

Figure  (1): Screenshot of control section

Figure (1) shows the previous implementation of a multimeter i.e the read section but as we know this is way different than the actual implementation of a multimeter and thus from here comes the task of implementing a new multimeter.

What is a Multimeter, how does it looks?

A multimeter basically is an instrument designed to measure electric current, voltage, and usually resistance, typically over several ranges of value.

          Figure (2): Showing a real multimeter instrument and its different sections [2]

Figure(2) clearly shows how an actual multimeter looks. It basically has three important components i.e the display the buttons and the rotary knob or the dial and thus the task was to implement the same in PSLab android.

Implementation in PSLab

Figure (3) :  Screenshot of new implementation of multimeter

The implementation of multimeter is thus inspired from its original look i.e it has got basic buttons, a rotary knob and a display. Figure (3) shows the implementation of multimeter in the android-app

Back-end of Multimeter

A separate multimeter activity was implemented for the multimeter. The main back-end part of getting the resistance, capacitance, frequency and count pulse were taken from the communication related classes such as the ScienceLab class and PacketHandler class. For example to get the voltage calculation we use the getRawableVoltage function

private double getRawAverageVoltage(String channelName) {
  try {
      int chosa = this.calcCHOSA(channelName);
      mPacketHandler.sendByte(mCommandsProto.ADC);
      mPacketHandler.sendByte(mCommandsProto.GET_VOLTAGE_SUMMED);
      mPacketHandler.sendByte(chosa);
      int vSum = mPacketHandler.getVoltageSummation();
      mPacketHandler.getAcknowledgement();
      return vSum / 16.0;
  } catch (IOException | NullPointerException e) {
      e.printStackTrace();
      Log.e(TAG, "Error in getRawAverageVoltage");
  }
  return 0;
}

The above function shows the pure backend of PSLab and how data is taken from the hardware using the packet handler class, after which the data is processed in various other functions after we getting the final result. Similarly the function to get count pulse is

public int readPulseCount() {
 try {
  mPacketHandler.sendByte(mCommandsProto.COMMON);
  mPacketHandler.sendByte(mCommandsProto.FETCH_COUNT);
  int count = mPacketHandler.getVoltageSummation();
  mPacketHandler.getAcknowledgement();
  return 10 * count;
 } catch (IOException e) {
  e.printStackTrace();
 }
 return -1;
}

As we see that the data is being taken through a similar manner in the above function i.e using the packetHandler class(by sending and receiving bytes). Thus in all the other functions for capacitance, frequency similar communication model can be found.

Similarly all the functions are implemented in the ScienceLab class and thus all the functions are directly called from the ScienceLab class in the Multimeter activity. For more knowledge on these one can directly have a look at the PSLab android app codes available in Github.

Implementation of the Rotary Knob

The rotary knob is implemented using the BeppiMenozzi Knob library. More information regarding the same can be found in my previous blog on implementing the rotary knob.

Resources:

Continue ReadingImplementing Multimeter in PSLab Android App