A Few Models For Dealing With ADC Samples

classic Classic list List threaded Threaded
5 messages Options
BogdanM BogdanM
Reply | Threaded
Open this post in threaded view
|

A Few Models For Dealing With ADC Samples

Alright, a word of warning first: I'm not by any means a specialist in ADCs,
and I only used them in a buch of applications. That said, I do have some
ideas about how they work and what they're supposed to do, and a few ideas
of my own about the design of the module itself. The basic principle here is
KISS. I want the modules to cover all the needed functionality, but no more
than that. I definitely don't want a full blown API, but rather to keep
everything as lightweight as possible. For example, you might have noticed
that none of the modules currently exported by eLua use the "object
notation". This is intentional, as the "standard" notation is still more
widely used in different instances of embedded programming, plus it keeps
the implementation simpler. Of course, keeping a good balance between a
minimal API and a good functionality is an art in itself, something that I
don't pretend to master (but I try anyway :) ).
With that in mind, I think that our current ADC module does enough to
qualify as functional

- single sampling
- multiple sampling at a given frequency (which is very deterministic, being
handled in the backend with interrupts which are quite accurate).
- moving average filtering (quite important in real-life applications).

In the future, once interrupt handlers are implemented in eLua, we'll also
support double buffering, in that we'll have a circular sample buffer, and
an "interrupt" will be fired when that buffer is half full. This would allow
certain kind of applications (like data loggers) to be written very easily.
I think this is a very powerful model.

Please see below my other comment.


Single Function to Request and Return:
> 1. Simple Model
> call function to start sampling
> function waits for sampling to finish
> function returns samples
>

Not acceptable if this is the only model, perfectly OK if it coexists with
other (asynchronous) models.\

2. Non-blocking Model (this was present in an earlier version of the ADC
> module)
> call function to start sampling, function returns
> do some other stuff
> call function again to get samples from the sampling period, and start next
> set of sampling
>

Interesting, but let's see the next one.

Separate Request & Return Functions:
> 3. Separated Request/Return Model
> call function to start sampling, function returns
> do other work
> use another function to get samples in the buffer (this can be done while
> sampling is still happening)
>

I assume you're talking about a circular buffer here, and this is perfectly
OK with me. Add an overflow flag for those situations when you don't collect
the samples on time and you're all set (and it also matches (to some extent)
the interrupt model I was talking about earlier. Maybe even add a function
that would return "true" when half (or an user-specified fraction of the
buffer) is full).
This is the kind of funtionality I get from an Advantech acquisition board
on a PC (well, from its library API actually), and it was all I needed to
write a very precise acquisition application that archives data over very
long periods of time, plot real time graphs, thinks like this. I'm sure the
model would work equally well on embedded.

- samples collected in the background, other work can be done while samples
> are collected
> - samples collected using fairly deterministic timer-based interrupt system
> - longer deterministic periods can be used where one can request 100
> samples, but only pull in 5 at a time while sampling is happening, while
> still getting low timing jitter
>

For this situations, it might be a good idea to add a "poll" function that
would return 'true' each time a predefined number of samples (6 in your
example) are available. Kinda like the "return true when half of the buffer
is full" idea, but more generic.

- could be extended to support indefinite periods of sampling with buffer
> wrapping if samples aren't pulled out fast enough, but when you do need
> samples you can pull out up to the length of the buffer and they're still
> pretty well-timed
>

Of course you can. You can't escape circular buffers. If your process is
slow enough, it's all you need for continuous acquisition. If it's too fast,
it doesn't matter how long your buffers are, you will get into overflows at
some point.


> - more complicated, including dealing with buffer sizes
>

Why is that? We already know how to specify buffer sizes.


> - multiple commands needed to initiate/get samples
>

That's not really a problem.
In conclusion, this (3) would be my preffered model, with a catch: let's not
make it more complex than it needs to be.


> One alternative that I've not mentioned here is that there be two
> functional models for getting samples.  If one wants, one could have a
> simple getsamples method that follows model 1, and a second pair that
> follows model 3. i.e.:
>
> channels = adc.channel(0, 3, 17, 21)
>
> -- Style 1: Simple Blocking Model
> a = channels:getsamples(count)
>
> -- Style 2: Separated Model
> channels:requestsamples(count, timer, frequency)
> channels:returnsamples(count)
>

