I’m trying to finish up the PCBs for the boat this weekend and thought I’d share this little solution I thought was kind of neat.
Among other things, we need to measure the battery pack current, and fairly accurately This is mainly so the BMS can keep track of the approximate battery state of charge — i.e. percent charge remaining. To do this we need to measure the load current and the charger current all the time, and basically count coulombs in and out. ( There are some more sophisticated things you can do by doing calibration, tracking impedance and temperature but I don’t plan on doing any of that craziness for something like this. There are some cool state of charge ICs out there as well, and you actually calibrate them with the cell you’ll be using. Pretty cool. )
How to Measure Current
Anyway the basic idea is that you place a shunt resistor in the current path — this resistor will develop a little voltage across it in accordance with ohm’s law, and you can measure that voltage to get the current. You can use precision components for this, or you can always calibrate it. In my case I’ll be using precision stuff, mainly because I don’t want to have to worry about calibration.
Marine Grade Current Shunt
One thought I had was that I would simply measure the voltage drop across a couple large cables, and calibrate with a amp meter — more recently I discovered you can get a precision marine grade current shunt and I’ve opted to go with that.
If you run 200A though this bad boy you’ll get 50mV across the shunt, a whopping .25 mOhm of resistance. I don’t expect that much current typically but I that is the peak level I’d like to support. Btw, 48V * 200A is just about 10,000W, holy crap.
High Side or Low Side Current Measurement
The next choice you have is if you want to do “low side” or “high side” current measurement. If you do low side, that means the shunt resistor goes between ground and the load. This is generally easier to deal with because one side if the resistor is ground, and the other side of the resistor is a small voltage, which you can directly amplify with an om-amp and measure (with an ADC in my case).
However, having a resistor in the ground path can be undesirable for other reasons; so the other choose we have is is high side. With high side current measurement, the shunt resistor goes between the power (+V) and the load. One side of the shunt resistor therefore is the supply voltage (+V) and the other side is a little lower (V – I*Rshunt). You want to take the difference between these two voltages with an op-amp. The trouble is, typically these voltages are right at the same voltage as the op-amp, which probably isn’t going to work too well without a little thought. There are a number of ways to deal with this but the easy way is just to use a dedicated Current Amplifier IC. High Side current amplifiers generally let you measure shunt resistor voltages that are higher than the power supply you provide the IC.
I choose low side for a few reasons, but the main reason is that 48V is a pretty high voltage to try and connect to. It’s doable with some resistor dividers but let’s just say we don’t want to do that for now.
Measuring Current Direction
Another challenge with current sensing is that your application might allow the current to flow in both directions. In my case, the current can change direction as the load current goes above and below the charge current. (you could avoid this buy measuring each current individually, but let’s say we didn’t want to do this). This means that the voltage difference can swing negative.
Since we almost certainly aren’t running our op-amp (or ADC) with split rails (both positive voltage and negative voltage) we’ll need to add an voltage offset — such that the output voltage goes above or below the offset voltage depending in the current direction.
Negative Voltages at the Op-Amp Inputs
Another issue we’ll have to deal with is that depending on the current direction, the voltages coming in from the shunt will be negative with respect to our ground on the PCB. The way we’ll deal with this is to use an inverting op-amp configuration and force it to drive the inverting input to a positive voltage, or zero. In fact we can provide different offset voltages to each of the two inverting op-amps, thus introducing an offset in our output so we can support both positive and negative currents.
When running negative voltage into op-amps it’s important to make sure the op-amp inputs have clamping diodes so they don’t blow up between the time the negative voltage is applied and when it’s able to drive its input back positive. In addition there should be sufficient resistance in between the negative voltage source and the input, to keep the clamping current low. In our case it’s not a huge concern since the negative voltages are so small (~ -50mV).
I’d like to support a negative (charge) current of 40A — so when if/when I get more batteries (placed in parallel at the cell level) I can support the maximum charge rate the pack will accept.
So, when the current is zero, I want it to look like the current is 40A. The differential voltage from the current shunt goes between -10mV @ -40A to +50mV @ 200A, and this should result in an output voltage of 0V @ -40A and 1.2V @ 200A. Let’s see if we can’t figure this out without too much pain.
First of all, the gain. Basically we want 60mV full scale to become 1.235V full scale (I’m using a 1.235V ADC precision voltage reference), so the gain is about ~20.58. We’ll use a gain of 20.5 since we can get resistors for this.
One of the two inputs we’ll want to level shift up by 10mV so we get the full -40V (-10mV) to +200A (+50mV) range. We can use our 1.235V precision reference to create this tiny voltage, but note that in this configuration the op-amp is actually gaining our offset by two, so we’ll need to place 5mV at the non-inverting input.
Converting the ADC value to the current
Rather than to take great pains to make 1 bit equal to some perfectly round number of mA, I recommend just computing the overall gain/offset from the nominal values of the actual resistors used. Come up with a multiplier, a divider, and an offset. Assuming this is fairly high precision, it won’t fit in a 16-bit number, so opt for a 32-bit variable and burn some cpu cycles. Then you can have the result in exactly the unit you want.
Measuring Low Current at Higher Resolution
I was originally planning to use a 12-bit ADC built into a MSP430. With a 200A maximum current, that’s a resolution of about 50mA/bit. Not terrible, but not as precise as I would really like, since most of the time the system will be at far lower currents than 200A — it better be!
Since the bandwidth of this application is only ~100Hz, you could easily use a digital potentiometer or analog switches to change the resistor ratios for the gain. Analog switches would probably be better since you can use precision resistors. The parasitic capacitance of these parts typically makes them useless above, I don’t know — certainly 1 MHz generally speaking — but 100Hz is a great use case for them. Note that analog switches typically have on resistances that vary with the voltage at the switch; for something like this I would recommend avoiding that and using a maximally low R-ON part). Also note that you may need to use smaller value feedback resistors to prevent premature roll-off from the switch parasitics.
You could also use another op-amp to gain the signal even more, and use two different ADC inputs, switching to the most precise one that isn’t maxed out — of course check that the ADC will tolerate this. You could even control the ADC reference with a DAC, depending on how flexible the ADC’s reference range is. But that’s getting silly, in this application it would be more straightforward just to use a 16-bit ADC.
Maybe I’ll just use a 16-bit external ADC. I’m looking forward to seeing how that goes — I’ve never used anything that high resolution.
Quick Note on Resistor Thermal Noise
Since we might be going to a 16-bit ADC we might as well take a look at our thermal noise. To keep power consumption super low I generally like to use fairly large resistors for this low bandwidth stuff, on the order of 100K.
The voltage noise generated by each resistor is about .13 SQRT(R) at room temperature, in units of nV/SQRT(Hz). Without going into it, basically this describes the typical peak-to-peak voltage noise as a function of how much bandwidth we actually let though. The more bandwidth, the higher the typical voltage noise. In our case we’re only letting though 100Hz of bandwidth so we’re talking noise on the order of .13 * SQRT(100K) * SQRT(100) =411nV. 1.235V (our ADC reference) divided into 2^16-1 is 18.8uV/bit, or about 45x greater than the typical voltage noise on a 100K resistor. Moving down to a 10K resistor brings the ratio to 156x — I’ll do that since this isn’t exactly running from a watch battery :)
Quick Note on Op-Amp Input Offset Voltage
In the typical Op-Amp topology the output will drive the two inputs to be nearly the same voltage. However, due to how Op-Amps area actually implemented, the inputs will actually have a small amount of voltage error relative to each other — meaning that the Op-Amp may think the two voltages are the same but in reality they are off by a few mV. The difference between the voltage the Op-Amp sees on an input, and the actual voltage, is called the input offset voltage. The amount of this voltage error is bounded, but otherwise not predictable — it could be 0mV, -2mV, or 3mV for example – it has to do with the input transistors not quite matching or something like that. Anyway this is introduces a small amount of DC error into your signal path, and if the gain is high, the error could be fairly significant. In addition, the input offset voltage typically moves with temperature, so even if you calibrate the design it can easily drift if used at anything other than room temperature. Luckily, if this matters to you, they do make Op-Amps with extremely small input offset voltage errors — you’ll just pay more for them and it’ll limit which Op-Amps you can use.
I believe off-the-self current amplifiers typically have done something about the input offset voltage so you don’t have to worry about it.
In my case I’m using the extremely low input offset voltage Op-Amps such as OPA2188 or OPA376.
All for now. Thanks!
Update — Whoops!
One of the many consequences of not bothering to use the proper op-amp models is that it doesn’t care if it drives the output above or below the rail, or if the inputs go above or below the rail for that matter.
It just occurred to me that this inverting op-amps were going to try to output a negative voltage when the shunt inputs went positive, which they do when charging. The solution is simply to add an offset voltage to each one of the offsets to keep the outputs nice and positive. We can even use one three-resistor ladder to ensure that the offsets are 5mV off from each other.
Also, I should point out that this design pretty much requires precision resistors and super low input offset voltage op-amps.