Say I have an 8-bit ADC and I oversample at such a rate as to obtain 2 additional bits. So, before I apply the low-pass filter, I need to append two extra bits to the 8-bit signal of the ADC. Do I append 00 or 10? Does it make any difference?
-
$\begingroup$ To be able to provide a helpful answer some addition information may be needed. Are you implementing this processing in fixed point, floating point, an FPGA, etc? $\endgroup$– GrapefruitIsAwesomeJul 30, 2022 at 14:27
-
$\begingroup$ @GrapefruitIsAwesome assume 10-bit fixed point. $\endgroup$– user110971Jul 30, 2022 at 14:28
-
$\begingroup$ 10-bit fixed point doesn’t give you anywhere near enough headroom bits for the intermediate results of the antialiasing filter MACs required for de-oversampling. So the real issue will be not how to add bits but how to shorten the much wider filter result to only 10 bits. $\endgroup$– hotpaw2Jul 31, 2022 at 7:49
1 Answer
The answer is -- neither.
If you have an $n$-bit ADC, then you can usefully oversample it if there's some noise either inside the ADC or before it that makes the average value of the ADC output equal to the actual thing being measured (this is the whole point of a Sigma-Delta ADC -- you intentionally build a circuit that makes that happen with a 1-bit ADC).
The key words there are average and value.
To profitably low-pass filter the output of an oversampled ADC so that you can decimate the result, you need to bit-extend the ADC output so that the value is retained. This is different for different ADCs. There's three common cases that I can think of, but if you include early telephone company experimentation, nearly 100 years for clever people to come up with all sorts of ways to make ADCs. So -- read the data sheet very carefully.
The three common ways to arrange an ADC are:
- Unipolar, where the ADC reads a voltage* from $0 \mathrm V$ to its $V_{ref}$, and gives an output from 'b00000000 to 'b11111111.
- Signed, where the ADC reads a voltage from $-V_{ref}$ to $+V_{ref}$, and gives an output of 'b10000000 for $-V_{ref}$, up through 'b00000000 for $0\mathrm V$, then to 'b01111111 for $+V_{ref}$.
- Offset signed, where the ADC reads a voltage from $-V_{ref}$ to $+V_{ref}$, and gives an output of 'b00000000 (note the leading bit is different) for $-V_{ref}$, up through 'b10000000 for $0\mathrm V$, then to 'b11111111 for $+V_{ref}$.
It is up to you to take these values and make them "right". There's efficient ways in C to deal with each of these cases (assuming that's what you're doing). Assuming you want a 16-bit integer, then under the hood you would extend these by:
- Unipolar: just make a longer word by setting the most significant bits to 0. I.e.
result = {'b00000000, raw_val}
.
- Signed: you need to sign extend the result. I.e.
if raw_val[bit 7] == 0 then result = {'b00000000, raw_val}.
if raw_val[bit 7] == 1 then result = {'b11111111, raw_val}.
- Offset signed: Convert like unipolar, then subtract:
result = {'b00000000, raw_val} - 'b0000000010000000
Then you would take the result and you would filter or average it in a way that preserves the least significant bits.
* Or some other quantity -- I'm just going to say "voltage" here.
-
$\begingroup$ I was thinking about the unipolar case with unsigned fixed point. However, don’t you need to set the least significant bits to zero? Adding two zeroes to the MSB will cut the output in 4. $\endgroup$ Jul 30, 2022 at 14:42
-
$\begingroup$ "Assuming you want a 16 bit integer" -- no, adding bits does not cut the output. It just adds more headroom. $\endgroup$ Jul 30, 2022 at 14:52
-
$\begingroup$ I suggest you re-read the part where I say that value is a key word. Any process that retains the value of the ADC will do -- don't get wrapped around the axle over what the bit pattern should be. Instead, grab a pencil and some paper and try things out. Eventually, you'll find a method that works. $\endgroup$ Jul 30, 2022 at 14:53
-
$\begingroup$ Thanks. I figured it out. I was confused about how to do it initially. $\endgroup$ Jul 31, 2022 at 8:03