summaryrefslogtreecommitdiff
path: root/Radio/Utils
diff options
context:
space:
mode:
Diffstat (limited to 'Radio/Utils')
-rw-r--r--Radio/Utils/WaterfallFile/NaiveFFT.swift7
-rw-r--r--Radio/Utils/WaterfallFile/SimpleImage.swift116
-rw-r--r--Radio/Utils/WaterfallFile/main.swift113
3 files changed, 236 insertions, 0 deletions
diff --git a/Radio/Utils/WaterfallFile/NaiveFFT.swift b/Radio/Utils/WaterfallFile/NaiveFFT.swift
new file mode 100644
index 0000000..79393b7
--- /dev/null
+++ b/Radio/Utils/WaterfallFile/NaiveFFT.swift
@@ -0,0 +1,7 @@
+//
+// NaiveFFT.swift
+// PrySDR
+//
+// Created by Jacky Jack on 05/01/2025.
+//
+
diff --git a/Radio/Utils/WaterfallFile/SimpleImage.swift b/Radio/Utils/WaterfallFile/SimpleImage.swift
new file mode 100644
index 0000000..c05709f
--- /dev/null
+++ b/Radio/Utils/WaterfallFile/SimpleImage.swift
@@ -0,0 +1,116 @@
+//
+// Image.swift
+// PrySDR
+//
+// Created by Jacky Jack on 27/12/2024.
+//
+
+import Foundation
+import AppKit
+
+// https://stackoverflow.com/questions/30958427/pixel-array-to-uiimage-in-swift
+public struct PixelData {
+ var a: UInt8
+ var r: UInt8
+ var g: UInt8
+ var b: UInt8
+}
+
+public class SimpleImage {
+
+ private var pixels: [PixelData] = []
+ private var width:Int = 0
+ private var height:Int = 0
+
+ init(width: Int, height: Int) {
+ self.width = width
+ self.height = height
+ pixels = .init(repeating: .init(a: 255, r: 0, g: 0, b: 0), count: width*height)
+ }
+
+
+ func drawPalletLine(line: Int, pixelLine:[Float]) {
+ for i in 0..<self.width {
+ var pixel = pixelLine[i]
+ if pixel>256.0 {
+ //print("values to high")
+ pixel = 255.0
+ }
+ if pixel < 0.0 {
+ pixel = 0.0
+ }
+ self.pixels[line*self.width + i].a = 255
+ self.pixels[line*self.width + i].r = UInt8(pixel)
+ self.pixels[line*self.width + i].g = UInt8(pixel)
+ self.pixels[line*self.width + i].b = UInt8(pixel)
+ }
+ }
+
+ func drawPixel(_ w: Int, _ h: Int, _ pixel: PixelData) {
+ self.pixels[h*self.height+w] = pixel
+ }
+
+ func toCGImage() -> CGImage? {
+ guard self.width > 0 && self.height > 0 else { return nil }
+ guard self.pixels.count == self.width * self.height else { return nil }
+
+ let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
+ let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
+ let bitsPerComponent = 8
+ let bitsPerPixel = 32
+
+ var data = self.pixels // Copy to mutable []
+ guard let providerRef = CGDataProvider(data: NSData(bytes: &data,
+ length: data.count * MemoryLayout<PixelData>.size)
+ )
+ else { return nil }
+
+ guard let cgim = CGImage(
+ width: self.width,
+ height: self.height,
+ bitsPerComponent: bitsPerComponent,
+ bitsPerPixel: bitsPerPixel,
+ bytesPerRow: self.width * MemoryLayout<PixelData>.size,
+ space: rgbColorSpace,
+ bitmapInfo: bitmapInfo,
+ provider: providerRef,
+ decode: nil,
+ shouldInterpolate: true,
+ intent: .defaultIntent
+ )
+ else { return nil }
+
+ return cgim
+ }
+
+ func toNSImage() -> NSImage? {
+ guard let cgim = toCGImage() else { return nil }
+ return NSImage(cgImage: cgim, size:.zero)
+ }
+
+ func saveAsJPEG(_ image: NSImage, _ name: String) {
+ if let imageData = image.tiffRepresentation {
+ do {
+ let bundlePath = Bundle.main.resourcePath!
+ let imageUrl = URL(fileURLWithPath:bundlePath+"/"+name)
+ try imageData.write(to: imageUrl)
+
+ } catch {
+ print("Cant save image to disk")
+ }
+
+ } else {
+ print("cant get tiff representation")
+ }
+ }
+
+ func saveAsJPEG(_ name: String) {
+ if let img = self.toNSImage() {
+ saveAsJPEG(img, name)
+ }
+ }
+}
+
+
+
+
diff --git a/Radio/Utils/WaterfallFile/main.swift b/Radio/Utils/WaterfallFile/main.swift
new file mode 100644
index 0000000..cf72d56
--- /dev/null
+++ b/Radio/Utils/WaterfallFile/main.swift
@@ -0,0 +1,113 @@
+//
+// main.swift
+// WaterfallFile
+//
+// Created by Jacky Jack on 23/12/2024.
+//
+
+import Foundation
+import Accelerate
+
+print("Read binary file")
+
+let input_filename="rtlsdr_100M_m.cu8"
+
+
+//get data from u8 file
+let dir = getCurrentExecutableDir()
+let filemgr = FileManager.default
+
+if !filemgr.fileExists(atPath: input_filename) {
+ print("Cant find file \(input_filename)")
+ exit(0)
+}
+
+let fileHandle: FileHandle? = FileHandle(forReadingAtPath: dir+"/"+input_filename)
+var i8_arr:[Int8]? = nil
+if let file = fileHandle {
+ file.seek(toFileOffset: 0)
+ do {
+ if let databuf = try file.readToEnd() {
+
+ print("read \(databuf.count) \(databuf) bytes")
+ //let temp_arr = [Int8](databuf)
+ i8_arr = [Int8](repeating: 0, count: databuf.count)
+
+ for i in 0..<i8_arr!.count {
+ print(String(format:"%02X", databuf[i]),terminator: "")
+ //convert from 0..255 to -127..128
+ let val = databuf[i]
+ if val <= 127 {
+ i8_arr![i] = Int8(val)-127
+ } else {
+ i8_arr![i] = Int8(val-128)
+ }
+ //print(String(format:"%02X", i8_arr![i]),terminator: "")
+ }
+ }
+ } catch {
+ print(error)
+ exit(0)
+ }
+
+}
+fileHandle?.closeFile()
+
+//all data in buffer lets process data
+//convert all u8 data to float's
+
+//is there other ways to do that?
+/*for i in 0..<dataFloat.count {
+ dataFloat[i] = Float(u8_arr![i])
+}*/
+//will generate 512x512 image
+let sampleCount = 512
+let img = SimpleImage(width: sampleCount, height: sampleCount)
+let number_of_lines = (i8_arr!.count/sampleCount)
+let forwardDCT = vDSP.DCT(count: sampleCount, transformType: .II)!
+var frequencyDomain:[Float] = []
+var transform_result:[Float] = .init(repeating: 0.0, count: sampleCount)
+var dataFloat = [Float](repeating: 0.0, count: sampleCount)
+for i in 0..<sampleCount {
+ let sample_idx = i*sampleCount
+ if i < number_of_lines {
+ let processingSlice = i8_arr![sample_idx...sample_idx+512-1]
+ let processingArray = Array(processingSlice)
+ vDSP.convertElements(of: processingArray, to: &dataFloat)
+ //dataFloat = vDSP.add(127.0, dataFloat)
+ //print(dataFloat)
+
+ //move from -127.0 to 128.0 range -1.0...1.0
+ //var adjusted = vDSP.divide(dataFloat, Float(sampleCount))
+ var adjusted = dataFloat
+ //print(adjusted)
+
+ transform_result = forwardDCT.transform(adjusted)
+ transform_result = vDSP.absolute(transform_result)
+ let max = vDSP.maximum(transform_result)
+ //print("max=\(max)")
+ //frequencyDomain.append(contentsOf: transform_result)
+ img.drawPalletLine(line: i, pixelLine: transform_result)
+ //print(transform_result)
+ } else {
+ img.drawPalletLine(line: i, pixelLine: transform_result)
+ }
+
+}
+
+img.drawPixel(0, 0, PixelData(a: 255, r: 255, g: 0, b: 0))
+img.drawPixel(sampleCount-1, 0, PixelData(a: 255, r: 0, g: 255, b: 0))
+img.drawPixel(0, sampleCount-1, PixelData(a: 255, r: 0, g: 255, b: 0))
+img.drawPixel(sampleCount-1, sampleCount-1, PixelData(a: 255, r: 0, g: 0, b: 255))
+
+
+//print(dataFloat)
+
+
+
+//output data to image file
+img.saveAsJPEG("fft_100m_512.jpeg")
+
+
+
+print("All computations are done")