Let's go for option 3, the one that doesn't use an object notation at all
(for reasons I mentioned at the beginning of this thread).

Best,
Bogdan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: https://lists.berlios.de/pipermail/elua-dev/attachments/20090219/24768332/attachment.html 

jbsnyder jbsnyder
Reply | Threaded
Open this post in threaded view
|

A Few Models For Dealing With ADC Samples


On Feb 19, 2009, at 4:48 AM, Bogdan Marinescu wrote:

> Alright, a word of warning first: I'm not by any means a specialist  
> in ADCs, and I only used them in a buch of applications. That said,  
> I do have some ideas about how they work and what they're supposed  
> to do, and a few ideas of my own about the design of the module  
> itself. The basic principle here is KISS. I want the modules to  
> cover all the needed functionality, but no more than that. I  
> definitely don't want a full blown API, but rather to keep  
> everything as lightweight as possible. For example, you might have  
> noticed that none of the modules currently exported by eLua use the  
> "object notation". This is intentional, as the "standard" notation  
> is still more widely used in different instances of embedded  
> programming, plus it keeps the implementation simpler. Of course,  
> keeping a good balance between a minimal API and a good  
> functionality is an art in itself, something that I don't pretend to  
> master (but I try anyway :) ).
> With that in mind, I think that our current ADC module does enough  
> to qualify as functional
>
> - single sampling
> - multiple sampling at a given frequency (which is very  
> deterministic, being handled in the backend with interrupts which  
> are quite accurate).
> - moving average filtering (quite important in real-life  
> applications).
>
> In the future, once interrupt handlers are implemented in eLua,  
> we'll also support double buffering, in that we'll have a circular  
> sample buffer, and an "interrupt" will be fired when that buffer is  
> half full. This would allow certain kind of applications (like data  
> loggers) to be written very easily. I think this is a very powerful  
> model.
>
> Please see below my other comment.
>
>
> Single Function to Request and Return:
> 1. Simple Model
> call function to start sampling
> function waits for sampling to finish
> function returns samples
>
> Not acceptable if this is the only model, perfectly OK if it  
> coexists with other (asynchronous) models.\
>
> 2. Non-blocking Model (this was present in an earlier version of the  
> ADC module)
> call function to start sampling, function returns
> do some other stuff
> call function again to get samples from the sampling period, and  
> start next set of sampling
>
> Interesting, but let's see the next one.
>
> Separate Request & Return Functions:
> 3. Separated Request/Return Model
> call function to start sampling, function returns
> do other work
> use another function to get samples in the buffer (this can be done  
> while sampling is still happening)
>
> I assume you're talking about a circular buffer here, and this is  
> perfectly OK with me. Add an overflow flag for those situations when  
> you don't collect the samples on time and you're all set (and it  
> also matches (to some extent) the interrupt model I was talking  
> about earlier. Maybe even add a function that would return "true"  
> when half (or an user-specified fraction of the buffer) is full).

This is, by far, the most common model I've seen for a lot of higher  
level APIs (initiate sampling, samples buffer, pull samples out with  
another function).  As an example, since I've worked with it before,  
and the docs are online, here's an overview of how MATLAB deals with  
the wide range of  ADC/DAC/GPIO devices it talks to:
http://www.mathworks.com/access/helpdesk/help/toolbox/daq/index.html?/access/helpdesk/help/toolbox/daq/f14-17602.html&http://www.mathworks.com/products/daq/

An overflow flag would be a good idea.  The partial filling flag is  
interesting as well.  Currently we've got a function that will return  
the number of samples available, so adding something to poll for a  
specified number would be trivial.


>
> This is the kind of funtionality I get from an Advantech acquisition  
> board on a PC (well, from its library API actually), and it was all  
> I needed to write a very precise acquisition application that  
> archives data over very long periods of time, plot real time graphs,  
> thinks like this. I'm sure the model would work equally well on  
> embedded.

Do you mean the flag/partial filling mechanism, or the two function  
request/return model?  I'd be interested in hearing some general usage  
case information from your application so that I can keep that in mind  
while doing the implementation.

>
>
> - samples collected in the background, other work can be done while  
> samples are collected
> - samples collected using fairly deterministic timer-based interrupt  
> system
> - longer deterministic periods can be used where one can request 100  
> samples, but only pull in 5 at a time while sampling is happening,  
> while still getting low timing jitter
>
> For this situations, it might be a good idea to add a "poll"  
> function that would return 'true' each time a predefined number of  
> samples (6 in your example) are available. Kinda like the "return  
> true when half of the buffer is full" idea, but more generic.

