Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

set_capacity not defined for realtime_circular_buffer? #74

Open
roncapat opened this issue Mar 25, 2024 · 12 comments
Open

set_capacity not defined for realtime_circular_buffer? #74

roncapat opened this issue Mar 25, 2024 · 12 comments

Comments

@roncapat
Copy link

Am I right or set_capacity() member is not implemented? I searched in the whole repo, only one result for this symbol, and it's the line at the link below.

https://github.com/ros/filters/blob/e33463aebca78471c0e52f45eaf31585b781af61/include/filters/realtime_circular_buffer.hpp#L83C8-L83C20

In this case, would you like me to provide a PR?

@jonbinney
Copy link
Contributor

Yep, doesn't seem to be implemented. A PR would be appreciated, thanks!

@roncapat
Copy link
Author

Will do :)

@roncapat
Copy link
Author

roncapat commented Mar 26, 2024

@jonbinney The seems to be a bit of ambiguity about the original meaning of this function.

In Boost:

Given the signature of the missing set_capacity() implementation here, I believe that it should call resize() internally. Since we would not break any API here, we could think about renaming this method to avoid any confusion.

@jonbinney
Copy link
Contributor

From the boost documentation of resize(): "If the new size is greater than the current size, copies of item will be inserted at the back of the of the circular_buffer in order to achieve the desired size."

That doesn't sound like the behavior I'd usually want. What use case do you have in mind? I wouldn't worry too much about keeping the signature of set_capacity() the same here.

@roncapat
Copy link
Author

roncapat commented Mar 27, 2024

@jonbinney IMHO new items should be somehow initialized, so the user has to provide a value.

My use case is that I implemented an average filter on top of this buffer, by averaging latest N samples of an incoming measure. I would not change size of the buffer at runtime, but it would come handy to change the size of a default-constructed one during for example initialization of a controller - like, on_init()/on_configure() stages.

That doesn't sound like the behavior I'd usually want.

Could you elaborate a bit? Let's discuss what is your ideal behaviour, maybe we can implement it inside this class here.

@jonbinney
Copy link
Contributor

I may misunderstand, but wouldn't your rolling window average be wrong at the start? For example, assume N=10 for your case. You resize() the buffer to a size of 10 , fill it with some default value, and start collecting samples. When you have collected 5 samples so far, how would you know that the other 5 samples aren't yet actual samples? The size would be 10 and the capacity would be 10, so they're effectively storing the same information twice.

If we have a set_capacity() method, in the same case capacity would be 10 and size would be 5, so you'd have more info - you'd know exactly how many valid samples you've got, right?

@roncapat
Copy link
Author

The point is: let's say we construct a RealtimeCircularBuffer(5,0). If we only do set_capacity(10) on the internal buffer later on, the user will not be able to add a sixth element at all.

About the averaging in my use case: in the first few cycles I may be able to accept a transient with "wrong values" (a sort of ramp effect), but truly I use a counter to keep track of the number of real measures obtained up to that moment (i.e. something that grows like 1 2 3 4 5 5 5 5 5 5...)

@jonbinney
Copy link
Contributor

You're right - I misunderstood how push_back() worked! Also the constructor of RealtimeCircular buffer already requires initializing the elements, so having the resize method do the same makes sense. I agree now that having a resize() method makes more sense.

@roncapat
Copy link
Author

roncapat commented Apr 3, 2024

There is still a thing to notice:

  • since we expose both push_front() and push_back() the user is free to use the circular buffer in both directions - i.e. when pushing back an element, the buffer might drop the front one (if it's already full), when pushing front an element, it might drop the back one instead.

Given this, the problem here is to choose between resize and rresize (notice the double R). Because people might want to reside extending the left-most side, or the right-most one, depending on the direction they are using the buffer (front->back or back->front).

@jonbinney do you have any opinion or more background on this?

@jonbinney
Copy link
Contributor

It looks like both the mean and median filters in this repo use push_back(); I'd guess that is the most common case.

@roncapat
Copy link
Author

roncapat commented Apr 3, 2024

I would propose to drop RealtimeCircularBuffer::push_front() and expose boost::circular_buffer::resize().
This way users are forced to use the circular buffer in one direction only.

But I can imagine breaking some possible packages in the wild doing so...

@jonbinney
Copy link
Contributor

I should have asked this earlier, but at some point is it worth encouraging people to just use boost::circular_buffer directly instead of exposing more and more of its member functions in RealtimCircularBuffer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants