Solar Cell Characterization (Workflow Comparison)

Solar or photovoltaic cells are devices that convert light energy into electric energy through the photovoltaic effect. Optimizing power conversion from solar cells is not trivial because of the shape of the I/V curve:




Parameters that define the I/V curve of a solar cell for a defined light condition are the short circuit current (Isc), the open circuit voltage (Voc) and the maximum power (Pmax), which is the power at Vmax voltage and Imax current.


I connected a small 6 V solar panel to the instrument to compare how these parameters can be measured through different workflows.





Front panel


Since the instrument keeps the last used settings, I will start with a setting that is more or less standard:


  • Voltage priority mode
  • Current limits: ±3 A
  • Programmable voltage: 20V
  • Readback voltage: 20V
  • Programmable current: 8A
  • Readback current: 10 A


The display with these settings looks like this:




To measure the Isc it is as simple as pressing the output button. The SMU sinks at 0 V and the the current value (5.49 mA) indicates the Isc.



To find the Vmax, Imax and Pmax, I pressed the voltage setting, and then the rotary knob to enter the voltage value.



Instead of entering a value, I pressed the rotary knob again and then used it to set each of the voltage digits. Rotating the knob changes the selected digit, while pressing it switches the selected digit to the next one. While doing this I kept an eye on the power indicator to make sure it increased until I reach its maximum value (Pmax). There, Pmax was 22.14 mW, Vmax was 5.78930 V and an Imax was 3.83 mA.



I could have measured Voc in an analog way by changing the voltage until the current reaches 0 A. That would have been probably the fastest way, but the current limit settings can also be used to find Voc. To do so, I pressed over the range settings, then I selected the programming current range to 10 mA, pressed the home button, and finally set the negative limit to 0, which the instruments sets automatically to -20uA (the minimum). The numbers then turned red as the SMU switched to constant voltage mode. The voltage output of 6.32423 V is the Voc.


Setting the programmed current to 10 mA could be omitted, but this would reduce the accuracy of the results. Setting the proper range could also have improved the measurement of Isc, Vmax, Imax and Pmax, but the impact there was much lower, so to keep things simple I did not bother doing that.



NGx Sweep Tool


Even though it is possible to perform a sweep using the front panel, this is a bit time consuming as it requires:

  1. Setting the sweep table.
  2. Enabling the arbitrary function generator (AFG) and loading the sweep table.
  3. Enable logging to log into a USB drive.
  4. Taking the USB drive from the SMU and plugging it into the computer.
  5. Load the measurements with a suitable application (i.e, Excel, a Python program, etc.)


A faster way to perform a quick measurement is with the Rhode & Schwarz's NGx sweep tool.


To use it I load it, and then I set the sweep parameters. I set a voltage sweep from 0 V to 7 V with 100 points (or steps), and the current limits from -3 A to 0.1 mA. The end behavior was set to off so that once the sweep is complete the SMU just cuts the output off. The pre-delay adds time for the control loop to stabilize before the aperture begins; I set it to 10 ms. The settling time adds time after the end of the aperture before the next step occurs; I set it to 1 ms. The aperture is the time where measurements take place; I set it to 20 ms. The time resolution, which is the inverse of the sampling rate, was set to 0.1 ms (10 ksps). Mains frequency was also properly set to reduce mains noise. Finally I set the current measurement range to 10 mA.


Then I pressed the Set button, and the tool uploaded the AFG function to the SMU.



Pressing "Start" initiated the sweep and showed the progress on a green bar.



As soon as the sweep finished, an I/V chart window appeared, and was able to explore the I/V curve.



Surprisingly the 0 V point was missing (the tool appears to miss the first value of the sweeps), to get that value I could rerun the sweep starting with a negative voltage, or just roughly estimate Isc from the plot (~5.4 mA). The graph can be zoomed in to find the Voc, but I consider the graph view more useful to get a rough estimate (i.e, I found its navigation not that simple), so here Voc appeared to be ~6.3 V.


