Searching \ for '[EE] Accurate measurement of battery voltage' in subject line. ()
Help us get a faster server
FAQ page: www.piclist.com/techref/power/batterys.htm?key=battery
Search entire site for: 'Accurate measurement of battery voltage'.

Exact match. Not showing close matches.
'[EE] Accurate measurement of battery voltage'
2010\11\22@002008 by

Hi all,

I want to construct a simple device for plotting discharge curves for
batteries. I want to be able to measure voltage to the nearest
millivolt.

How would I go about doing this? Would an ADC on a PIC suffice
Not really.  10-bit ADC = 1024 steps, so you've got a ~1V range if each ADC step = 1mV.  Note that there is no guarantee of "nearest" millivolt with this setup.  And I assume you want to measure over the whole battery range, from full (whatever that is - you don't say and it is important, it could be anything from 1.2V to 12V) to zero (if higher than zero for "battery is dead stop measuring" is OK, that gives more design choices.)

You sure you need to a millivolt?  That seems like overkill, unless you're trying to do something special.  What's the application?

If say 2 or 5mV is good enough I think a simple circuit with a PIC can be made.  More details are needed.

J

V G wrote:
> Hi all,
>
> I want to construct a simple device for plotting discharge curves for
> batteries. I want to be able to measure voltage to the nearest
> millivolt.
>
> How would I go about doing this? Would an ADC on a PIC suffice
On 22/11/2010 05:19, V G wrote:
> Hi all,
>
> I want to construct a simple device for plotting discharge curves for
> batteries. I want to be able to measure voltage to the nearest
> millivolt.
>
> How would I go about doing this? Would an ADC on a PIC suffice?

It depends. Most PICs have a 10bit ADC so for say (if you use 5V full scale reference) 5V/1024 you are only getting around 4 mV resolution.
However, if you have a front end that only selects part of the voltage, (say 1V -> 1/1024 = ~1mV) that is of interest to you then you can achieve 1mV or higher. For instance, if the battery is at 3V, you can just monitor the 2.5-3.5 range using an opamp to amplify (and level shift if necessary) so the full range of the ADC is used, whatever that may be (of course you could set the ADC reference to 1V full scale too)
Implementing this and possibly needing some way of tracking/adjusting the "window" might be a pain though, depending on your requirements.
Having said that, there are plenty of cheap, high resolution, low speed ADCs out there that would provide a far higher resolution (likely better SNR etc than the onboard ADC too though I have not checked)
I would be tempted to go for something that provides the required resolution over the full range of the voltages you wish to measure, thus simplifying things a bit.
Microchip make 16 and 18 bit I2C Delta-Sigma ADCs for less than £2, so they may be worth considering, for say 5V, you get around a 80uV resolution (obviously you need a front end that is accurate/noise free enough to make use of this)
Something like this:
http://uk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6696098 <http://uk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6696098>

What kind of batteries do you want to measure?
How often do you want to sample and for how long?
How do you want the data to be stored/displayed? EEPROM/SD card? LCD? USB/Serial to PC?
> However, if you have a front end that only selects part of the voltage,
> (say 1V -> 1/1024 = ~1mV) that is of interest to you then you can
> achieve 1mV or higher. For instance, if the battery is at 3V, you can
> just monitor the 2.5-3.5 range using an opamp to amplify (and level
> shift if necessary) so the full range of the ADC is used

IIRC the absolute resolution of a 10-bit PIC ADC is 500uV (although
you may wish to consult Microchip AN1152, "Achieving Higher ADC
Resolution Using Oversampling")

Using an external 14- or 16-bit ADC would be a lot simpler than
tracking the battery with a Vref+/Vref- window to make the most of
the inherent 500uV granularity of the internal ADC, which I think
are mostly 10-bit or 12-bit but I've not researched that

Joe

*
*
**********
Quality PIC programmers
http://www.embedinc.com/products/index.ht
On 22/11/2010 05:19, V G wrote:
> Hi all,
>
> I want to construct a simple device for plotting discharge curves for
> batteries. I want to be able to measure voltage to the nearest
> millivolt.
>
> How would I go about doing this? Would an ADC on a PIC suffice?
You can get a quite cheap DVM with serial or USB and automatically fill up excel at a desired time interval. No idea what accuracy it is, but a PIC with 10bits is likely only  +/- 15mv to +/- 35mv on 10V range as the ADC is going to be +/- 1 bit , approx 10mV in 10V before reference and divider accuracy is considered
> I want to construct a simple device for plotting discharge curves for
> batteries. I want to be able to measure voltage to the nearest
> millivolt.
>
> How would I go about doing this? Would an ADC on a PIC suffice?

1. If you read "an ADC on a PIC" as "Typical PIC 10 bit ADC" then you
should be easily able to answer your own question with a "not if you
want to measure a range of more than 1 volt directly with the ADC
without extra magic" (and not even 1 volt range in real world
situations). .

