0

私は次の問題の解決策を見つけるために数日間インターネットを検索してきました。

私のプログラムでは、2つの16ビット.wavファイルからサウンドバッファ(タイプの配列short)にデータのチャンクを読み取り、ヒープにメモリを割り当てています。データはdoublefftw関数用にキャストされ、処理されてから縮小され、キャストさshortれてコレクションバッファーに配置されてから、出力ファイルがディスクに書き込まれます。このようにして、データのいくつかのチャンクを読み取っていて(つまり、ファイル内を移動し)、各反復でディスクに書き込みたくないので、ハードディスクにアクセスする必要がある回数を減らします。

これが私がしていることです:

short* sound_buffer_zero;
short* sound_buffer_one;
short* collection_buffer_one;
sound_buffer_zero = (short *) fftw_malloc(sizeof(short) * BUFFERSIZE); 
sound_buffer_one = (short *) fftw_malloc(sizeof(short) * BUFFERSIZE);
collection_buffer_one = (short *) fftw_malloc(sizeof(short) * COLLECTIONLENGTH);

// read BUFFERSIZE samples from file into sound_buffer
inFileZero.read((char*)sound_buffer_zero, sizeof(short)*BUFFERSIZE);
inFileOne.read((char*)sound_buffer_one, sizeof(short)*BUFFERSIZE);

// typecast the short int values of sound_buffer into double values
// and write them to in_
for(int p = 0; p < BUFFERSIZE; ++p) {
    *(in_zero + p) = (double)*(sound_buffer_zero + p);
    *(in_one + p) = (double)*(sound_buffer_one + p);
}

// cross correlation in the frequency domain
// FFT on input zero (output is f_zero)
fftw_execute(p_zero);

// FFT on input one (output is f_one)
fftw_execute(p_one);

// complex multiplication (output is almost_one, also array of type double)
fastCplxConjProd(almost_one, f_zero, f_one, COMPLEXLENGTH);

// IFFT on almost_one (output is out_one, array of double)
fftw_execute(pi_one);

// finalize the output array (sort the parts correctly, output is final_one, array of double)
// last half without first value becomes first half of final array
for(int i = ARRAYLENGTH/2 + 1; i < ARRAYLENGTH; ++i) {
    *(final_one + i - (ARRAYLENGTH/2 + 1)) = *(out_one + i);
}
// first half becomes second half of final array
for(int i = 0; i < ARRAYLENGTH/2; ++i) {
    *(final_one + i + (ARRAYLENGTH/2 - 1)) = *(out_one + i);
}

short* scaling_vector; 
scaling_vector = (short *) fftw_malloc(sizeof(short) * ARRAYLENGTH-1);

// fill the scaling_vector with the numbers from 1, 2, 3, ..., BUFFERSIZE, ..., 3, 2, 1
for(short i = 0; i < BUFFERSIZE; ++i) {
    *(scaling_vector + i) = i + 1;
    if(i + BUFFERSIZE > ARRAYLENGTH-1) break;
    *(scaling_vector + i + BUFFERSIZE) = BUFFERSIZE - i - 1;
}

// scale values in relation to their position in the output array
// to values suitable for short int for storage
for(int i = 0; i < ARRAYLENGTH-1; ++i) {
    *(final_one + i) = *(final_one + i) * SCALEFACTOR; // #define SCALEFACTOR SHRT_MAX/pow(2,42)
    *(final_one + i) = *(final_one + i) / *(scaling_vector + i);
}

// transform the double values of final_ into rounded short int values
// and write them to the collection buffer
for(int p = 0; p < ARRAYLENGTH-1; ++p) {
    *(collection_buffer_one + collectioncount*(ARRAYLENGTH) + p) = (short)round(*(final_one + p));
}

// write collection_buffer to disk
 outFileOne.write((char*)collection_buffer_one, sizeof(short)*collectioncount*(ARRAYLENGTH));