Right, I was actually thinking of implementing the "half-full" thing  
this way anyways.

>
>
> - could be extended to support indefinite periods of sampling with  
> buffer wrapping if samples aren't pulled out fast enough, but when  
> you do need samples you can pull out up to the length of the buffer  
> and they're still pretty well-timed
>
> Of course you can. You can't escape circular buffers. If your  
> process is slow enough, it's all you need for continuous  
> acquisition. If it's too fast, it doesn't matter how long your  
> buffers are, you will get into overflows at some point.

Right. Honestly to make it run continuously all I have to do is turn  
off the function that tells the sequencer to stop once the number of  
requested samples are collected.

>
>
> - more complicated, including dealing with buffer sizes
>
> Why is that? We already know how to specify buffer sizes.

I didn't mean much more complicated :-)  The complication here, at  
least in terms of the way I'm thinking is if we want to minimize  
buffer size as much as possible but be flexible if more samples are  
coming in and we want to grow the buffer without destroying  
uncollected samples.  I know this isn't essential, though :-) Right  
now, buffers can be resized whenever all samples are pulled out, or  
when a request is made that exceeds current buffer size (any samples  
remaining in the buffer at these times will get nuked though).

>
>
> - multiple commands needed to initiate/get samples
>
> That's not really a problem.
> In conclusion, this (3) would be my preffered model, with a catch:  
> let's not make it more complex than it needs to be.

Right, I'd be open to suggestions of where to pare things down.  But  
before I do that, here are a few things that people have brought up or  
have come up that might be useful to consider:

1. Have a function that returns only one sample at a time from the  
buffer (if available). Depending on whether we keep the "amend/adjust  
the table" approach, this does make it so that if all I want is one  
sample, I can do that without the overhead of creating a new table.  
This could also be a function that could request the sample itself as  
well.

2. Locking multiple channels to a clock was discussed during the  
object model discourse, so that one could have a bunch of channels  
grab each sample in lock step.  Doing this without the object model is  
less attractive, but I could see doing something like the following:

adc.chain(0,3,8)

Where any property modification or sampling request you make of one is  
made of all of them, so if I then do:

adc.setsmoothing(0,16)

it is actually equivalent to:

adc.setsmoothing(0,16)
adc.setsmoothing(3,16)
adc.setsmoothing(8,16)

but more importantly, when I do adc.sample(0)

they all fire off conversions sequentially on the C side where the  
delay between conversions would be much more minimal than doing a loop  
in lua.  I think I would keep the reads from each channel separate  
though (not return all channels' results with one adc.getsamples(),  
though that could be done too)

If you do the same for burst requests, they all get triggered by the  
same clock.

If the idea of chaining seems a little unsavory, since it could make  
code hard to interpret later if you miss the chaining command, we  
could also accept a table of channel_ids as opposed to just single  
channel ids for at least burst and sample.  So you might call  
something like this:

adc.burst({0, 3},16,0,5000)

this would initiate sampling on channels 0 and 3 to collect 16  
samples, using timer 0, at 5000 Hz...

That doesn't even require a new function :-)

3. Do we keep the modify-the-table approach? I think having number 1  
above that returns single samples at least removes this need for  
something that samples like adcscope.lua does.

Table modification is a bit ugly in the API, but it could be done in a  
limited fashion.  Either only appending could be allowed, or going  
slightly more flexible, modifications could be made starting at an  
offset, but only if the number of elements to modify were included.  I  
think of this as sort a syntactically ugly version of using slices  
(like in Python) to modify data :-)

Or, we can just return new tables for now :-)  Any thoughts about what  
to do in the immediate future with this?  We could have global tables  
to represent returned samples, but I don't like that a huge amount.

>
>
> One alternative that I've not mentioned here is that there be two  
> functional models for getting samples.  If one wants, one could have  
> a simple getsamples method that follows model 1, and a second pair  
> that follows model 3. i.e.:
>
> channels = adc.channel(0, 3, 17, 21)
>
> -- Style 1: Simple Blocking Model
> a = channels:getsamples(count)
>
> -- Style 2: Separated Model
> channels:requestsamples(count, timer, frequency)
> channels:returnsamples(count)
>
> Let's go for option 3, the one that doesn't use an object notation  
> at all (for reasons I mentioned at the beginning of this thread).

I do like the syntax of the object model approach, but consistency is  
a pretty good argument.  The other thing is that if one wanted to, one  
could certainly build a lua-only object model implementation on top of  
the simple API. :-)

Best.

-jsnyder

--
James Snyder
Biomedical Engineering
Northwestern University
jbsnyder at fanplastic.org
http://fanplastic.org/key.txt
ph: (847) 644-2322

-------------- next part --------------
An HTML attachment was scrubbed...
URL: https://lists.berlios.de/pipermail/elua-dev/attachments/20090219/13dfeecf/attachment-0001.html 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PGP.sig
Type: application/pgp-signature
Size: 194 bytes
Desc: This is a digitally signed message part
Url : https://lists.berlios.de/pipermail/elua-dev/attachments/20090219/13dfeecf/attachment-0001.pgp 

Andre Carregal-2 Andre Carregal-2
Reply | Threaded
Open this post in threaded view
|

A Few Models For Dealing With ADC Samples

In reply to this post by BogdanM
(changing gears... screech...)

> On Feb 19, 2009, at 4:48 AM, Bogdan Marinescu wrote:
> Alright, a word of warning first: I'm not by any means a specialist in ADCs,
> and I only used them in a buch of applications. That said, I do have some
> ideas about how they work and what they're supposed to do, and a few ideas
> of my own about the design of the module itself. The basic principle here is
> KISS. I want the modules to cover all the needed functionality, but no more
> than that. I definitely don't want a full blown API, but rather to keep
> everything as lightweight as possible. For example, you might have noticed
> that none of the modules currently exported by eLua use the "object
> notation". This is intentional, as the "standard" notation is still more
> widely used in different instances of embedded programming, plus it keeps
> the implementation simpler. Of course, keeping a good balance between a
> minimal API and a good functionality is an art in itself, something that I
> don't pretend to master (but I try anyway :) ).
> With that in mind, I think that our current ADC module does enough to
> qualify as functional

I hear you, crystal clear. I really came to the list with a very
different point of view and this thread has been a good lesson of
scale and politics for me... :o)

As a side note, it's interesting how "small" is a subjective concept.
For an astronomer, the moon is probably small... for me, something
around 5k was small, but once you find that people are fighting for
bytes suddenly the scale changes.

I apologize for not spending time enough to get a feeling of the
project bias and culture before manifesting my ideas and I promise to
be more careful in the future.

> Let's go for option 3, the one that doesn't use an object notation at all
> (for reasons I mentioned at the beginning of this thread).
>
> On Thu, Feb 19, 2009 at 2:58 PM, James Snyder <jbsnyder at fanplastic.org> wrote:
> I do like the syntax of the object model approach, but consistency is a
> pretty good argument.  The other thing is that if one wanted to, one could
> certainly build a lua-only object model implementation on top of the simple
> API. :-)

Consistency is enough for me too, let's leave the higher level APIs
for those with extra space.

Andr?

jbsnyder jbsnyder
Reply | Threaded
Open this post in threaded view
|

A Few Models For Dealing With ADC Samples


On Feb 21, 2009, at 3:55 PM, Andre Carregal wrote:

> (changing gears... screech...)
>
>> On Feb 19, 2009, at 4:48 AM, Bogdan Marinescu wrote:
>> Alright, a word of warning first: I'm not by any means a specialist  
>> in ADCs,
>> and I only used them in a buch of applications. That said, I do  
>> have some
>> ideas about how they work and what they're supposed to do, and a  
>> few ideas
>> of my own about the design of the module itself. The basic  
>> principle here is
>> KISS. I want the modules to cover all the needed functionality, but  
>> no more
>> than that. I definitely don't want a full blown API, but rather to  
>> keep
>> everything as lightweight as possible. For example, you might have  
>> noticed
>> that none of the modules currently exported by eLua use the "object
>> notation". This is intentional, as the "standard" notation is still  
>> more
>> widely used in different instances of embedded programming, plus it  
>> keeps
>> the implementation simpler. Of course, keeping a good balance  
>> between a
>> minimal API and a good functionality is an art in itself, something  
>> that I
>> don't pretend to master (but I try anyway :) ).
>> With that in mind, I think that our current ADC module does enough to
>> qualify as functional
>
> I hear you, crystal clear. I really came to the list with a very
> different point of view and this thread has been a good lesson of
> scale and politics for me... :o)
>
> As a side note, it's interesting how "small" is a subjective concept.
> For an astronomer, the moon is probably small... for me, something
> around 5k was small, but once you find that people are fighting for
> bytes suddenly the scale changes.
>
> I apologize for not spending time enough to get a feeling of the
> project bias and culture before manifesting my ideas and I promise to
> be more careful in the future.

