2010-06-27 2 views
2

저는 소프트웨어 정의 된 라디오 개념을 실험하려고합니다. 이 article에서 GPU 병렬 처리 이산 푸리에 변환을 구현하려고했습니다.F #/"Accelerator v2"아마도 DFT 알고리즘 구현이 잘못되었습니다

저는 죄의 90도 (i)를 미리 계산할 수 있다고 확신합니다. 그리고 나서이 코드에서 내가하고있는 일보다 플립 앤 플렉스를 반복하여 속도를 높일 수있을 것이라고 확신합니다. 그러나 지금까지 나는 정답을 얻고 있다고 생각지 않는다. 모든 제로 입력은 예상대로 0의 결과를 제공하지만 입력으로 모두 0.5이면 78.9985886f가됩니다 (이 경우에도 0 결과가 예상 됨). 기본적으로, 나는 대체로 혼란 스럽다. 나는 좋은 입력 데이터가 없으며 그 결과를 어떻게 처리할지 또는 어떻게 검증 하는지를 모른다.

이이 질문 here

open Microsoft.ParallelArrays 
open System 

// X64MulticoreTarget is faster on my machine, unexpectedly 
let target = new DX9Target() // new X64MulticoreTarget() 

ignore(target.ToArray1D(new FloatParallelArray([| 0.0f |]))) // Dummy operation to warm up the GPU 

let stopwatch = new System.Diagnostics.Stopwatch() // For benchmarking 

let Hz = 50.0f 
let fStep = (2.0f * float32(Math.PI))/Hz 
let shift = 0.0f // offset, once we have to adjust for the last batch of samples of a stream 

// If I knew that the periodic function is periodic 
// at whole-number intervals, I think I could keep 
// shift within a smaller range to support streams 
// without overflowing shift - but I haven't 
// figured that out 

//let elements = 8192 // maximum for a 1D array - makes sense as 2^13 
//let elements = 7240 // maximum on my machine for a 2D array, but why? 
let elements = 7240 

// need good data!! 
let buffer : float32[,] = Array2D.init<float32> elements elements (fun i j -> 0.5f) //(float32(i * elements) + float32(j))) 

let input = new FloatParallelArray(buffer) 
let seqN : float32[,] = Array2D.init<float32> elements elements (fun i j -> (float32(i * elements) + float32(j))) 
let steps = new FloatParallelArray(seqN) 
let shiftedSteps = ParallelArrays.Add(shift, steps) 
let increments = ParallelArrays.Multiply(fStep, steps) 
let cos_i = ParallelArrays.Cos(increments) // Real component series 
let sin_i = ParallelArrays.Sin(increments) // Imaginary component series 

stopwatch.Start() 
// From the documentation, I think ParallelArrays.Multiply does standard element by 
// element multiplication, not matrix multiplication 
// Then we sum each element for each complex component (I don't understand the relationship 
// of this, or the importance of the generalization to complex numbers) 
let real = target.ToArray1D(ParallelArrays.Sum(ParallelArrays.Multiply(input, cos_i))).[0] 
let imag = target.ToArray1D(ParallelArrays.Sum(ParallelArrays.Multiply(input, sin_i))).[0] 
printf "%A in " ((real * real) + (imag * imag)) // sum the squares for the presence of the frequency 
stopwatch.Stop() 

printfn "%A" stopwatch.ElapsedMilliseconds 

이 (System.Console.ReadKey())

+1

병렬 처리가 없으면 올바른 답을 얻을 수 있습니까? –

+0

그 방법을 어떻게 작동 시킬지 모르겠다. 다른 알고리즘을 모두 필요로한다고 생각한다. 그래도 나는 옳은 대답을 모른다. –

답변

2

답이 0에 가까워서 놀랍습니다. F #에서 DFT를 수행하고 불일치의 원인을 추적 할 수 있는지 확인하는 간단한 코드를 작성하는 것이 좋습니다. 희망 당신을위한 더 나은 직관을 얻기 위해이 순진 코드를 사용하는 방법 가속기 코드가 테스트에 여러분을 안내 할 수있는, 행동한다고 ​​

let N = 7240 
let F = 1.0f/50.0f 
let pi = single System.Math.PI 

let signal = [| for i in 1 .. N*N -> 0.5f |] 

let real = 
    seq { for i in 0 .. N*N-1 -> signal.[i] * (cos (2.0f * pi * F * (single i))) } 
    |> Seq.sum 

let img = 
    seq { for i in 0 .. N*N-1 -> signal.[i] * (sin (2.0f * pi * F * (single i))) } 
    |> Seq.sum 

let power = real*real + img*img 

을 : 여기

내가 당신이하려는 생각입니다 가속기 코드의 불일치의 이유 중 일부는 단순히 계산의 정밀도 일 수 있습니다 - 배열에 약 5 천 2 백만 개의 요소가 있으므로 전체 오류 79 개를 누적하면 실제로 나쁘지 않을 수도 있습니다. FWIW, 위의 단 정밀도 코드를 실행할 때 ~ 0.05의 거듭 제곱을 얻을 수 있지만 배정도 숫자가있는 동등 코드를 사용할 때는 ~ 4e-18의 거듭 제곱이됩니다.

2

두 제안을 무시할 내 다른 게시물에 관련된다 :

  • 어떻게 든 혼란 아니에요 확인 라디안으로도.
  • 시도해보십시오. sans-parallelism을 시도하거나 병렬 처리를 위해 F #의 비동기를 사용하십시오.
  • 당신은 당신이 '병렬로의 모든 단계를 추가'할 수

    다음
    let a : float[] = ... 
    

    수레의 배열이있는 경우

는 (F 번호에서 가진 새로운 배열을 생산하는

let aShift = a |> (fun x -> async { return x + shift }) 
       |> Async.Parallel |> Async.RunSynchronously 

(비록 이것이 동기 루프를 수행하는 것보다 느릴 수도 있습니다.)