开发者

Interleaving/deinterleaving 3 vectors in C++ STL

I'm trying to combine three signal waveforms into a single, interleaved waveform. I need to know the best way to do it in C++ STL. Better solutions would use as much C++ STL style as possible, avoid redundant code, etc. Is there some STL "tuple" type class that would do this for me? I need contiguous storage at all times for backward compatibility with other code (therefore, vector). The best solutio开发者_JAVA技巧n would be correct and easy to understand. Space and speed are not as high of a priority as correctness and ease of understanding.

The output waveform must be ordered like this: first sample from first channel, first sample from second channel, first sample from third channel, then continue with the second sample from each channel and repeat for all samples. I know that all three input waveforms have the same number of samples.

In Matlab, I would have done it like this:

function outputWaveform=Interleave3(a, b, c)
outputWaveform=zeros([1 3*length(a)]);
outputWaveform(1:3:end)=a(:);
outputWaveform(2:3:end)=b(:);
outputWaveform(3:3:end)=c(:);

This is my first C++ STL attempt:

typedef vector<double>  dVector;
typedef vector<double>::iterator  dVectorIT;
dVector Interleave3(dVector a, dVector b, dVector c)
{
    dVector result(0, 3*a.size());
    dVectorIT aIT=a.begin(), bIT=b.begin(), cIT=c.begin(), rIT=result.begin();
    for(; aIT != a.end(); ++aIT, ++bIT, ++cIT)
    {
        *rIT++=*aIT;
        *rIT++=*bIT;
        *rIT++=*cIT;
    }
    return  result;
}

It works, but is there a better way to do this? I hoped there might be some clever way to do it in one line with transform(). Can you append b to a, then c to a, then transform the temporary "a1a2a3...-b1b2b3...-c1c2c3..." vector into "a1b1c1a2b2c2a3b3c3..."?

Bonus question: I also need the inverse operation (to split an output waveform of 3*N samples into 3 vectors of N samples each). The Matlab solution is quite easy:

function [a, b, c]=Deinterleave3(outputWaveform)
a=outputWaveform(1:3:end);
b=outputWaveform(2:3:end);
c=outputWaveform(3:3:end);

C++ STL seems fairly awkward, and I bet there's a better way to do it than this:

typedef vector<double>  dVector;
typedef vector<double>::iterator  dVectorIT;
void Deinterleave3(dVector outputWaveform, dVector &a, dVector &b, dVector &c)
{
    ASSERT( !(outputWaveform.size()%3) );
    a.clear(); b.clear(); c.clear();
    dVectorIT oIT=outputWaveform.begin();
    for(; oIT != outputWaveform.end(); )
    {
        a.push_back( *oIT++ );
        b.push_back( *oIT++ );
        c.push_back( *oIT++ );
    }
}

Is there some clever combination of transform() and back_inserter() which would do the inverse operation? Again, using a temporary vector would be acceptable.

Boost has a "zip iterator," but I can't figure out if it would perform either the interleaving or deinterleaving operation.

EDIT: fixed the missing angle brackets (<>). The HTML filter ate them! Also, I have a new idea about how to fix this with a custom iterator.


If you're willing to use Boost, you can use slices to get syntax very close to your code in Matlab. Here's a C++ version of your Interleave3 function:

template<typename V>
V Interleave3(V const& a, V const& b, V const& c)
{
    using namespace boost::numeric::ublas;

    V v(a.size() + b.size() + c.size());
    vector_slice<V>(v, slice(0, 3, a.size())) = a;
    vector_slice<V>(v, slice(1, 3, b.size())) = b;
    vector_slice<V>(v, slice(2, 3, c.size())) = c;

    return v;
}

The catch is that instead of using std::vector you have to use boost::numeric::ublas::vector.


I'm not sure about interleaving but you can use for_each to deinterleave. You would still want to add additional error checking (that the source size is correct etc):

#include <iostream>
#include <vector>

typedef std::vector<double> dVector;
typedef dVector::iterator dVectorIT;

class DeInterleave
{
public:
    DeInterleave(std::vector<dVector>& output) : output_(output), currentIndex_(0) { }
    void operator()(const dVector::value_type& item)
    {
        output_[currentIndex_].push_back(item);
        currentIndex_ = (currentIndex_ + 1) % output_.size();
    }

private:
    std::vector<dVector>& output_;
    int currentIndex_;
};

int main()
{
    dVector source;
    source.push_back(5.0);
    source.push_back(6.0);
    source.push_back(8.0);
    source.push_back(2.0);
    source.push_back(2.0);
    source.push_back(1.0);
    std::vector<dVector> dest(3);

    std::for_each(source.begin(), source.end(), DeInterleave(dest));

    std::cout << dest[0].size() << " " << dest[0][0] << ":" << dest[0][1] << std::endl;
    std::cout << dest[1].size() << " " << dest[1][0] << ":" << dest[1][1] << std::endl;
    std::cout << dest[2].size() << " " << dest[2][0] << ":" << dest[2][1] << std::endl;

    return 0;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