Supercap evaluation

Recently I have been exploring the possibility of powering projects with solar and a supercap, followed by a 3.3volt micro-power boost converter.
I already had 100F Samwha GreenCaps, but I needed to bridge longer after dark/rainy days, so I ordered a 10-pack of 500F Samwha GreenCaps from ebay.
Most of them lasted shorter than the 100F caps I already had.
Wanted to understand, so I added some resistors on top of an Uno and wrote a sketch to test leakage (which can be significant) and value of the caps.
Disapponting results (some tested as low as 50F), until I got some 400F AVX caps.
They had lower leakage than any of the Samwha caps, and were close to their rated value.
Sketch attached, so you can try yourself.

Charging and soak times mimic real-world solar charging, not the unrealistic (72-hour) leak test from the datasheets.

For consistent (leakage) results you should pre-charge the cap to 1volt on a power supply for a day.
Or run the test the next day (the end of the sketch leaves the cap at ~1volt).
Leo..

/* Arduino Uno
  12x 330 ohm from pin 2-13 to a star point
  330 ohm from A0 to star point
  6k8 between Aref pin and 3.3volt pin, to create a 2.7volt Aref, ! measure it !
  1N4004 diode (protection) between star point and 5volt, cathode (ring) to 5volt
  supercap connected to star point (+) and two ground pins (-)
*/
const float Aref = 2.71;
const unsigned long soakDuration = 10800000; // milliseconds (3 hours)
const unsigned long selfDischargeDuration = 14400000; // (4 hours)
const unsigned long interval = 300000; // minimum interval (5 minutes)
const byte firstPin = 2, lastPin = 13, measurePin = A0; // 12 charge/discharge pins
unsigned long startMillis, stopMillis, voltMillis, soakMillis; // timing
float volt, prevVolt, leakage, capValue, capCal = 0.000048; // calibration factor

void voltage() { // print periodically while waiting
  if (millis() - voltMillis > interval) {
    volt = trunc(analogRead(measurePin) * Aref / 1024 * 100) / 100; // truncated to two decimal places
    if (volt != prevVolt) { // only print changes
      Serial.print(volt);
      Serial.println(" volt");
      prevVolt = volt;
    }
    voltMillis = millis();
  }
}
void charge() {
  for (byte i = firstPin; i <= lastPin; i++) {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH);
  }
}
void discharge() {
  for (byte i = firstPin; i <= lastPin; i++) {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }
}
void floating() {
  for (byte i = firstPin; i <= lastPin; i++) {
    pinMode(i, INPUT);
    digitalWrite(i, LOW); // make sure pull up is off
  }
}

void setup() {
  Serial.begin(9600);
  analogReference(EXTERNAL); // switch to 2.7 volt Aref
  if (analogRead(measurePin) == 1023) Serial.println(F("Connect cap\n"));
  while (analogRead(measurePin) == 1023);
  Serial.println(F("Supercapacitor evaluation"));
  for (byte i = 0; i < 25; i++) Serial.print(F("="));
  Serial.print(F("\nSelf-discharge and value test\nInitial charge: "));
  delay(5000); // time to properly connect cap
  Serial.print(analogRead(measurePin) * Aref / 1024);
  voltMillis = millis();
  Serial.println(F(" volt\nCharging to 2.7 volt"));
  charge();
  while (analogRead(measurePin) < 1023) voltage();
  Serial.println(F("Timed hold at 2.7 volt"));
  soakMillis = millis(); // mark
  while (millis() - soakMillis < soakDuration) {
    if (analogRead(measurePin) < 1023) charge();
    else floating();
    voltage();
  }
  floating();
  Serial.println(F("Self-discharge test"));
  soakMillis = millis(); // mark
  while (millis() - soakMillis < selfDischargeDuration) voltage();
  Serial.print(F("Self-discharge: "));
  leakage = ((1023 - analogRead(measurePin)) * Aref / 1024) / (selfDischargeDuration / 1000000000.); // (dV / dt)
  Serial.print(leakage, 1);
  Serial.println(F(" uA/F (should be ≤2.5uA/F)"));
  if (analogRead(measurePin) < 2.2 * 1024 / Aref) {
    Serial.println("Excessive leakage\nRe-charging to 2.2volt");
    charge();
    while (analogRead(measurePin) < 2.2 * 1024 / Aref) voltage();
  }
  Serial.println(F("Value test\nDischarging to 1 volt"));
  discharge();
  while (analogRead(measurePin) > 2 * 1024 / Aref) voltage();
  startMillis = millis(); // 2 volt mark
  Serial.println(F("Measurement startpoint"));
  while (analogRead(measurePin) > 1024 / Aref) voltage();
  stopMillis = millis(); // 1 volt mark
  floating();
  capValue = (stopMillis - startMillis) * capCal;
  for (byte i = 0; i < 33; i++) Serial.print(F("="));
  Serial.print(F("\nCapacitor value: "));
  Serial.print(capValue, 0);
  Serial.print(F(" Farad\nSelf-discharge: "));
  Serial.print(leakage, 1);
  Serial.print(F(" uA/F\nCapacitor self-discharge: "));
  Serial.print(leakage * capValue, 0);
  Serial.println(F(" uA"));
  for (byte i = 0; i < 33; i++) Serial.print(F("="));
  Serial.println("");
}

void loop() {
}
1 Like

Could those poor 500F caps be rejects, bad samples rejected in tests and then sold on ebay? Reports similar to that like repurposed electronic components are coming from China made, or handled electronics. Power rating is also way too high now and then. A metric, or Imperial Amp is doubled when using Chinese Amps...

1 Like

What would one expect for that type of cap, purchased from a reputable source?

1 Like

I've never used a supercap but capacitors make lousy batteries because the discharge curve is the opposite of an "ideal battery".

1 Like

Yep, most likely rejects.
Very damaging to a brand name if they don't destroy but dump the rejects on the black market.

I didn't expect the full 500F, and maybe a higher leakage, but these were seriously under-rated.
Still measuring, but most of them are about 100F, but with the leakage of a 500-1000F cap.
(they should leak less than 2.5uA per Farad)

There are some advantages over batteries. Potentially longer life (10-30 year), almost infinite number of charges/discharges, and low internal resistance. But indeed, you must use a boost converter to use them with electronic circuits. The NCP1402 is ideal, but no longer manufactured.
Leo..