From the graph view it is not possible to find Pmax, so I saved the trace points into a text file.



NGx Trace File
Voltage Current
1.60204e-001 -5.33334e-003
2.29694e-001 -5.31678e-003
2.99212e-001 -5.29695e-003
3.68671e-001 -5.27734e-003
4.38107e-001 -5.25550e-003
4.97842e-001 -5.23655e-003
5.67364e-001 -5.21488e-003
6.36860e-001 -5.19285e-003
7.06315e-001 -5.17287e-003
7.76771e-001 -5.15170e-003
8.47485e-001 -5.13287e-003
9.18192e-001 -5.11359e-003
9.88942e-001 -5.09609e-003
1.05964e+000 -5.07998e-003
1.13033e+000 -5.06393e-003
1.20110e+000 -5.04922e-003
1.27178e+000 -5.03425e-003
1.34250e+000 -5.02059e-003
1.41316e+000 -5.00809e-003
1.48396e+000 -4.99647e-003
1.55464e+000 -4.98544e-003
1.62534e+000 -4.97441e-003
1.69603e+000 -4.96476e-003
1.76679e+000 -4.95512e-003
1.83748e+000 -4.94659e-003
1.90816e+000 -4.93852e-003
1.97887e+000 -4.93119e-003
2.04966e+000 -4.92448e-003
2.12032e+000 -4.91823e-003
2.19103e+000 -4.91282e-003
2.26171e+000 -4.90758e-003
2.33248e+000 -4.90300e-003
2.40319e+000 -4.89865e-003
2.47386e+000 -4.89485e-003
2.54452e+000 -4.89128e-003
2.61533e+000 -4.88796e-003
2.68607e+000 -4.88493e-003
2.75670e+000 -4.88183e-003
2.82745e+000 -4.87859e-003
2.89823e+000 -4.87462e-003
2.96890e+000 -4.86951e-003
3.03962e+000 -4.86282e-003
3.11027e+000 -4.85367e-003
3.18105e+000 -4.84213e-003
3.25173e+000 -4.82873e-003
3.32243e+000 -4.81362e-003
3.39313e+000 -4.79765e-003
3.46390e+000 -4.77998e-003
3.53460e+000 -4.76231e-003
3.60526e+000 -4.74414e-003
3.67595e+000 -4.72598e-003
3.74675e+000 -4.70821e-003
3.81742e+000 -4.69119e-003
3.88809e+000 -4.67381e-003
3.95879e+000 -4.65736e-003
4.02958e+000 -4.64122e-003
4.10023e+000 -4.62644e-003
4.17094e+000 -4.61233e-003
4.24165e+000 -4.59946e-003
4.31241e+000 -4.58708e-003
4.38312e+000 -4.57527e-003
4.45378e+000 -4.56454e-003
4.52450e+000 -4.55419e-003
4.59524e+000 -4.54505e-003
4.66593e+000 -4.53644e-003
4.73666e+000 -4.52836e-003
4.80731e+000 -4.52078e-003
4.87811e+000 -4.51364e-003
4.94876e+000 -4.50707e-003
5.01945e+000 -4.50052e-003
5.09018e+000 -4.49464e-003
5.16094e+000 -4.48852e-003
5.23159e+000 -4.48276e-003
5.30231e+000 -4.47677e-003
5.37301e+000 -4.46961e-003
5.44366e+000 -4.45872e-003
5.51448e+000 -4.43960e-003
5.58517e+000 -4.40923e-003
5.65585e+000 -4.36160e-003
5.72653e+000 -4.28742e-003
5.79729e+000 -4.16967e-003
5.86794e+000 -3.98733e-003
5.93862e+000 -3.71717e-003
6.00939e+000 -3.33826e-003
6.08010e+000 -2.83538e-003
6.15077e+000 -2.19440e-003
6.22149e+000 -1.40044e-003
6.29225e+000 -4.35777e-004
6.33290e+000 2.02958e-004



