如何处理信号处理库的输入/输出类型?

时间:2011-08-29 18:13:50

标签: c++

好的 - 所以我有一个我正在研究的图书馆。基本上是块信号处理库。它使用顶级“Block”类实现,每个派生块实现信号处理操作,例如,添加是“AddBlock”等。

到目前为止,我依赖输入和输出是一个double数组,具体来说,数组类型是基于blitz ++库。一切都很好。

但是,我现在想要包括处理具有复数的数组的能力,特别是在'FFT块'的输出中(或者'IFFT块的输入')。

所以我的问题是:如何最好地迎合这一点?

我是否根据输入和输出类型参数化每个类? (读:存储在数组中的数据类型)。或者有更好的方法吗?

或者,我应该将输入/输出对象封装到一个单独的类中来抽象它们的实际表示吗? (这可能是一种可能性,因为它通常很容易在抽象的基础上提供操作,如果这有意义的话......)

我已经考虑过了一点......相当多。有什么想法吗?

提前致谢。

1 个答案:

答案 0 :(得分:0)

使用模板对信号类型进行“通用化”。您的类型,块大小等等可以转换为您的类的参数。例如:

template < typename TSignalType >
class t_fir {
public:
    //...
    void apply(TSignalType* const destination, const TSignalType* const source, const size_t& count) {
      // ...
    }
private:
  TSignalType d_buffer[Size];
};

然后根据需要专门化。

这种方法很好,因为它类型安全且执行速度非常快/很小。

缺点是它可能会增加您的构建时间。此外,这样的实现是一个陡峭的主题,如果您不熟悉这些概念,将需要花费大量时间来实现。

更详细地阅读评论后:很多都取决于您的设计目标(执行速度最快,实施最简单?)。我通常会将一个参数传递给块进程,该参数将根据需要公开有关类型的详细信息。那么你可以专门化流程或简单地创建子方法(也是模板)。

说明:

template < typename T >
class t_array {
public:
/* not certain how you represent a signal... */
    typedef T t_element;

    t_array() : d_elements() {
    }

    t_element& operator[](const size_t& idx) { return this->d_elements[idx]; }
    const t_element& operator[](const size_t& idx) const { return this->d_elements[idx]; }
private:
    std::vector<t_element> d_elements;
private:
/* prohibited */
    t_array(const t_array&);
    t_array& operator=(const t_array&);
};

typedef t_array<float> t_float_array;
typedef t_array<double> t_double_array;

typedef t_array<std::complex<float> > t_complex_float_array;
typedef t_array<std::complex<double> > t_complex_double_array;

template < typename TInputSignal, typename TOutputSignal >
class t_render_arguments {
public:
    typedef TInputSignal t_input_signal;
    typedef TOutputSignal t_output_signal;

    t_render_arguments(const t_input_signal& inInput, t_output_signal& inOutput, const size_t& inCount) : d_count(inCount), d_input(inInput), d_output(inOutput) {
    }

    const size_t count() const { return this->d_count; }

    const t_input_signal& input() const { return this->d_input; }

    t_output_signal& output() { return this->d_output; }
    const t_output_signal& output() const { return this->d_output; }

private:
    const size_t d_count;
    const t_input_signal& d_input;
    t_output_signal& d_output;
private:
/* prohibited */
    t_render_arguments(const t_render_arguments&);
    t_render_arguments& operator=(const t_render_arguments&);
};

class t_block_process_specification {
public:
/* documentation only, as no requirement is defined. all blocks provide this. */
template < typename TRenderArguments >
    bool process(TRenderArguments& arguments);
};

// type abides t_block_process_specification
template < typename TArray >
class t_block_add {
public:

    t_block_add() : d_array() {} /* << ctor is not what you'd see in practice */

/* specialize as needed */
template < typename TRenderArguments >
    bool process(TRenderArguments& arguments) {
    /* check preconditions and return false if needed */
        const typename TRenderArguments::t_input_signal& input(arguments.input());;
        typename TRenderArguments::t_output_signal& output(arguments.output());

        const TArray& a(this->d_array);
        const typename TRenderArguments::t_input_signal& b(input);
    // this is one approach, but some signals/processors will need specialzations
    // in addition to specializing process, this type could instead create local 
    // methods to handle such specializations when mixing modes and signal types
        for (size_t idx(0); idx < arguments.count(); ++idx) {
            output[idx] = a[idx] + b[idx];
        }
        return true;
    }
private:
    TArray d_array;
};

实例化然后采用一般形式:

template < typename TSource, typename TDest, typename TProcess >
void TestProcess() {

    TSource source;
    TDest dest;
    const size_t N(1024);
    t_render_arguments<TSource,TDest> arguments(source, dest, N);

/* would obviously need a real ctor in real life */
    TProcess process;
    process.process(arguments);
}
...
    TestProcess<t_float_array, t_complex_float_array, t_block_add<t_float_array> >();
    TestProcess<t_double_array, t_complex_double_array, t_block_add<t_double_array> >();

    TestProcess<t_float_array, t_float_array, t_block_add<t_float_array> >();
    TestProcess<t_double_array, t_double_array, t_block_add<t_double_array> >();

这种方法允许您根据需要指定精确的实现,完全基于编译时的信息和实例化。

但您可能需要发布一些特定代码和更具体的问题以获得更具体的答案。

祝你好运