Searching \ for 'Pic A/D sampling a biased sine wave' in subject line. ()
Help us get a faster server
FAQ page: massmind.org/techref/microchip/math/index.htm?key=sine
Search entire site for: 'Pic A/D sampling a biased sine wave'.

Truncated match.
'Pic A/D sampling a biased sine wave'
2000\02\18@064824 by

I need to (hopefully) use the 16F876 to sample a sine wave that rides on a
1.75v reference line, swinging from 0v to 3.5v but before I even attempt
this, I'm thinking it won't work because if an average value of the sine
wave is what's taken over time, then wouldn't I always get a reading
somewhere near that 1.75v reference line?

Assuming a maximum swing signal, if a peak is measured in one instance in
time at 3.5v, and then a trough is measured the next time at 0v, and then
the middle of the signal is measured at 1.75v, the average of the 3 samples
is 1.75v.

What would be a proper method to sample a biased "ac" signal?  Considering
that the maximum voltage is 3.5v, I have ruled out the idea of rectifying
the signal or something unless I can use a semiconductor junction that
doesn't drop very much of that valuable signal level.  I also considered
looking into peak detectors.  I don't know off hand what they really do but
if they can be used to sort of sample and hold the most positive peaks of
this sine wave, I could sample from that and then just compensate in
software for the bias level to get a peak reading from the reference 1.75v.

What other options are there?

Lorick wrote:
{Quote hidden}

Depending on how fast and/or noisy the signal is and what response time you
need, you may be able to sample with the A/D and take the max and min of
your samples over a given interval.  Then (max - min) would give your
peak-to-peak voltage.  Just be sure that you are sampling at a rate or phase
that catches the peaks (sample much faster than the signal or phase-lock to
it so that you can align your samples with the peaks).

If you do phase-lock to the signal, you could take the average of the
samples aligned with the peaks minus the average of the samples aligned with
the troughs and thus reject noise much better (than taking max and min).
Phase lock can be accomplished by also sampling at the zero crossings and
using the difference between the two zero crossing points (rising edge and
falling edge) as an error control signal for the loop.  I used this
technique to lock to the 60kHz WWVB carrier for a direct-sampling WWVB
receiver I designed a few years ago based on a 16C73.  It worked like a
charm and could measure the carrier amplitude with a lot more precision than
one might expect given an 8-bit A/D (the signal can bias the noise and
produce a clearly measureable difference in the average even when the signal
itself is smaller than one LSB worth of voltage on the A/D input).  To get a
high degree of precision with a noisy signal you will also need to apply a
time-domain windowing function (like the windowing functions used for FFTs
and serving exactly the same purpose).  The only practical windowing
function to use with fast signals on a PIC (because it can be done with a
coupple of running sums and thus avoid time-consuming multiplications) is
the triangle window.  But that's probably more than you needed to know ...

Anyway, there are lots of ways to measure the amplitude of a sinusoid with a
PIC.  The most appropriate method depends on how fast your signal is, how
fast you want to measure its amplitude, how noisy it is, how much frequency
modulation it has, how much precision you need, how much code (or hardware)
you are willing to devote to the task, etc.

Cheers,

Ken

<x-flowed>At 06:47 AM 2/18/00 -0500, Lorick wrote:
>I need to (hopefully) use the 16F876 to sample a sine wave that rides on a
>1.75v reference line, swinging from 0v to 3.5v but before I even attempt
>this, I'm thinking it won't work because if an average value of the sine
>wave is what's taken over time, then wouldn't I always get a reading
>somewhere near that 1.75v reference line?

It's not clear what you are doing here. Is this supposed to be a simple RMS
measurement, or you need details of the sine wave?

In the latter case, you seem to be assuming the mean value (DC component)
the problem?

If you simply want to determine the average DC level, that's easy: just use
a low-pass digital filter. Even a simple moving-average will work fine.
What are the performance requirements?

If you need a 'rectified' signal, do it in software: record and analyze
samples separately for above and below 1.75 V. To rectify, difference from
1.75 V and flip the sign.

If you're worried about clipping at 0 V, add a 'bias' with an op-amp summer
before sampling.

================================================================
Robert A. LaBudde, PhD, PAS, Dpl. ACAFS  e-mail: rallcfltd.com
Least Cost Formulations, Ltd.                   URL: http://lcfltd.com/
824 Timberlake Drive                            Tel: 757-467-0954
Virginia Beach, VA 23464-3239                   Fax: 757-467-2947