Then I opened it with Excel, computed the power, and plotted the current and power (just as a data sanity check).



Here we can see that Pmax = ~24.7 mW, Vmax = ~5.66 V, and Imax = ~4.36 mA.



SCPI commands


SCPI commands give the highest flexibility and greatest control of the instrument. There are many alternatives to communicate to the instrument through SCPI commands, such as LabVIEW, C/C++ and Python. I decided to use Python mostly because I find it takes less development time, and I'm familiar with it. To communicate to the instrument Rhode & Schwarz provides a library called RsInstrument, but I sticked to PyVisa as I already have experience with it.


I wrote a program that works more or less like this:

  1. Connect to the instrument.
  2. Set the parameters.
  3. Perform a voltage sweep from 0 to 20 V at 0.01 V steps, and interrupt it as soon as the measured current turns positive (e.g, The instrument switches from sinking into sourcing).
  4. Take the recorded I/V points, find the solar panel parameters and print them to the screen.


To keep things simple here, I did not use the AFG or logger. At each step the voltage was set with the "SOUR:VOLT" command, and the voltage and current were read with the "READ?" command.



import pyvisa
import time
import numpy

# Settings

resource = 'tcpip0::'
step = 0.01

# Code

ngu = pyvisa.ResourceManager().open_resource(resource, timeout = 30_000)

ngu.write('*RST')                           # Reset instrument
ngu.write('SOUR:VOLT 0')                    # Set voltage to 0
ngu.write('SOUR:CURR:NEG -1')               # Set negative current limit to -1
ngu.write('SOUR:CURR MIN')                  # Set positive current to the minimum (0.001 mA)
ngu.write('SENS:VOLT:RANG:AUTO 1')          # Set voltage readback range to auto
ngu.write('SENS:CURR:RANG:AUTO 1')          # Set current readback range to auto
ngu.write('SENS:NPLC 1')                    # Set the number of power line cycles to 1
ngu.write('OUTP 1')                         # Turn on the output
ngu.query('*OPC?')                          # Wait for previous operations to complete

source = 0
data = []

while source <= 20:
    ngu.write('SOUR:VOLT {:f}'.format(source))    # Set voltage to the variable
    ngu.query('*OPC?')                            # Wait for previous operations to complete

    currentTime = time.time()

    query = ngu.query('READ?')                    # Read the voltage and current

    v, i = [float(x) for x in query.split(',')]
    data.append([v, i])
    if i > 0:

    source += step

ngu.write('OUTP 0')                         # Turn off the output

vi = numpy.array(data)
idx = numpy.argmax(-vi[:, 0] * vi[:, 1])

print('Voc  = {:.3f} V'.format(vi[-1, 0]))
print('Isc  = {:.3f} mA'.format(-vi[0, 1] * 1000.))
print('Vmax = {:.3f} V'.format(vi[idx, 0]))
print('Imax = {:.3f} mA'.format(-vi[idx, 1] * 1000.))
print('Pmax = {:.3f} mW'.format(-vi[idx, 0] * vi[idx, 1] * 1000.))



The execution produced the output:


Voc  = 6.359 V
Isc  = 5.235 mA
Vmax = 5.789 V
Imax = 3.569 mA
Pmax = 20.660 mW






As usual a single objective can be accomplished in different ways, nevertheless either method has its own advantages and disadvantages. So let me summarize what I would use depending on the situation.


If I need to make just a few measurements, and the instrument can provide the values that I need, such as voltage or current, I would just use the front panel. If want to get a rough view of the I/V curve of a component I would use the NGx tool, that even though it may have some glitches, they are being fixed. If I need to make repeated measurements, or if the measurements require synchronization with multiple instruments, or the data needs to be recorded, or analyzed in more complex ways, I would use SCPI commands. If I need some level of interactivity and a dashboard, I would use LabVIEW, while if I don't, I would use Python.