2.  What they all said.

3.  You can get Sigma-Delta ADC's that offer 16 to 24 bit resolution.
You can get other faster devices that offer 12 to 16 to more depending on \$.. But

4. As several said, it is unlikely that 1 mV resolution is needed
unless you are doing something very very special or unusual.

For a 1 mV resolution  to be meaningful for most purposes you would
have to control charge/discharge currents closely and even
charge/discharge  profiles are going to alter the results more than
that.

What are you trying to achieve?.

It's likely that 10 mV resolution will be OK for most purposes and 25
mV for many. 50 mV is getting rather coarse in some situations.

The effects of temperature will utterly swamp 1 mV resolution.
Wiring drop too.
Currents as above.
Battery brand and model (even of same nominal capacity and chemistry.

Lithium chemistry batteries should ideally ne managed to within say 25
mV (hence my above comment on 50 mV being rather coarse).
eg a LiIon battery specified to plateau at 4.3 Volts REALLY doesn't
want to be at 4.3V, is better not at 4.25V and is probably tolerable
at 4.25V - but cell temperature will affect what's acceptable.

If you want to measure to 1 mV then your dividers etc need to be
accurate to better than 0.1% overall - either by trimming or
calibration. And need to retain stability better than that over
temperature and age and voltage.

ie you really need to know why uou need 1 mV - or if you do - or
better still, work out what you do need and THEN work backwards to see
what the measurement system must achieve to achieve your overall
system result.

So if eg 25 mV resolution overall is OK (likely)_ and if you never
measure more than 1 x LiIon cell (ie ~ 4.2V) as opposed to eg "12V"
lead acid, then you need 4200/25 ~= 168 levels or a bit under 8 bits
actual achievable resolution. So, a 10 bit ADC handle this if due care
was taken. You effectively "lose" one bit due to quantising noise and
you still have temperature drift, divider accuracy and more to cope
with, so 12 bits of honest ADC basic resolution would be a nicer
starting point.As a bonus that allows lead acid at say up to 15 V at
15V / 2^12 = 3.7 mV steps. ie 10 to 20 mV achievable maybe.

http://melabs.picbasic.com/Scripts/perl/picsearch.pl

12 bits

PIC18F2423
PIC18F2458
PIC18F2523
PIC18F2553
PIC18F4423
PIC18F4458
PIC18F4523
PIC18F4553
PIC18F6393
PIC18F6493
PIC18F6628
PIC18F6723
PIC18F8393
PIC18F8493
PIC18F8628
PIC18F8723
PIC18F8723

Russell McMaho
V G wrote:
> I want to construct a simple device for plotting discharge curves for
> batteries. I want to be able to measure voltage to the nearest
> millivolt.

So go ahead.  This is not hard.  Connect a resistor accross the battery and
measure voltage over time.  The current will be proportional to the voltage,
but you can still compute it.

Why do you need mV accuracy?  That seems excessive unless this is some
special lab experiment.  I've done a battery charger and maintainer with the
normal 10 bit A/D of a PIC and it had sufficient resolution for the purpose..

> How would I go about doing this? Would an ADC on a PIC suffice?

The A/D in a PIC should suffice for normal purposes.  If you really need 1mV
resolution (I suspect you probably don't), then you can:

1 - Use external circuitry to map just the full to empty battery voltage to
the full range of a PIC A/D.  NiMH cells go from about 1.3V full to 900mV
empty for a range of 400mV, so that would work in this case.

2 - Use a external high resolution A/D.  There are pleny out there that
communicate over IIC or SPI.  Since your signal is very slow, a sigma-delta
type sounds appropriate here.  You can get 20 bits or more, which is way
more than you need.  Microchip makes several sigma-delta A/Ds that would
work fine.

3 - Use a PIC with 12 bit instead of the more common 10 bit A/D.  Probably
used directly is good enough, but with proper choice of Vref you actually
get 1mV resolution.  There are PIC 18 and some dsPICs with 12 bit A/Ds.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
Oli Glaser wrote:
> of course you could set the ADC reference to 1V full scale too

No, you can't.  Not on most PICs anyway.  Not if you want the A/D to work
correctly and at full resolution.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
Hi all, thanks for the replies.

The purpose is to make a battery charger/discharger/cycler/profiler. I
want to be able to accurately detect end of charge and "almost dead"
states using delta V. Plotting discharge curves would also show true
battery capacity.

I ordered some Maxim samples of 14 bit ADCs, which should give
better-than-millivolt accuracy, but as everyone said,
noise/temperature/other stuff will make that accuracy irrelevant.

I'll just go ahead and use the 10 bit ADC on the PIC. Also cool since
the PIC has multiple ADC channels.

I'm going to be measuring NiMH voltages only, so around 0 - 1.5 volts
is an acceptable range per channel. Should give me far better accuracy
than I need

If you run the 10 bit A2D with external reference voltages of around
1.54 volts, you'll still get around
1.5mv resolution.
Regards,

Jim

> ---{Original Message removed}
V G wrote:
> The purpose is to make a battery charger/discharger/cycler/profiler. I
> want to be able to accurately detect end of charge and "almost dead"
> states using delta V. Plotting discharge curves would also show true
> battery capacity.

I did that a bunch of years ago as a one off project.  See
http://www.embedinc.com/pic/bat.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
jim@jpes.com wrote:
> If you run the 10 bit A2D with external reference voltages of around
> 1.54 volts, you'll still get around 1.5mv resolution.

No, you won't have any idea what the resolution is or even if the A/D will
function at all, at least for many PICs.  Some PICs may allow such a low
Vref, but without qualifying your statement to particular PICs it is just
morning.  You guys really need to start reading the datasheet.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
On 22/11/2010 13:30, Olin Lathrop wrote:
> Oli Glaser wrote:
>> of course you could set the ADC reference to 1V full scale too
> No, you can't.  Not on most PICs anyway.  Not if you want the A/D to work
> correctly and at full resolution.
>

You're right, I should have confirmed this was actually possible in practice - the specs say 2V minimum (between hi and lo ref, for full 10-bit resolution) for a couple of devices I checked.

>  If you run the 10 bit A2D with external reference voltages of around
> 1.54 volts, you'll still get around
>  1.5mv resolution.

For extra points (and headaches) mapping  only the top half of  tht
range onto the ADC takes you to better than the originally specified
nominal 1 mV, notionally at least.

Using a PIC with a 12 bit ADC is probably worthwhile.

Note that somebody mentioned dithering to get additional resolution.
Whether you also get extra accuracy depends on other factors. If you
add +/- ha;f a bot of gaussian noise it will sometimes move signal at
the intermediate point between 2 bits up or down so the ADC reads it
at one of two bit values. The ratio occurrences at value N or value
N+1 relate rto its actual distance between the two states. In practice
with somewhat random noise and good enough other components you can
get an extra bit or two this way and maybe more with luck and skill.

Simplistic example. If random noise is added to a signal and it reads
145 mV 60% of the time and 146 mV 40 % of the time then actual voltage
MAY be about 145.4 (not 145.6) mV. Take care when arttempting to apply
this magic. It does work, but ... .

Russell
RussellMc wrote:
> Simplistic example. If random noise is added to a signal and it reads
> 145 mV 60% of the time and 146 mV 40 % of the time then actual voltage
> MAY be about 145.4 (not 145.6) mV. Take care when arttempting to apply
> this magic. It does work, but ...

It's pretty easy to apply on the firmware end.  Just low pass filter

When you have the cycles and real time available, it's a good idea to
oversample with the A/D, then low pass filter in firmware anyway.  It gets
you a little extra resolution if the right kind of input noise is present as
you said, but it also reduces quantization noise and relaxes anti-aliasing
filtering requirements on the external hardware.

Fortunately a single pole low pass filter is easy to compute:

FILT <-- FILT + FF(NEW - FILT)

where FILT is the low pass filter being updated with input value NEW each
iteration.  FF is the "filter fraction".  FF = 1 is just a pass thru filter,
and FF = 0 is a infinitely heavy filter.  Useful values are obviously in
between.  In a small system with limited math capabilities, you often
arrange FF = 1/(2**N), so that the multiply by FF becomes a right shift by
N.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
I would normally implement such a filter as:

Total = Total + New - Filt
Filt = (Total+1) / Factor
And I usually  make Factor = 2^N so I can divide by right shifting.
This keeps everything as integers, and if you want the extra resolution, you can use Total.

Kerry

Olin Lathrop wrote:
{Quote hidden}

-- Internal Virus Database is out-of-date.
Checked by AVG Anti-Virus.
Version: 7.0.289 / Virus Database: 267.11.13 - Release Date: 10/6/05
Kerry Wentworth wrote:
>>   FILT <-- FILT + FF(NEW - FILT)
>>
>> where FILT is the low pass filter being updated with input value NEW
>> each iteration.  FF is the "filter fraction".  FF = 1 is just a pass
>> thru filter, and FF = 0 is a infinitely heavy filter.  Useful values
>> are obviously in between.  In a small system with limited math
>> capabilities, you often arrange FF = 1/(2**N), so that the multiply
>> by FF becomes a right shift by N.
>
> I would normally implement such a filter as:
>
> Total = Total + New - Filt
> Filt = (Total+1) / Factor

I'm not sure what exactly that results in, but it's not a single pole low
pass filter, otherwise known as a exponential decay.  The simple case of a
unit step input with N=1 proves that easily enough.  Your filter jumps to 1
in the first iteration, then stays there.  It also requires more computation
and more persistant state, so it's not clear what the advantage is.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
You could use an op amp to scale your input to the full range of your A/D.

http://www.electrotap.com/blog/495

DougM

On Tue, Nov 23, 2010 at 7:23 AM, Olin Lathrop <olin_piclistembedinc.com>wrote:

{Quote hidden}

>

> -----Original Message-----
> From: piclist-bouncesmit.edu [piclist-bouncesmit.edu] On
Behalf
> Of Olin Lathrop
> Sent: 23 November 2010 15:23
> To: Microcontroller discussion list - Public.
> Subject: Re: [EE] Accurate measurement of battery voltage
>
> Kerry Wentworth wrote:
> >>   FILT <-- FILT + FF(NEW - FILT)
> >>
> >> where FILT is the low pass filter being updated with input value
NEW
> >> each iteration.  FF is the "filter fraction".  FF = 1 is just a
pass
> >> thru filter, and FF = 0 is a infinitely heavy filter.  Useful
values
> >> are obviously in between.  In a small system with limited math
> >> capabilities, you often arrange FF = 1/(2**N), so that the multiply
> >> by FF becomes a right shift by N.
> >
> > I would normally implement such a filter as:
> >
> > Total = Total + New - Filt
> > Filt = (Total+1) / Factor
>
> I'm not sure what exactly that results in, but it's not a single pole
low
> pass filter, otherwise known as a exponential decay.  The simple case
of a
> unit step input with N=1 proves that easily enough.  Your filter jumps
to
> 1
> in the first iteration, then stays there.  It also requires more
> computation
> and more persistant state, so it's not clear what the advantage is.

Factor=2 causes the output to immediately jump to full scale with a unit
input, but after the input falls below 1 it does actually start working
as a filter.  It's better behaved with high values of 'Factor', though
it still has a glitch if the filter starts with an input of 0.
As you point out, it's difficult to see what the extra complexity buys
you.

Regards

Mike

=======================================================================
This e-mail is intended for the person it is addressed to only. The
information contained in it may be confidential and/or protected by
law. If you are not the intended recipient of this message, you must
not make any use of this information, or copy or show it to any
received this e-mail, and return the original to us. Any use,
forwarding, printing or copying of this message is strictly prohibited.
No part of this message can be considered a request for goods or
services.
=======================================================================
Michael Rigby-Jones wrote:
> As you point out, it's difficult to see what the extra complexity buys
> you.

It also appears to not be a linear system, which means whole bunch of off
the shelf analisys can't be applied.

I don't know what it is about digital filters, but everyone seems to be
expert even though most of them clearly didn't pay attention in digital
signal processing class.  It's OK not to know something, but then it would
be a good idea to refrain from dispensing advice on the subject.
I think you perhaps meant:

Filt=(Total)/Factor

In that case, I often use the structure you are talking about. It
allows you to do only one division for both the output computation and
the internal filter computation, while avoiding resolution issues with
fixed-point math.

For example, if we have a filter factor of 16, with Olin's example,
and using integer math, we have:

FILT<--FILT + (NEW-FILT)/16

If the absolute value of the difference NEW-FILT is less than 16,
nothing ever happens.

With Kerry's version:

Total<--Total+New-Filt

Any nonzero value of New-Filt causes a change in Total. To scale the
output, we just divide Total by 16 (filt=Total/16). However, that also
gives us the value Filt which we need in order to compute the filter's
difference equation, too.

Sean

On Tue, Nov 23, 2010 at 9:30 AM, Kerry Wentworth
<kwentworthskunkworksnh.com> wrote:
{Quote hidden}

>
It WAS a typo.  I actually meant Filt = (Total + (Factor/2)) / Factor, which rounds the number rather than truncates.  If truncating is good enough, then you can use Filt = Total / Factor.

Kerry

Sean Breheny wrote:
{Quote hidden}

-- Internal Virus Database is out-of-date.
Checked by AVG Anti-Virus.
Version: 7.0.289 / Virus Database: 267.11.13 - Release Date: 10/6/05
Sean Breheny wrote:
> For example, if we have a filter factor of 16, with Olin's example,
> and using integer math, we have:
>
> FILT<--FILT + (NEW-FILT)/16
>
> If the absolute value of the difference NEW-FILT is less than 16,
> nothing ever happens.

Right.  You generally want to use Log2 fraction bits to avoid this.

However, the other version doesn't give you a free lunch.  It looks like
TOTAL will float around the value times the same factor that you're dividing
by in the equation above.  That just means you're adding the bits on the

So you have to leave overflow bits on the left or add the same number of
fraction bits on the right.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
Olin Lathrop wrote:
> Sean Breheny wrote:
>
>> For example, if we have a filter factor of 16, with Olin's example,
>> and using integer math, we have:
>>
>> FILT<--FILT + (NEW-FILT)/16
>>
>> If the absolute value of the difference NEW-FILT is less than 16,
>> nothing ever happens.
>>
>
> Right.  You generally want to use Log2 fraction bits to avoid this.
>   Where are your fractional bits?  In Filt?  Are you doing floating point math?  If you are, converting to integer math without loss of resolution IS a 'free lunch'.
> However, the other version doesn't give you a free lunch.  It looks like
> TOTAL will float around the value times the same factor that you're dividing
> by in the equation above.  That just means you're adding the bits on the
> left instead of the right.
>   Yes, Total will float around that number.
Do you mean adding bits on the right instead of the left?  The fractional bits in mine are on the right side of the equation.  Am I getting confused?
> So you have to leave overflow bits on the left or add the same number of
> fraction bits on the right.
>
>
> ********************************************************************
> Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
> (978) 742-9014.  Gold level PIC consultants since 2000.
>
Kerry, fresh off the turnip truck

-- Internal Virus Database is out-of-date.
Checked by AVG Anti-Virus.
Version: 7.0.289 / Virus Database: 267.11.13 - Release Date: 10/6/05
>
> So go ahead.  This is not hard.  Connect a resistor accross the battery and
> measure voltage over time.  The current will be proportional to the voltage,
> but you can still compute it.
>

What have you done with Olin?
Kerry Wentworth wrote:
>> Right.  You generally want to use Log2 fraction bits to avoid this.
>
> Where are your fractional bits?

Where they ususally are, to the right of the binary point.

> In Filt?

In all the values.  Everything is a fixed point number with the specified
number of fraction bits.  To be clear, the algorithm I mentioned was:

FILT <-- FILT + FF(NEW - FILT)

NEW and FILT are expressed as fixed point values.  This is usually easy on a
PIC when NEW is successive A/D readings by using the left justify A/D result
mode.  For example, with the common 10 bit PIC A/D, you automatically get
each reading in 10.6 fixed point format in left justify mode.

The minimum number of fraction bits you need to not loose information
is -Log2(FF).  For example, if FF = 1/16, then you need 4 fraction bits.

In the other method that uses TOTAL, you still need the extra 4 bits but
they are on the high end of the number.  For example, if filtering 10 bit
values with FF = 1/16, then TOTAL needs to be 14 bits wide.  Note that TOTAL
then has exactly the same representation as FILT.  It makes no difference
whether you consider it in the scale of the original value with 4 fraction
bits, or in the scale of the original value times 16.  The bits inside the
processor are exactly the same.

The only real difference between these methods is that yours requires the
additional piece of persistant state, being the TOTAL accumulator.  You can
do some substitutions in your algorithm to reduce it to what I described
above.

> Are you doing floating point math?

You can, but this discussion was about fixed point.  There have been a few
cases where I've done that where I needed precise control over the time
constant or on the host computer with floating point hardware or where
cycles don't matter anyway.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
>> So go ahead.  This is not hard.  Connect a resistor accross the battery and
>> measure voltage over time.  The current will be proportional to the voltage,
>> but you can still compute it.

> What have you done with Olin?

Everyone has to have a 1/bad day occasionally.

R
OK, I think I see it.  My Total is your Filt, except Total is right justified, and Filt is left justified.  Both contain 14 significant bits (assuming N=16).

My Filt is the Total (or your Filt) right justified and truncated (or rounded) to 10 bits, to give a filtered A/D between 0 and 1023.  This step is optional, if one wanted the 14 bit number, one could skip the conversion.

And your FF(NEW - FILT) is really (NEW - FILT) / FF.

Is this correct?

Kerry

Olin Lathrop wrote:
{Quote hidden}

-- Internal Virus Database is out-of-date.
Checked by AVG Anti-Virus.
Version: 7.0.289 / Virus Database: 267.11.13 - Release Date: 10/6/05
Kerry Wentworth wrote:
> My Filt is the Total (or your Filt) right justified and truncated (or
> rounded) to 10 bits, to give a filtered A/D between 0 and 1023.

Yes.

> This step is optional, if one wanted the 14 bit number, one could
> skip the conversion.

No, not with your algorithm, since it requires your FILT in a previous step..

It is optional in the normal method that I described.  You can convert to
the original integer scale when you want, but are not forced to do so each
iteration.  More likely, you adjust the scale factors in the rest of the
system so no conversion is ever required.  Usually the A/D values are in
some arbitrary scale, so having values in that scale times 2**N is no
different in that it's just as arbitrary.

> And your FF(NEW - FILT) is really (NEW - FILT) / FF.
> Is this correct?

Clearly not if FF can take on values other than 1, which of course it can.
As I said before, useful values for FF are between 0 and 1.  For easy
implementation on small systems, FF = 2**-N since the multiply by FF then
becomes a right shift by N.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
Do you have a math library of some sort to do 10.6 arithmetic?

For example, a 1/2 scale left justified A/D reading would be

1000 0000 00.00 0000
and 1/16 would be
0000 0000 00.00 0100
The desired result is 0000 1000 00.00 0000
Doing a binary multiply would result in a value of 0.
On the other hand, a 1/2 scale right justified A/D reading would be
0000 0010 00.00 0000
And doing a binary multiply by 1/16 would result in a value of
0000 1000 00.00 0000
which is correct.

Please pardon my ignorance, I'm here to learn.  Is 10.6 arithmetic something that everybody but me uses?  Is it an assembly language thing?  I use a C compiler almost exclusively.

Kerry

Olin Lathrop wrote:
{Quote hidden}

-- Internal Virus Database is out-of-date.
Checked by AVG Anti-Virus.
Version: 7.0.289 / Virus Database: 267.11.13 - Release Date: 10/6/05
So, this might be a good time to recap.

Method 1:

FILT <-- FILT + FF(NEW - FILT)

Method 2:

Total = Total + New - Filt
Filt = Total / Factor

The difference is in the format of the answer, binary vs. 10.6, and one extra variable in method 2 which holds the filtered value in 10 bit binary format.

Is that a fair assessment?

Kerry

Olin Lathrop wrote:
{Quote hidden}

-- Internal Virus Database is out-of-date.
Checked by AVG Anti-Virus.
Version: 7.0.289 / Virus Database: 267.11.13 - Release Date: 10/6/05
Kerry Wentworth wrote:
> Do you have a math library of some sort to do 10.6 arithmetic?

Not specifically.  I do have various 32 bit math routines for PICs.

The advantage of fixed point is that for much of the processing you can
treat the numbers as integers.  The machine just does the add, only you know
that you consider the least significant 6 bits to be fraction bits.

> For example, a 1/2 scale left justified A/D reading would be
>
> 1000 0000 00.00 0000
> and 1/16 would be
> 0000 0000 00.00 0100

Yes.

> The desired result is 0000 1000 00.00 0000

Assuming you want to multiply the two numbers, which you didn't say.

> Doing a binary multiply would result in a value of 0.

No.  I don't see how you get that no matter how you think multiply works.

If you just multiply fixed point numbers together as if they were integers,
then the result has the total number of fraction bits in both the input
numbers, which in this example is 12.  The result of a straight integer
multiply without any prescaling would be:

1000000000.000000
x 0000000000.000100
-------------------
00000000100000000000.000000000000

Again, the fact that you consider these numbers to have a binary point
somewhere in the middle is totally on your end.  The processor just does
integer arithmetic.

> On the other hand, a 1/2 scale right justified A/D reading would be
> 0000 0010 00.00 0000

That doesn't make sense.  If you are using right justified A/D readings,
then they would be integers.  I don't see where the fraction bits are
supposed to come from in this case.

> Please pardon my ignorance, I'm here to learn.  Is 10.6 arithmetic
> something that everybody but me uses?  Is it an assembly language
> thing?

Fixed point in general is commonly used on small systems like PICs.  10.6
format is just one example, which has 6 fraction bits in a 16 bit number.
Fixed point is common when you need to represent fractional values but have
a integer arithmetic processor.  It's more tricky than floating point
because you have to keep track of where the imagined binary point is.

One way to think of floating point is that it stores the binary point
information in the number, and updates everything accordingly at run time.
That takes more hardware, which small processors like PICs don't have.

> I use a C compiler almost exclusively.

There's the problem.  Wake up and smell the bits.  It is difficult to
understand what is really going on if you keep a compiler between you and
what is really going on.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
On 24/11/2010 16:22, Olin Lathrop wrote:
{Quote hidden}

Other common option are 8.8 if only 8 bit "final" values are needed, as then the higher byte is the Integer.

The compiler is irrelevant.

You are just using 16 bit integers.
You only have to think about the dp location after a multiply. Since an Integer multiplication results in twice the bits on answer, you have to think about that anyway. (maybe in C cast the input values to 32bits from 16bit sized type before you multiply or it will overflow).

Where the DP is placed is application dependent. All the existing Integer libraries work. You just may rescale by packing or dropping a byte, or Left or right shifts before calling the existing math routines or after calling them.

Maths done with paper and pen of currency is example of fixed point integer. Infact most long hand on paper fixed decimal length maths is not Floating point but simply Integer. It's really nothing magical, but pre-calculator Primary School maths.
So, your Filt is a 32 bit number in 20.12 format?  Odd that you didn't mention that before.  Is there any chance of you providing a snippet of code that implements your version of the filter?

Kerry

Olin Lathrop wrote:
{Quote hidden}

-- Internal Virus Database is out-of-date.
Checked by AVG Anti-Virus.
Version: 7.0.289 / Virus Database: 267.11.13 - Release Date: 10/6/05
Kerry Wentworth wrote:
{Quote hidden}

Yes.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
Kerry Wentworth wrote:
> So, your Filt is a 32 bit number in 20.12 format?  Odd that you didn't
> mention that before.

As I said several times now already, FILT has -Log2(FF) extra fraction bits..
When FF = 1/16, you only need 4 fraction bits, but since bits come in chunks
of 8, it's OK to use 6 fraction bits out of a 16 bit number if the integer
part only needs 10 bits.

Sometimes I do use wider values for the filters.  As you should be able to
see by now, it all depends on FF.  Multiple filters chained together also
require more bits if you want to represent every last bit of detail in the
original value.  Often that is not necessary.  Just because the math can
provide the filtered value to one part in 2**30, it doesn't mean it's useful
and you therefore don't have to bother computing to that accuracy.

> Is there any chance of you providing a snippet of
> code that implements your version of the filter?

Look around, there's bound to be stuff out there.  It's not "my" filter.  I
was just describing the basic one pole low pass digital filter people have
been using since the first bits were invented.  I've implemented filters
based on that principal many times, both on PICs and in host software.  Some
of it is probably out there somewhere, but I can't think of specific code
right now.

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
> > On the other hand, a 1/2 scale right justified A/D reading would be
> > 0000 0010 00.00 0000
>
> That doesn't make sense.  If you are using right justified A/D
> then they would be integers.  I don't see where the fraction bits are
> supposed to come from in this case.

Part of the problem that I see (and it doesn't matter if he uses a C
compiler or anything else) is that Olin didn't explain himself properly
in the first place. His 10.6 is 10 bits of binary mantissa and 6 bits of
binary fraction, but his arithmetic is only ever done as adds, subtracts
and shifts. But Kerry appears to be thinking of this 10.6 as being like
an IEEE 754 or similar floating point representation, and doing math on
it as though it is an ordinary decimal number, so doing a divide is not
being properly done.
In your example Kerry, if the full scale is 1000 0000 00.00 0000, then a
1/2 scale reading is 0100 0000 00.00 0000
i.e. divide by 2, or a 1 bit right shift.
-- Scanned by iCritical.
Actually, a full scale A/D reading in left justified 10.6 format is 1111111111.000000, in binary, 0000001111111111, or decimal 1023.
For a half scale reading (i.e. 2.5V on a 5V reference) would be either 1000000000.000000 or 0111111111.000000, in binary 0000001000000000 or 0000000111111111, or decimal 511 or 512.  When you read the A/D result registers in a PIC, you can choose which format you get.

In 10.6 math, there is an imaginary decimal point between bits 5 and 6.  Bit 6 has a value of 1, bit 7 is 2, bit 8 is 4, etc.
Bit 5 would have a value of 1/2, bit 4 is 1/4, bit 3 is 1/8, bit 2 is 1/16, bit 1 is 1/32 and bit 0 is 1/64.

Now let's say we are implementing Olin's filter, and want to multiply our A/D reading by 1/16.
1/16 has bit 4 set, and all others cleared, so it is 0000000000.000100, which is a binary 4.
when we multiply 0111111111.000000 by 0000000000.000100 we get
0000 0000 0000 0001 1111.1111 0000 0000, which is too large to fit into 16 bits, and so becomes a 32 bit bit number, in 20.12 format.  But the last 6 bits will always be 0, so we don't really need them.  Without them, the number would fit into 16 bits, and in fact would fit into the 10.6 format.  We could do that by right shifting 6 times and taking the lowest 16 bits.  We would end up with 0000 0111 11.11 1100.  The end result off all of this is that we took a number, multiplied it by 4 then divided it by 64.

Reading the A/D in right justified mode results in a number that is already right shifted by 6 bits (i.e. divided by 64), so taking our reading as 0000000111111111 and multiplying by 0000000000000100 would give us
0000 0111 11.11 1100, which will fit into a 16 bit number without overflow, and is in fact in 10.6 format, with the fractional bits right where they oughta be, without ever needing a 32 bit variable.

Kerry

alan.b.pearcestfc.ac.uk wrote:
{Quote hidden}

-- Internal Virus Database is out-of-date.
Checked by AVG Anti-Virus.
Version: 7.0.289 / Virus Database: 267.11.13 - Release Date: 10/6/05
Kerry Wentworth wrote:
{Quote hidden}

Did I miss a point you were trying to make somewhere in there, a question,
or are you just saying out loud what you think you understand to try to make
more sense of it?

********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000
> Kerry Wentworth wrote:
> > Actually, a full scale A/D reading in left justified 10.6 format is
> > 1111111111.000000, in binary, 0000001111111111, or decimal 1023.
> > For a half scale reading (i.e. 2.5V on a 5V reference) would be
either
> > 1000000000.000000 or 0111111111.000000, in binary 0000001000000000
or
> > 0000000111111111, or decimal 511 or 512.  When you read the A/D
result
> > registers in a PIC, you can choose which format you get.
> >
....
>
> Did I miss a point you were trying to make somewhere in there, a
question,
> or are you just saying out loud what you think you understand to try
to make
> more sense of it?

Well, he was replying to my post, which he had quoted at the bottom.
-- Scanned by iCritical.
Olin Lathrop wrote:

{Quote hidden}

I disagree that using a C compiler is a problem. IMO the difficulty in
understanding fixed point math is about the same either way. (IMO it's
actually easier in C, because you're less sidetracked by other issues.)
IMO it is also not about smelling the bits, it is about understanding
the principle, and you don't even need a processor for this, whether
programming it in assembly or C; a sheet of paper (and a head) is all
you need.

I think the (one) key to understanding fixed-point math is to understand
units. Most are used to deal with numbers and not consider units, or
consider them only at the output, where the units appear like magic. IMO
this is generally not a good idea, but the absence of units makes itself
most notable when dealing with fixed-point math. Just pin an appropriate
unit to each number, and it all will solve itself. The units of course
usually contain a scaling factor, and you need to carry units through
operations properly.

In the simplest case -- and this is enough to understand fixed-point
math --, the unit is just a scaling factor. Say you have numbers with 4
(binary) digits to the right of the binary point, then their unit is
[1/16]. Adding two such numbers leaves the unit [1/16], using simple
math rules:

(A * [1/16]) + (B * [1/16]) = (A + B) * [1/16];

The operation (A + B) is done by the processor, the rest happens on your
sheet of paper.

Multiplying two such numbers makes the unit of the result [1/16] *
[1/16] = [1/256], again using the same simple math rules:

(A * [1/16]) * (B * [1/16]) = (A * B) * ([1/16] * [1/16])                             = (A * B) * [1/256];

The operation (A * B) is done by the processor, the rest is implicit in
the design of the algorithm.

Now if for some reason you need the result with a unit of [1/16], you
know what to do... you need to divide by 16:

C * [1/256] = C/16 * [1/16];

Brining the last two calculations together, the complete multiplication
of two numbers with the unit [1/16] resulting in a number with a unit of
[1/16] becomes:

(A * [1/16]) * (B * [1/16]) = (A * B / 16) * [1/16];

(A, B and C are integer variables of any suitable size.)

This could get you started. Just carry always the unit along, helpfully
marked with e.g. brackets "[]", when you design your algorithm, and the
actual arithmetic will all be integer and you won't even know that
you're doing fixed-point math -- until you see that it's exactly this
what it is :)  The advantage of this approach is that it all reduces to
simple math that can be easily executed on a sheet of paper, no magic
with smelling bits and dead chickens necessary.

Gerhar

More... (looser matching)
- Last day of these posts
- In 2010 , 2011 only
- Today
- New search...