There's no problem with discussing these things though (with some  
limitations) :-)

Even if the lower level APIs don't adopt an object style of notation,  
there were a couple of things that came out there that were  
interesting.  I think that the grouping or atomizing of channels is  
something that may prove to be a very useful feature, which may not  
have been communicated had we not gone down that path.  Also, I  
personally have only started recently working with Lua, so getting  
perspectives how others would want to implement something like this is  
quite valuable.

KISS is a difficult philosophy to adhere to when there are innumerable  
ways to do even simple things.  Given that, I think that brainstorming  
a bit about the different ways to do things can help in figuring out  
what does and doesn't make sense about any given approach.  It also  
should help with preventing cases where someone looks at this, many  
months down the road, and wonders why some particularly braindead  
decision was made :-)

Also, giving good reasons to rip out useless or bizarre functionality  
should help keep this smaller.

All of that said, things do need to be balanced.  We don't want  
something that needs even a megabyte of RAM to run in, so some ideas  
will generally always be off the table :-)

--
James Snyder
Biomedical Engineering
Northwestern University
jbsnyder at fanplastic.org
http://fanplastic.org/key.txt
ph: (847) 644-2322

-------------- next part --------------
An HTML attachment was scrubbed...
URL: https://lists.berlios.de/pipermail/elua-dev/attachments/20090221/cc2b8cbe/attachment-0001.html 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PGP.sig
Type: application/pgp-signature
Size: 194 bytes
Desc: This is a digitally signed message part
Url : https://lists.berlios.de/pipermail/elua-dev/attachments/20090221/cc2b8cbe/attachment-0001.pgp 

BogdanM BogdanM
Reply | Threaded
Open this post in threaded view
|

A Few Models For Dealing With ADC Samples

In reply to this post by Andre Carregal-2
On Sat, Feb 21, 2009 at 11:55 PM, Andre Carregal <carregal at pobox.com> wrote:

> (changing gears... screech...)


You really should take care of that gearbox of yours :)


> I hear you, crystal clear. I really came to the list with a very
> different point of view and this thread has been a good lesson of
> scale and politics for me... :o)
>
> As a side note, it's interesting how "small" is a subjective concept.
> For an astronomer, the moon is probably small... for me, something
> around 5k was small, but once you find that people are fighting for
> bytes suddenly the scale changes.
>
> I apologize for not spending time enough to get a feeling of the
> project bias and culture before manifesting my ideas and I promise to
> be more careful in the future.


Oh, there's nothing at all to apologize here, and your contribution is most
welcome. There is a lot to learn from a constructive critique (or simply a
debate on a given subject), even when the discussion happens between people
that come from very different backgrounds. And BTW, to that extent, your
solution is excellent. I didn't think of it as "wrong" for a single moment,
because it's not. But I believe that a project must follow a certain design
philosophy, otherwise it won't get very far. This is why I have to assume my
tiranic posture at times and mercilessly dictate the evolution of the
project :) But other than that, this kind of discussions are strongly
encouraged on this list.

Best,
Bogdan


>
> > Let's go for option 3, the one that doesn't use an object notation at all
> > (for reasons I mentioned at the beginning of this thread).
> >
> > On Thu, Feb 19, 2009 at 2:58 PM, James Snyder <jbsnyder at fanplastic.org>
> wrote:
> > I do like the syntax of the object model approach, but consistency is a
> > pretty good argument.  The other thing is that if one wanted to, one
> could
> > certainly build a lua-only object model implementation on top of the
> simple
> > API. :-)
>
> Consistency is enough for me too, let's leave the higher level APIs
> for those with extra space.
>
> Andr?
> _______________________________________________
> Elua-dev mailing list
> Elua-dev at lists.berlios.de
> https://lists.berlios.de/mailman/listinfo/elua-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: https://lists.berlios.de/pipermail/elua-dev/attachments/20090222/7710db88/attachment.html