"Vere scire est per causae scire"
================================================================

</x-flowed>
Hi Lorick, are you trying to measure the voltage? Assuming you can sample
at many times the actual frequency (like 30), then something like this
might work:

int peak, trough;                       // averages are here

// call for each sample taken
void process(int sample)
{
static int prior, rising;             // stuff to remember

if (sample > prior)                   // voltage is rising
{
if (!rising)                        // was it before?
{
rising = 1;                       // no, note it is now
trough += (prior-trough)/k;       // prior sample is trough
}
}
else                                  // else, voltage is falling
if (rising)                           // was it before?
{
rising = 0;                         // no, note it is now
peak += (prior-peak)/k;             // prior sample is peak
}

prior = sample;                       // remember prior sample
}

Hope this looks all pretty on your screen like it does on mine -- tabs
suck.

The 'peak += (sample-peak)/k' thing is the magic, it works exactly like an
RC filter. k is adjusted for your sample rate and jitter, noise floor,
etc., I'd start with 16 (rrf rrf rrf rrf, somebody let the dog out).

Anyway, peak voltage is (peak-trough)/2, don't trust no stinkin' DC bias
or the A/D either.

No doubt there's a better way, and hopefully someone will post it here so
I can swipe it.

-- Rich

On Fri, 18 Feb 2000, Lorick wrote:

{Quote hidden}

> It's not clear what you are doing here. Is this supposed to be a simple
RMS
> measurement, or you need details of the sine wave?
>
> In the latter case, you seem to be assuming the mean value (DC component)
> the problem?

I'm not actually sure if I would be looking to make measurements of the
peaks or if an rms reading would be fine, but what I meant by 1.75v average
is that since that is the bias level, if I accidently took successive
readings at the peaks and troughs instead of just at all the peaks, the
overall average would look like 1.75v which would be wrong, it would be the
"0" level of the signal...
I am assuming that what I am after is a way to measure the peaks but here is
the whole description if it will help.
The signal I am working with is from an electret condenser microphone that
will be picking up a definite 1KHz audio signal from some test oscillator
circuit and speaker.  I am interested in detecting the volume level of the
sound source so that I can tell how far away it is based on how strong the
signal is.  The mic output will be signal conditioned to swing from 0 to
3.5v (working from single supply op amps) and I will be reading this volume
level with the a/d and I was trying to fiure out how the a/d would perceive
the audio.  If it reads a level of 2v, how would it know if this is a
maximum of the current waveform, or if it's the normalized zero crossing
point, thus it should be interpreted as zero instead of two in terms of
amplitude.
The pic is being run at 4MHz so far but that's just arbitrary, so I am
assuming this means I can sample WAY above the 1KHz signal frequency.  Now I
need to know exactly what it is I should be looking for to get the "volume"
level of the signal...

part 0 2603 bytes
<P><FONT SIZE=2 FACE="Arial">I need to (hopefully) use the 16F876 to sample a sine wave that rides on a</FONT>
<BR><FONT SIZE=2 FACE="Arial">1.75v reference line, swinging from 0v to 3.5v but before I even attempt</FONT>
<BR><FONT SIZE=2 FACE="Arial">this, I'm thinking it won't work because if an average value of the sine</FONT>
<BR><FONT SIZE=2 FACE="Arial">wave is what's taken over time, then wouldn't I always get a reading</FONT>
<BR><FONT SIZE=2 FACE="Arial">somewhere near that 1.75v reference line?</FONT>
</P>

<P><FONT SIZE=2 FACE="Arial">Assuming a maximum swing signal, if a peak is measured in one instance in</FONT>
<BR><FONT SIZE=2 FACE="Arial">time at 3.5v, and then a trough is measured the next time at 0v, and then</FONT>
<BR><FONT SIZE=2 FACE="Arial">the middle of the signal is measured at 1.75v, the average of the 3 samples</FONT>
<BR><FONT SIZE=2 FACE="Arial">is 1.75v.</FONT>
</P>