相互相関で計算される値はタイプdoubleであり、正または負の符号があります。それらを縮小することにより、符号は変わりません。しかしshort、collection_arrayに到着する数値にキャストすると、すべて正になります。

配列はとしてshortではなく、として宣言され、unsigned shortスケーリング後、値は保持できる範囲内にあります(投稿を読みやすくするためにすべてshortのコードを投稿したくないので、これを信頼する必要があります)。小数部の切り捨ては気にしません。それ以上の計算には必要ありませんが、符号は同じままである必要があります。

入力値と出力値の小さな例を次に示します(配列の最初の10個の値が示されています)。

input: 157
input: 4058
input: -1526
input: 1444
input: -774
input: -1507
input: -1615
input: -1895
input: -987
input: -1729

// converted to double
as double: 157
as double: 4058
as double: -1526
as double: 1444
as double: -774
as double: -1507
as double: -1615
as double: -1895
as double: -987
as double: -1729

// after the computations 
after scaling: -2.99445
after scaling: -42.6612
after scaling: -57.0962
after scaling: 41.0415
after scaling: -18.3168
after scaling: 43.5853
after scaling: -14.3663
after scaling: -3.58456
after scaling: -46.3902
after scaling: 16.0804

// in the collection array and before writing to disk
collection [short(round*(final_one))]: 3
collection [short(round*(final_one))]: 43
collection [short(round*(final_one))]: 57
collection [short(round*(final_one))]: 41
collection [short(round*(final_one))]: 18
collection [short(round*(final_one))]: 44
collection [short(round*(final_one))]: 14
collection [short(round*(final_one))]: 4
collection [short(round*(final_one))]: 46
collection [short(round*(final_one))]: 16

私の質問は、なぜ標識が保持されないのですか?内部転換が欠けていますか?他の投稿で私の質問に対する答えが見つかりませんでした。見逃した場合はお知らせください。重要な情報を省略した場合もお知らせください。ご協力いただきありがとうございます!

乾杯、マンゴー

テスト出力のコードは次のとおりです。

//contents of sound_buffer (input from file):
// test output
for(int i = 0; i < 10; ++i) {
    cout << "input: " << *(sound_buffer_zero + i) << endl;
}

// content of in_ after converting to double
// test output
for(int i = 0; i < 10; ++i) {
    cout << "as double: " << *(in_zero + i) << endl;
}

// contents of final_ after the scaling
// test output 
for(int i = 0; i < 10; ++i) {
    cout << "after scaling: " << *(final_one + i) << endl;
}

// contents of collection_buffer after converting to short
// test output
for(int i = 0; i < 10; ++i) {
    cout << "collection [short(round*(final_one))]: " << *(collection_buffer_one + i) << endl;
}

alegunaのおかげで、次の計算で兆候が消えることがわかりました。私は自分がしているそのステップを完全に逃していfinal_one = fabs(final_one)ました。私はそれをテストのために入れましたが、それを完全に忘れていました。

コメントと回答ありがとうございます。結局、私はただ愚かでした。ごめんなさい。

4

3 に答える 3

0

最適化をまったく行わずにコンパイルした場合、以下はプラットフォーム上でどのように実行されますか?

#include <stdlib.h>
#include <stdio.h>

double a[10] = { 
  -2.99445,
  -42.6612,
  -57.0962,
  41.0415,
  -18.3168,
  43.5853,
  -14.3663,
  -3.58456,
  -46.3902,
  16.0804
};

int main(){
  int i;
  for (i=0;i<10;++i){
    short k = (short)*(a + i);
    printf("%d\n", k);
  }

}

次の結果が得られます。

-2
-42
-57
41
-18
43
-14
-3
-46
16
于 2012-10-29T12:26:12.840 に答える
-2

通常、shortは2バイト長で、doubleは8バイト長です。doubleをshortにキャストすると、上位バイトが失われます。符号なしの実際のデータには2バイトで十分ですが、符号拡張によって上位バイトに格納されている符号情報が失われます。

于 2012-10-29T11:52:10.503 に答える