我creating a ruby wrapper的fftw3库Scientific Ruby Foundation使用nmatrix对象而非常规ruby数组。
我在返回变换后的数组时遇到了一个奇怪的问题,我不知道如何做到这一点所以我可以检查变换是否已经在我的规范中对八度或(类似这样)进行了正确计算
我有一个想法,我可能最好将输出数组out
(fftw_complex
类型)转换为VALUE,以便在返回之前将其传递给nmatrix对象,但我不确定是否应该用智慧从fftw中获取价值。
static VALUE
fftw_r2c_one(VALUE self, VALUE nmatrix)
{
VALUE cNMatrix = rb_define_class("NMatrix", rb_cObject);
fftw_plan plan;
VALUE shape = rb_funcall(nmatrix, rb_intern("shape"), 0);
const int size = NUM2INT(rb_funcall(cNMatrix, rb_intern("size"), 1, shape));
double* in = ALLOC_N(double, size);
for (int i = 0; i < size; i++)
{
in[i] = NUM2DBL(rb_funcall(nmatrix, rb_intern("[]"), 1, INT2FIX(i)));
printf("IN[%d]: in[%.2f] \n", i, in[i]);
}
fftw_complex* out = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * size + 1);
plan = fftw_plan_dft_r2c(1,&size, in, out, FFTW_ESTIMATE);
fftw_execute(plan);
fftw_destroy_plan(plan);
xfree(in);
fftw_free(out);
return nmatrix;
}
如果你愿意,可以随意从github clone the repo开始玩游戏。
注意:在开始此项目之前,我对fftw3
并不熟悉且未使用C
(或ruby
)。到目前为止,我已经习惯了java
,python
和javascript
,因此无法完全了解内存管理等较低级别的概念,但我正在使用此项目。请在你的答案中牢记这一点,并试着看到他们对某人是明确的,并且最近他们主要习惯于面向对象的方法到目前为止通过避免使用行话(或注意指出)会真的有帮助。
谢谢。
答案 0 :(得分:0)
如果您希望看到使用FFTW带来任何性能优势,那么您需要对此代码进行重新分解,以便对于给定的FFT大小仅执行一次计划生成,因为计划生成成本非常高,而执行时该计划是绩效收益的来源。
你可以
a)有两个入口点 - 生成计划的初始化例程,然后是执行计划的主要入口点
b)使用记忆技术,这样您只需在第一次调用给定的FFT维度时生成计划一次,然后缓存计划以供后续重复使用。
b)的优点是它是一个更简洁的实现,只有一个入口点;缺点是如果你调用尺寸经常变化的函数就会中断。
答案 1 :(得分:0)
我从Colin Fuller得到了一些建议,经过他的一些指示我想出了这个解决方案:
VALUE fftw_complex_to_nm_complex(fftw_complex* in) {
double real = ((double (*)) in)[1];
double imag = ((double (*)) in)[2];
VALUE mKernel = rb_define_module("Kernel");
return rb_funcall(mKernel,
rb_intern("Complex"),
2,
rb_float_new(real),
rb_float_new(imag));
}
/**
fftw_r2c
@param self
@param nmatrix
@return nmatrix
With FFTW_ESTIMATE as a flag in the plan,
the input and and output are not overwritten at runtime
The plan will use a heuristic approach to picking plans
rather than take measurements
*/
static VALUE
fftw_r2c_one(VALUE self, VALUE nmatrix)
{
/**
Define and initialise the NMatrix class:
The initialisation rb_define_class will
just retrieve the NMatrix class that already exists
or define a new class altogether if it does not
find NMatrix. */
VALUE cNMatrix = rb_define_class("NMatrix", rb_cObject);
fftw_plan plan;
const int rank = rb_iv_set(self, "@rank", 1);
// shape is a ruby array, e.g. [2, 2] for a 2x2 matrix
VALUE shape = rb_funcall(nmatrix, rb_intern("shape"), 0);
// size is the number of elements stored for a matrix with dimensions = shape
const int size = NUM2INT(rb_funcall(cNMatrix, rb_intern("size"), 1, shape));
double* in = ALLOC_N(double, size);
fftw_complex* out = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * size * size);
for (int i = 0; i < size; i++)
{
in[i] = NUM2DBL(rb_funcall(nmatrix, rb_intern("[]"), 1, INT2FIX(i)));;
}
plan = fftw_plan_dft_r2c(1,&size, in, out, FFTW_ESTIMATE);
fftw_execute(plan);
for (int i = 0; i < 2; i++)
{
rb_funcall(nmatrix, rb_intern("[]="), 2, INT2FIX(i), fftw_complex_to_nm_complex(out + i));
}
// INFO: http://www.fftw.org/doc/New_002darray-Execute-Functions.html#New_002darray-Execute-Functions
fftw_destroy_plan(plan);
xfree(in);
fftw_free(out);
return nmatrix;
}
getting the specs to recognise the output types
中我唯一想解决的问题ruby core Complex API