diff --git a/Readme.md b/Readme.md
--- a/Readme.md
+++ b/Readme.md
@@ -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.
 
-![Screenshot](../screenshots/screenshots/screenshot.png?raw=true)
+![Screenshot](https://raw.githubusercontent.com/adamwalker/sdr/screenshots/screenshots/screenshot.png?raw=true)
 
 
 # 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 
diff --git a/benchmarks/Benchmarks.hs b/benchmarks/Benchmarks.hs
--- a/benchmarks/Benchmarks.hs
+++ b/benchmarks/Benchmarks.hs
@@ -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
diff --git a/hs_sources/SDR/FFT.hs b/hs_sources/SDR/FFT.hs
--- a/hs_sources/SDR/FFT.hs
+++ b/hs_sources/SDR/FFT.hs
@@ -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
diff --git a/hs_sources/SDR/FilterDesign.hs b/hs_sources/SDR/FilterDesign.hs
--- a/hs_sources/SDR/FilterDesign.hs
+++ b/hs_sources/SDR/FilterDesign.hs
@@ -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])
 
diff --git a/hs_sources/SDR/FilterInternal.hs b/hs_sources/SDR/FilterInternal.hs
--- a/hs_sources/SDR/FilterInternal.hs
+++ b/hs_sources/SDR/FilterInternal.hs
@@ -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
diff --git a/hs_sources/SDR/Util.hs b/hs_sources/SDR/Util.hs
--- a/hs_sources/SDR/Util.hs
+++ b/hs_sources/SDR/Util.hs
@@ -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 ()
diff --git a/sdr.cabal b/sdr.cabal
--- a/sdr.cabal
+++ b/sdr.cabal
@@ -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