<P><FONT SIZE=2 FACE="Arial">What would be a proper method to sample a biased &quot;ac&quot; signal?&nbsp; Considering</FONT>
<BR><FONT SIZE=2 FACE="Arial">that the maximum voltage is 3.5v, I have ruled out the idea of rectifying</FONT>
<BR><FONT SIZE=2 FACE="Arial">the signal or something unless I can use a semiconductor junction that</FONT>
<BR><FONT SIZE=2 FACE="Arial">doesn't drop very much of that valuable signal level.</FONT>
</P>
</UL>
<P><FONT COLOR="#0000FF" SIZE=2 FACE="Arial">To rectify signal under these conditions you use something called a &quot;precision rectifier&quot;.&nbsp; This scheme uses an op-amp with a diode in the feedback path, so the 0.7 volt odd voltage drop is canceled.&nbsp; You can even get precision rectifiers with True RMS detection built in, e.g<U> <A HREF="http://www2.national.com/ms/LB/LB-25.pdf" TARGET="_blank">http://www2.national.com/ms/LB/LB-25.pdf</A></U></FONT></P>

<P><FONT COLOR="#0000FF" SIZE=2 FACE="Arial">Hope this helps</FONT>
</P>

<P><FONT COLOR="#0000FF" SIZE=2 FACE="Arial">Mike</FONT>
</P>

</BODY>
</HTML>
</x-html>

,,, so if you don't need to measure the absolute millivolts of the
senoidal signal captured by the mic, what counts for you is which signal
(circuit + speaker) made the max signal...

In this situation I would install a simple 1N4148 diode integrating the
signal over a cap + resistor and that's all.

Wagner

You might get a pair of resistors of equal value between VCC
and Common to bias the A/D at its exact midpoint.  The path between
the biased sine wave signal and this junction between the A/D
converter and the resistors would be made with a DC blocking capacitor
so the DC bias on the audio would no longer matter.

The resistors should be low enough in value such that the
sample-and-hold of the A/D converter will not load the circuit.  The
blocking cap will need to be large enough that its reactence is not a
factor in the frequency range to be used.

The output of the A/D converter would read either 0x7F or 0x80
so your 0 crossing would be one or the other of those two values.  As
long as it doesn't drift much with temperature, you should be able to
resolve a sine wave 127 counts in one direction and 128 counts in the
other.

Martin McCormick

What are you trying to accomplish, and what is your sample rate? If the
sample rate is at least twice the frequency of the sine wave, you can get
enough data to accurately reproduce the sine wave. As you point out, the
average will indeed by 1.75V. Averaging is the same as running the
incoming signal thru a low pass filter. If you want the RMS (which will
include the RMS of the DC), square the samples as they come in,
accumulate a sum of squares (I accumulate a 16 bit sum of 256 8 bit
samples), divide by the number of samples (that's why I use 256! It's
easy!), then take the square root using one of the recently posted
algorithms. That'll get you RMS.  If you want peak to peak, set up a RAM
location for minimum and maximum, then sample thru the cycle looking for
min and max. Subtract and there's the peak to peak.
So... again, it comes down to what are you looking for (wasn't that a
line from "Third Rock from the Sun" where theyre spying on a neighbor and
one of them says "I wonder what he's looking for?").

Harold

On Fri, 18 Feb 2000 06:47:48 -0500 Lorick <lorickAIR.ON.CA> writes:
{Quote hidden}

FCC Rules Online at http://hallikainen.com/FccRules
Lighting control for theatre and television at http://www.dovesystems.com

________________________________________________________________
YOU'RE PAYING TOO MUCH FOR THE INTERNET!
Juno now offers FREE Internet Access!
Try it today - there's no risk!  For your FREE software, visit:
dl.http://www.juno.com/get/tagj.

2000\02\18@123641 by
<x-flowed>At 09:40 AM 2/18/00 -0500, Lorick wrote:
>The signal I am working with is from an electret condenser microphone that
>will be picking up a definite 1KHz audio signal from some test oscillator
>circuit and speaker.  I am interested in detecting the volume level of the
>sound source so that I can tell how far away it is based on how strong the
>signal is.  The mic output will be signal conditioned to swing from 0 to
>3.5v (working from single supply op amps) and I will be reading this volume
>level with the a/d and I was trying to fiure out how the a/d would perceive
>the audio.  If it reads a level of 2v, how would it know if this is a
>maximum of the current waveform, or if it's the normalized zero crossing
>point, thus it should be interpreted as zero instead of two in terms of
>amplitude.

If you are only interested in the power at a single frequency (1 kHz), you
can solve your problem with a hardware active bandpass filter @ 1 kHz, or a
software digital bandpass filter centered at the same frequency.

If you aren't sure about an exact frequency, a simple rectifier and
integrator (either passive or active) will provide a smoothed input to the
PIC. You can also do it in software by absolute value + moving average.

