sdr 0.1.0.8 → 0.1.0.9
raw patch · 7 files changed
+69/−65 lines, 7 filesdep ~sdrPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: sdr
API changes (from Hackage documentation)
- SDR.FFT: fftw :: (Vector v (Complex CDouble)) => Int -> IO (Pipe (v (Complex CDouble)) (Vector (Complex CDouble)) IO ())
+ SDR.FFT: fftw :: (Vector v (Complex Double)) => Int -> IO (Pipe (v (Complex Double)) (Vector (Complex Double)) IO ())
- SDR.FFT: fftw' :: (Vector v (Complex CDouble)) => Int -> IO (v (Complex CDouble) -> IO (Vector (Complex CDouble)))
+ SDR.FFT: fftw' :: (Vector v (Complex Double)) => Int -> IO (v (Complex Double) -> IO (Vector (Complex Double)))
- SDR.FFT: fftwParallel :: (Vector v (Complex CDouble)) => Int -> Int -> IO (Pipe (v (Complex CDouble)) (Vector (Complex CDouble)) IO ())
+ SDR.FFT: fftwParallel :: (Vector v (Complex Double)) => Int -> Int -> IO (Pipe (v (Complex Double)) (Vector (Complex Double)) IO ())
- SDR.FFT: fftwReal :: (Vector v CDouble) => Int -> IO (Pipe (v CDouble) (Vector (Complex CDouble)) IO ())
+ SDR.FFT: fftwReal :: (Vector v Double) => Int -> IO (Pipe (v Double) (Vector (Complex Double)) IO ())
- SDR.FFT: fftwReal' :: (Vector v CDouble) => Int -> IO (v CDouble -> IO (Vector (Complex CDouble)))
+ SDR.FFT: fftwReal' :: (Vector v Double) => Int -> IO (v Double -> IO (Vector (Complex Double)))
- SDR.FilterDesign: plotFrequency :: [Double] -> IO ()
+ SDR.FilterDesign: plotFrequency :: [Double] -> FilePath -> IO ()
Files
- Readme.md +6/−4
- benchmarks/Benchmarks.hs +1/−1
- hs_sources/SDR/FFT.hs +17/−16
- hs_sources/SDR/FilterDesign.hs +3/−2
- hs_sources/SDR/FilterInternal.hs +22/−22
- hs_sources/SDR/Util.hs +17/−17
- sdr.cabal +3/−3
Readme.md view
@@ -2,6 +2,8 @@ A Software Defined Radio library written in Haskell +See the [blog post](https://adamwalker.github.io/Introducing-SDR/).+ # Features * Write software defined radio applications in Haskell * Signal processing blocks can be chained together using the [Pipes](https://hackage.haskell.org/package/pipes) library@@ -23,7 +25,7 @@ # Screenshot A chunk of the FM broadcast spectrum. Captured with an RTLSDR device and drawn as a waterfall using the [Plot](https://github.com/adamwalker/sdr/blob/master/hs_sources/SDR/Plot.hs) module. -+ # Getting Started@@ -88,8 +90,8 @@ import Data.Vector.Generic as VG import Pipes import qualified Pipes.Prelude as P-import Foreign.Storable.Complex + import SDR.Filter import SDR.RTLSDRStream import SDR.Util@@ -107,7 +109,7 @@ info <- lift getCPUInfo - str <- sdrStream frequency 1280000 1 (fromIntegral samples * 2)+ str <- sdrStream (defaultRTLSDRParams frequency 1280000) 1 (fromIntegral samples * 2) lift $ do @@ -118,7 +120,7 @@ filt <- fastFilterSymR info coeffsAudioFilter runEffect $ str- >-> P.map convertCAVX + >-> P.map (interleavedIQUnsignedByteToFloatFast info) >-> firDecimator deci samples >-> fmDemod >-> firResampler resp samples
benchmarks/Benchmarks.hs view
@@ -11,7 +11,7 @@ import qualified Data.Vector.Generic.Mutable as VGM import qualified Data.Vector.Storable as VS import qualified Data.Vector.Storable.Mutable as VSM-import qualified Data.Vector.Fusion.Stream as VFS+import qualified Data.Vector.Fusion.Bundle as VFS import qualified Data.Vector.Fusion.Stream.Monadic as VFSM import Foreign.Storable.Complex
hs_sources/SDR/FFT.hs view
@@ -23,6 +23,7 @@ import Foreign.ForeignPtr import Control.Concurrent hiding (yield) import qualified Data.Map as Map+import Data.Coerce import qualified Data.Vector.Generic as VG import qualified Data.Vector.Storable as VS@@ -40,9 +41,9 @@ newForeignPtr fftwFreePtr ptr -- | Creates a function that performs a complex to complex DFT.-fftw' :: (VG.Vector v (Complex CDouble)) +fftw' :: (VG.Vector v (Complex Double)) => Int -- ^ The size of the input and output buffers- -> IO (v (Complex CDouble) -> IO (VS.Vector (Complex CDouble)))+ -> IO (v (Complex Double) -> IO (VS.Vector (Complex Double))) fftw' samples = do ina <- mallocForeignBufferAligned samples out <- mallocForeignBufferAligned samples@@ -60,24 +61,24 @@ let (fp, offset, length) = VSM.unsafeToForeignPtr inv - withForeignPtr fp $ \fpp -> - withForeignPtr out $ \op -> + withForeignPtr (coerce fp) $ \fpp -> + withForeignPtr (coerce out) $ \op -> executeDFT plan fpp op return $ VS.unsafeFromForeignPtr0 out samples -- | Creates a Pipe that performs a complex to complex DFT.-fftw :: (VG.Vector v (Complex CDouble)) +fftw :: (VG.Vector v (Complex Double)) => Int -- ^ The size of the input and output buffers- -> IO (Pipe (v (Complex CDouble)) (VS.Vector (Complex CDouble)) IO ())+ -> IO (Pipe (v (Complex Double)) (VS.Vector (Complex Double)) IO ()) fftw samples = do func <- fftw' samples return $ for cat $ \dat -> lift (func dat) >>= yield -- | Creates a function that performs a real to complex DFT.-fftwReal' :: (VG.Vector v CDouble) +fftwReal' :: (VG.Vector v Double) => Int -- ^ The size of the input Vector- -> IO (v CDouble -> IO (VS.Vector (Complex CDouble)))+ -> IO (v Double -> IO (VS.Vector (Complex Double))) fftwReal' samples = do --Allocate in and out buffers that wont be used because there doesnt seem to be a way to create a plan without them ina <- mallocForeignBufferAligned samples@@ -95,16 +96,16 @@ copyInto inv inv' let (fp, offset, length) = VSM.unsafeToForeignPtr inv - withForeignPtr fp $ \fpp -> - withForeignPtr out $ \op -> + withForeignPtr (coerce fp) $ \fpp -> + withForeignPtr (coerce out) $ \op -> executeDFTR2C plan fpp op return $ VS.unsafeFromForeignPtr0 out samples -- | Creates a pipe that performs a real to complex DFT.-fftwReal :: (VG.Vector v CDouble) +fftwReal :: (VG.Vector v Double) => Int -- ^ The size of the input Vector- -> IO (Pipe (v CDouble) (VS.Vector (Complex CDouble)) IO ())+ -> IO (Pipe (v Double) (VS.Vector (Complex Double)) IO ()) fftwReal samples = do func <- fftwReal' samples return $ for cat $ \dat -> lift (func dat) >>= yield@@ -114,10 +115,10 @@ a pool of threads to perform the DFT. Then, if a thread has finished performing a previous DFT, the result is yielded. -}-fftwParallel :: (VG.Vector v (Complex CDouble)) +fftwParallel :: (VG.Vector v (Complex Double)) => Int -- ^ The number of threads to use -> Int -- ^ The size of the input Vector- -> IO (Pipe (v (Complex CDouble)) (VS.Vector (Complex CDouble)) IO ())+ -> IO (Pipe (v (Complex Double)) (VS.Vector (Complex Double)) IO ()) fftwParallel threads samples = do --plan the DFT ina <- mallocForeignBufferAligned samples@@ -142,8 +143,8 @@ let (fp, offset, length) = VSM.unsafeToForeignPtr inv - withForeignPtr fp $ \fpp -> - withForeignPtr out $ \op -> + withForeignPtr (coerce fp) $ \fpp -> + withForeignPtr (coerce out) $ \op -> executeDFT plan fpp op theMap <- takeMVar outMap
hs_sources/SDR/FilterDesign.hs view
@@ -72,10 +72,11 @@ where func phase = magnitude $ sum $ zipWith (\index mag -> mkPolar mag (phase * (- index))) (iterate (+ 1) (- ((fromIntegral (length coeffs) - 1) / 2))) coeffs --- | Given filter coefficients, plot their frequency response and save the graph as "frequency_response.png".+-- | Given filter coefficients, plot their frequency response and save the graph as a png file plotFrequency :: [Double] -- ^ The filter coefficients+ -> FilePath -- ^ The filename -> IO ()-plotFrequency coeffs = toFile def "frequency_response.png" $ do+plotFrequency coeffs fName = toFile def fName $ do layout_title .= "Frequency Response" plot (line "Frequency Response" [signal coeffs $ takeWhile (< pi) $ iterate (+ 0.01) 0])
hs_sources/SDR/FilterInternal.hs view
@@ -10,7 +10,7 @@ import Control.Monad import Foreign.C.Types import Foreign.Ptr-import Unsafe.Coerce+import Data.Coerce import Data.Complex import Foreign.Marshal.Array import Foreign.Marshal.Alloc@@ -65,16 +65,16 @@ filterFFIR :: FilterCRR -> FilterRR filterFFIR func coeffs num inBuf outBuf = - VS.unsafeWith (unsafeCoerce coeffs) $ \cPtr -> - VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VS.unsafeWith (coerce coeffs) $ \cPtr -> + VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> func (fromIntegral num) (fromIntegral $ VG.length coeffs) cPtr iPtr oPtr filterFFIC :: FilterCRR -> FilterRC filterFFIC func coeffs num inBuf outBuf = - VS.unsafeWith (unsafeCoerce coeffs) $ \cPtr -> - VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VS.unsafeWith (coerce coeffs) $ \cPtr -> + VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> func (fromIntegral num) (fromIntegral $ VG.length coeffs) cPtr iPtr oPtr foreign import ccall unsafe "filterRR"@@ -164,16 +164,16 @@ decimateFFIR :: DecimateCRR -> DecimateRR decimateFFIR func factor coeffs num inBuf outBuf = - VS.unsafeWith (unsafeCoerce coeffs) $ \cPtr -> - VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VS.unsafeWith (coerce coeffs) $ \cPtr -> + VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> func (fromIntegral num) (fromIntegral factor) (fromIntegral $ VG.length coeffs) cPtr iPtr oPtr decimateFFIC :: DecimateCRR -> DecimateRC decimateFFIC func factor coeffs num inBuf outBuf = - VS.unsafeWith (unsafeCoerce coeffs) $ \cPtr -> - VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VS.unsafeWith (coerce coeffs) $ \cPtr -> + VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> func (fromIntegral num) (fromIntegral factor) (fromIntegral $ VG.length coeffs) cPtr iPtr oPtr foreign import ccall unsafe "decimateRR"@@ -269,9 +269,9 @@ resampleCRR :: Int -> Int -> Int -> Int -> VS.Vector Float -> VS.Vector Float -> VS.MVector RealWorld Float -> IO () resampleCRR num interpolation decimation offset coeffs inBuf outBuf = - VS.unsafeWith (unsafeCoerce coeffs) $ \cPtr -> - VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VS.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VS.unsafeWith (coerce coeffs) $ \cPtr -> + VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> resample_c (fromIntegral num) (fromIntegral $ VG.length coeffs) (fromIntegral interpolation) (fromIntegral decimation) (fromIntegral offset) cPtr iPtr oPtr pad :: a -> Int -> [a] -> [a]@@ -320,14 +320,14 @@ resampleFFIR :: (Ptr CFloat -> Ptr CFloat -> IO CInt) -> VS.Vector Float -> VSM.MVector RealWorld Float -> IO Int resampleFFIR func inBuf outBuf = liftM fromIntegral $- VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VS.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> func iPtr oPtr resampleFFIC :: (Ptr CFloat -> Ptr CFloat -> IO CInt) -> VS.Vector (Complex Float) -> VSM.MVector RealWorld (Complex Float) -> IO Int resampleFFIC func inBuf outBuf = liftM fromIntegral $- VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VS.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> func iPtr oPtr type ResampleR = CInt -> CInt -> CInt -> CInt -> Ptr CInt -> Ptr (Ptr CFloat) -> Ptr CFloat -> Ptr CFloat -> IO CInt@@ -429,8 +429,8 @@ dcBlocker num lastSample lastOutput inBuf outBuf = alloca $ \fsp -> alloca $ \fop -> - VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> do+ VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> do c_dcBlocker (fromIntegral num) (realToFrac lastSample) (realToFrac lastOutput) fsp fop iPtr oPtr r1 <- peek fsp r2 <- peek fop
hs_sources/SDR/Util.hs view
@@ -59,7 +59,7 @@ import qualified Data.Vector.Storable as VS import qualified Data.Vector.Storable.Mutable as VSM import Control.Monad.Primitive-import Unsafe.Coerce+import Data.Coerce import Foreign.Ptr import System.IO.Unsafe import Foreign.Storable.Complex@@ -105,7 +105,7 @@ interleavedIQUnsignedByteToFloat inBuf = unsafePerformIO $ do outBuf <- VGM.new $ VG.length inBuf `quot` 2 VS.unsafeWith inBuf $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> convertC_c (fromIntegral $ VG.length inBuf) iPtr oPtr VG.freeze outBuf @@ -117,7 +117,7 @@ interleavedIQUnsignedByteToFloatSSE inBuf = unsafePerformIO $ do outBuf <- VGM.new $ VG.length inBuf `quot` 2 VS.unsafeWith inBuf $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> convertCSSE_c (fromIntegral $ VG.length inBuf) iPtr oPtr VG.freeze outBuf @@ -129,7 +129,7 @@ interleavedIQUnsignedByteToFloatAVX inBuf = unsafePerformIO $ do outBuf <- VGM.new $ VG.length inBuf `quot` 2 VS.unsafeWith inBuf $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> convertCAVX_c (fromIntegral $ VG.length inBuf) iPtr oPtr VG.freeze outBuf @@ -155,7 +155,7 @@ interleavedIQSignedWordToFloat inBuf = unsafePerformIO $ do outBuf <- VGM.new $ VG.length inBuf `quot` 2 VS.unsafeWith inBuf $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> convertCBladeRF_c (fromIntegral $ VG.length inBuf) iPtr oPtr VG.freeze outBuf @@ -167,7 +167,7 @@ interleavedIQSignedWordToFloatSSE inBuf = unsafePerformIO $ do outBuf <- VGM.new $ VG.length inBuf `quot` 2 VS.unsafeWith inBuf $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> convertCSSEBladeRF_c (fromIntegral $ VG.length inBuf) iPtr oPtr VG.freeze outBuf @@ -179,7 +179,7 @@ interleavedIQSignedWordToFloatAVX inBuf = unsafePerformIO $ do outBuf <- VGM.new $ VG.length inBuf `quot` 2 VS.unsafeWith inBuf $ \iPtr -> - VSM.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> convertCAVXBladeRF_c (fromIntegral $ VG.length inBuf) iPtr oPtr VG.freeze outBuf @@ -205,7 +205,7 @@ complexFloatToInterleavedIQSignedWord :: VS.Vector (Complex Float) -> VS.Vector CShort complexFloatToInterleavedIQSignedWord inBuf = unsafePerformIO $ do outBuf <- VGM.new $ VG.length inBuf * 2- VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> + VS.unsafeWith (coerce inBuf) $ \iPtr -> VSM.unsafeWith outBuf $ \oPtr -> convertBladeRFTransmit_c (fromIntegral $ VG.length inBuf * 2) iPtr oPtr VG.freeze outBuf@@ -220,9 +220,9 @@ -> VS.MVector RealWorld Float -- ^ Output vector -> IO () scaleC factor inBuf outBuf = - VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VS.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> - scale_c (fromIntegral (VG.length inBuf)) (unsafeCoerce factor) iPtr oPtr+ VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> + scale_c (fromIntegral (VG.length inBuf)) (coerce factor) iPtr oPtr foreign import ccall unsafe "scaleSSE" scaleSSE_c :: CInt -> CFloat -> Ptr CFloat -> Ptr CFloat-> IO ()@@ -233,9 +233,9 @@ -> VS.MVector RealWorld Float -- ^ Output vector -> IO () scaleCSSE factor inBuf outBuf = - VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VS.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> - scaleSSE_c (fromIntegral (VG.length inBuf)) (unsafeCoerce factor) iPtr oPtr+ VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> + scaleSSE_c (fromIntegral (VG.length inBuf)) (coerce factor) iPtr oPtr foreign import ccall unsafe "scaleAVX" scaleAVX_c :: CInt -> CFloat -> Ptr CFloat -> Ptr CFloat -> IO ()@@ -246,9 +246,9 @@ -> VS.MVector RealWorld Float -- ^ Output vector -> IO () scaleCAVX factor inBuf outBuf = - VS.unsafeWith (unsafeCoerce inBuf) $ \iPtr -> - VS.unsafeWith (unsafeCoerce outBuf) $ \oPtr -> - scaleAVX_c (fromIntegral (VG.length inBuf)) (unsafeCoerce factor) iPtr oPtr+ VS.unsafeWith (coerce inBuf) $ \iPtr -> + VSM.unsafeWith (coerce outBuf) $ \oPtr -> + scaleAVX_c (fromIntegral (VG.length inBuf)) (coerce factor) iPtr oPtr -- | Scale a vector. Uses the fastest SIMD instruction set your processor supports. scaleFast :: CPUInfo -> Float -> VS.Vector Float -> VS.MVector RealWorld Float -> IO ()
sdr.cabal view
@@ -1,5 +1,5 @@ name: sdr-version: 0.1.0.8+version: 0.1.0.9 synopsis: A software defined radio library description: Write software defined radio applications in Haskell.@@ -117,7 +117,7 @@ base >=4.6 && <5, QuickCheck >=2.8 && <2.10, vector >=0.11 && <0.12, - sdr ==0.1.0.8, + sdr ==0.1.0.9, primitive >=0.5 && <0.7, storable-complex >=0.2 && <0.3, test-framework >=0.8 && <0.9,@@ -133,7 +133,7 @@ base >=4.6 && <5, criterion >=1.0 && <1.2, vector >=0.11 && <0.12, - sdr ==0.1.0.8, + sdr ==0.1.0.9, primitive >=0.5 && <0.7, storable-complex >=0.2 && <0.3 hs-source-dirs: benchmarks