module Numeric.Transform.Fourier.FFTUtils (
fft_mag, fft_db, fft_phase, fft_grd, fft_info,
rfft_mag, rfft_db, rfft_phase, rfft_grd, rfft_info,
write_fft_info, write_rfft_info,
) where
import System.IO
import Data.Array
import Data.Complex
import Numeric.Transform.Fourier.FFT
import DSP.Unwrap
magsq :: RealFloat a => Complex a -> a
magsq (x:+y) = x*x + y*y
log10 :: (Floating a, Eq a) => a -> a
log10 0 = -1.0e9
log10 x = logBase 10 x
dot :: RealFloat a => Complex a -> Complex a -> a
dot a b = realPart a * realPart b + imagPart a * imagPart b
eps :: Double
eps = 1.0e-1 :: Double
fft_mag :: (RealFloat b, Integral a, Ix a) =>
Array a (Complex b) -> Array a b
fft_mag x = fmap magnitude $ fft $ x
fft_db :: (RealFloat b, Integral a, Ix a) =>
Array a (Complex b) -> Array a b
fft_db x = fmap (10 *) $ fmap log10 $ fmap magsq $ fft $ x
fft_phase :: (Integral a, Ix a) =>
Array a (Complex Double) -> Array a Double
fft_phase x = unwrap eps $ fmap phase $ fft $ x
fft_grd :: (Integral i, RealFloat a, Ix i) =>
Array i (Complex a) -> Array i a
fft_grd x = listArray (bounds x') [ dot (x'!i) (dx'!i) / magsq (x'!i) | i <- indices x' ]
where x' = fft x
dx' = fft $ listArray (bounds x) [ fromIntegral i * x!i | i <- indices x ]
fft_info :: (Integral i, Ix i) =>
Array i (Complex Double)
-> (Array i Double, Array i Double, Array i Double, Array i Double)
fft_info x = (mag,db,arg,grd)
where x' = fft x
dx' = fft $ listArray (bounds x) [ fromIntegral i * x!i | i <- indices x ]
mag = fmap magnitude $ x'
db = fmap (10 *) $ fmap log10 $ fmap magsq $ x'
arg = unwrap eps $ fmap phase $ x'
grd = listArray (bounds x') [ dot (x'!i) (dx'!i) / magsq (x'!i) | i <- indices x' ]
rfft_mag :: (RealFloat b, Integral a, Ix a) =>
Array a b -> Array a b
rfft_mag x = fmap magnitude $ rfft $ x
rfft_db :: (RealFloat b, Integral a, Ix a) =>
Array a b -> Array a b
rfft_db x = fmap (10 *) $ fmap log10 $ fmap magsq $ rfft $ x
rfft_phase :: (Integral a, Ix a) =>
Array a Double -> Array a Double
rfft_phase x = unwrap eps $ fmap phase $ rfft $ x
rfft_grd :: (Integral i, Ix i, RealFloat a) =>
Array i a -> Array i a
rfft_grd x = listArray (bounds x') [ dot (x'!i) (dx'!i) / magsq (x'!i) | i <- indices x' ]
where x' = rfft x
dx' = rfft $ listArray (bounds x) [ fromIntegral i * x!i | i <- indices x ]
rfft_info :: (Integral i, Ix i) =>
Array i Double
-> (Array i Double, Array i Double, Array i Double, Array i Double)
rfft_info x = (mag,db,arg,grd)
where x' = rfft x
dx' = rfft $ listArray (bounds x) [ fromIntegral i * x!i | i <- indices x ]
mag = fmap magnitude $ x'
db = fmap (10 *) $ fmap log10 $ fmap magsq $ x'
arg = unwrap eps $ fmap phase $ x'
grd = listArray (bounds x') [ dot (x'!i) (dx'!i) / magsq (x'!i) | i <- indices x' ]
hPrintIndex :: (Integral a, Integral i, Show b) =>
Handle -> i -> (a, b) -> IO ()
hPrintIndex h n (i,x) = do
hPutStr h $ show (fromIntegral i / fromIntegral n :: Double)
hPutStr h $ " "
hPutStrLn h $ show x
write_cvector :: (Show e, Integral i, Ix i) =>
FilePath -> Array i e -> IO ()
write_cvector f x = do
let n = (snd $ bounds x) + 1
withFile f WriteMode $ \h ->
mapM_ (hPrintIndex h n) $ assocs x
write_fft_info :: (Ix i, Integral i) =>
String -> Array i (Complex Double) -> IO ()
write_fft_info b x = do
let (mag,db,arg,grd) = fft_info x
write_cvector (b ++ "_mag.out") mag
write_cvector (b ++ "_db.out") db
write_cvector (b ++ "_arg.out") arg
write_cvector (b ++ "_grd.out") grd
write_rvector :: Show e => FilePath -> Array Int e -> IO ()
write_rvector f x = do
let n = (snd $ bounds x) + 1
withFile f WriteMode $ \h ->
mapM_ (hPrintIndex h n) $ take (n `div` 2) $ assocs x
write_rfft_info :: String -> Array Int Double -> IO ()
write_rfft_info b x = do
let (mag,db,arg,grd) = rfft_info x
write_rvector (b ++ "_mag.out") mag
write_rvector (b ++ "_db.out") db
write_rvector (b ++ "_arg.out") arg
write_rvector (b ++ "_grd.out") grd