================================================================
Robert A. LaBudde, PhD, PAS, Dpl. ACAFS  e-mail: rallcfltd.com
Least Cost Formulations, Ltd.                   URL: http://lcfltd.com/
824 Timberlake Drive                            Tel: 757-467-0954
Virginia Beach, VA 23464-3239                   Fax: 757-467-2947

"Vere scire est per causae scire"
================================================================

</x-flowed>
Lorick wrote:
>The signal I am working with is from an electret condenser microphone that
>will be picking up a definite 1KHz audio signal from some test oscillator
>circuit and speaker.  I am interested in detecting the volume level of the
>sound source so that I can tell how far away it is based on how strong the
>signal is.  The mic output will be signal conditioned to swing from 0 to
(snip)
>assuming this means I can sample WAY above the 1KHz signal frequency.  Now
I
>need to know exactly what it is I should be looking for to get the "volume"
>level of the signal...

The most precise measurement you could achieve in this case would be using a
software PLL (digital signal processing).  The signal from the microphone
will probably have a lot of background noise.  A software PLL combined with
an integrator to average the peaks and troughs of the signal (multiplied by
a time-domain windowing function) over a selected interval will give you the
same results as analysing a single band (the 1kHz band in this case) of a
discrete (fast) Fourier transform (FFT) performed using the same windowing
function and sampling rate.

In other words, this technique will give you an amplitude measurement of an
extremely narrow band (bandwidth depends on how long an interval you
integrate over) centered on your 1kHz signal.  Any noise that is not
precisely at 1kHz will be ignored.  It is not the simplest technique but it
can be implemented on a PIC with plenty of room and processing time to spare
(I used this technique on a PIC16C73 to measure a 60kHz signal -- 1kHz
should be a piece of cake!  I would be hapy to give you tips, pointers, and
sample code if you are interested).  The results are definitely worth the
effort if you want a precise measurement.

Cheers,

Ken

Lorick wrote:

> I need to (hopefully) use the 16F876 to sample a sine wave that rides
> on a 1.75v reference line, swinging from 0v to 3.5v but before I even
> attempt this, I'm thinking it won't work because if an average value
> of the sine wave is what's taken over time, then wouldn't I always get
> a reading somewhere near that 1.75v reference line?

Yes.  The *average* value of any pure AC signal is zero, as it spends
equal areas under the signal curve in either direction.  So if you feed
your signal into a low-pass filter, you will get the same voltage with
and without signal.

Although you say the reference line is 1.75V, it would probably be as
well to implement an averaging algorithm to determine exactly what this

You probably want the standard FIR (Finite Impulse Response) filter
function of adding the current sample to a 16- bit value and subtracting
the "current average" which is 1/256 of the current tally.  Of course,
1/256 of the current tally is merely the high byte of the tally plus the
high bit of the low byte added (or in this case, both are being
subtracted from the tally itself) for rounding correction.

Now that you know what the "zero level" is, you would prefer to sum
the squares of the instantaneous deviation from this level to measure
your signal level as a MS (Mean Squares - it's a waste of time to take
the square root again as the MS value is a perfectly good indicator).

This however is messy as it involves multiplications and at least 24-
bit accumulation, presuming you again use a FIR filter to smooth it.
Instead, just sum the modulo of the deviation from the average (do the
subtract, test the result and negate if presently negative) using the
same averaging procedure.

For a 1 kHz frequency, sample at approximately 16 k samples per second
to get 16 points per cycle and all the mathematics should be easy on a 4
MHz crystal PIC.

This method still measures signal plus noise.  If you want to filter
out the signal at a (one only) precise frequency of 1 kHz, then you need
a different technique.
--
Cheers,
Paul B.

>I would be interested in more information on this technique and some pic
>code to implement it.  Does this technique
>allow an input signal of wide bandwidth and then discriminate for the
center
>frequency of choice or does it assume
> a pre filtered limited bandwidth?

It allows a wide bandwidth.  Like any technique that samples a signal it is
susceptable to aliasing.  It is thus best to low-pass-filter the input so
that it does not excede the Nyquist frequency (one-half of the sample rate).

If you have some processing time to spare I would recommend sampling at a
high rate (20-40 ksps).  This way, a cheap RC lowpass filter can be used
outside of the PIC and still provide plenty of attenuation at the Nyquist
frequency.  If you sample slower you may want to consider using an active
filter with a steeper cutoff or perhaps an LC bandpass filter.

The code I have is written to deal with a 60kHz signal.  I would do a few
things differently for a 1kHz signal.  For a 1kHz signal I would recommend
the following:

1). Use CCP2 with TMR1 to generate the "special event" trigger that starts
an A/D conversion (every 50 microseconds to sample at 20kHz, 25 microseconds
for 40kHz).  Write an ISR to receive the A/D value and process it.  Here's a
chunk of code from my WWVB receiver that sets up the timer and A/D
interrupt:

movlw  1
movwf  t1con    ;timer1 internal clk, no prescale
movlw  149
movwf  ccpr2l   ;150 clk cycles (tosc/4)
clrf  ccpr2h    ; = 37.5us with 16MHz osc
movlw  0x0b
movwf  ccp2con   ;enable ccp2 as comparator
;CCP2 generates the special event trigger which
;clears timer1 and starts an A/D conversion

bsf  status,rp0
movlw  2
bsf  pie1,adie  ;enable A/D peripheral interrupt
bcf  status,rp0

movlw  0x81
movwf  adcon0   ;a/d clk = fosc/32, select ch 0
bcf  pir1,adif  ;clr A/D int flag
bsf  intcon,peie  ;enable peripheral interrupt
bsf  intcon,gie  ;enable interrupts

2). Lowpass filter the A/D signal at a cutoff frequency just above 1kHz.
The filter should produce enough attenuation at 3kHz to reduce aliasing to
acceptable levels (the first harmonic that will be aliased to 1kHz is at
3kHz).  A really simple lowpass filter stage (doing something similar to an
analog RC filter) can be achieved by the following:

out = out + ((in - out) / n)

Since the processing time per stage is so low (if n is a power of 2 and can
be accomplished by a simple right-shift), several such stages can be
cascaded to achieve the desired cutoff slope.  I'm not sure what the formula
is to relate n to a cutoff frequency -- I usually just write a C program to
calculate the results and then experiment with n (choosing powers of 2 or
other easily calculatable values) until I get the results I want.

3). Resample the lowpass-filtered signal at 4ksps (i.e. pick out every 5th
value if your original sample rate was 20ksps or every 10th value if your
original sample rate was 40ksps).

4). Add the resampled values sequentially into 4 different accumulators.
The accumulators will correspond (if you use a PLL) to the rising zero
crossing, the positive peak, the falling zero crossing, and the negative
peak of the 1kHz signal.  If you don't use a PLL, you can get a complex
(phasor representation) signal measurement as follows:

r = (ACC2 - ACC4) / n
j = (ACC1 - ACC3) / n

Where n is the number of samples in the accumulators.  The measured
amplitude is simply sqrt(r*r + j*j).

Every so often (how long depends on how much frequency selectivity you need
and how often you need to get an amplitude measurement), you take the
results as shown above and then zero the accumulators.

You may find that this alone produces adequate results (no PLL and a simple
rectangular windowing function).  The longer you add samples into the
accumulators before using the average and zeroing the accumulators, the more
selective the frequency response will be.  If you average samples for too
long (long enough for the phase of the 1kHz signal to drift a substantial
amount relative to the sampling phase) then you will need to use a PLL to
precisely match the frequency of the signal.

A PLL can be implemented by adding or subtracting clock cycles from the A/D
sampling timer (by adjusting CCP2) so that each set of samples that go into
ACC1 and ACC3 are as close to the zero-crossing as possible.  If these
samples were exactly on the zero-crossing then S1-S3 would be zero (where S1
is the sample that gets added into ACC1 and S3 is the sample that gets added
into ACC3).  If the sampling points were late then S1-S3 would be positive.
If the sampling points were early then S1-S3 would be negative.  Thus, S1-S3
can be used as an error measurement to steer the phase of the A/D sampling.
If you are interested in doing this I could provide an example (but it is
pretty long and difficult to explain).

For really good noise rejection you may want to use a PLL along with a
windowing function to improve the frequency selectivity.  For more
information about windowing functions, see the following:

www.spd.eee.strath.ac.uk/~interact/moved/dft/window.html
www.engr.sjsu.edu/~knapp/HCIROD3D/3D_phys/Fou_note.htm
http://www.cooper.edu/~donahu/auFilter/auFilter.html

A triangle (Bartlett) window can be calculated using a coupple of running
sums and taking the difference for the ramp up and just using a running sum
for the ramp down.  At the slow 4ksps rate, other windowing functions
requiring multiplications are also possible.

I hope this helps and isn't overly confusing.

Cheers,

Ken

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