AccelerateWatch: High performance digital signal processing and vector operations implemented in C, and wrapped in Swift, designed especially to be targeted at watchOS.
Working version: 1.0.1
Currently all codes are built and tested on
- Xcode 8.0 beta 3
- iOS 10.0 beta 3
- watchOS 3.0 beta 3
- Swift 3
Where and why to use AccelerateWatch?
Apple watchOS 3 opens opptunities to developers to access more motion sensor data both in real time and possible background tasks. Unfortunately meanwhile, the Accelerate framework, a powerful tool for high-performance computations, is still unavailable on watchOS. This library is extracted from my other projects, and help those watchOS⌚️ apps which need to process sensor data in real time, just like what Accelerate does for iOS platform.
- Swift APIs. C data structures and methods are wrapped in Swift, so that you can call them using Swift conveniently.
- Friendly syntax. This is a reason that you even want to use this instead of Accelerate framework on iOS, though other similar libraries like Surge exists.
Currently the functionality set is relatively smaller compared with Accelerate framework because only those I used in my projects are added (mostly focused on time series operations and analysis). So contributions are welcome! 😃
Manual install is recommended for now. Swift Package Manager will be supported when it is ready.
- Clone the latest version of this repo to your local machine.
- Copy AccelerateWatch folder to your project (usually the Watch Extension folder). Remove
acceleratelib/buildfolder which is for C code testing.
- Check that every .swift and .c files has Watch Extension as target if your want it to be used on watch target.
- Add a bridging header (here is a Instruction), and add the following line to it:
Full documentation HERE.
The library currently has two modules:
DSBufferis a class for windowed time series processing.
Vectoris a set of functons for vector manipulations.
Below is a summary of the APIs.
DSBuffer represents a fixed length signal queue (Float type) which is suitable for storing and processing a windowed time series.
// Create a DSBuffer object // *Tips*: // - If you do not need to perform FFT on the buffer, set fftIsSupperted to be false could save 50% memory. // - If you need to perform FFT, set buffer size to power of 2 could accelerate more. init(size: Int, fftIsSupported: Bool = true) // Push new data to the end of the buffer (and the foremost will be dropped) func push(value: Float) // Get data by index func dataAt(index: Int) // Get buffer size var bufferSize: Int // Dump buffer as array var data: [Float] // Reset all buffer values to zero func clear()
func add(value: Float) -> [Float] func multiply(value: Float) -> [Float] var centralized: [Float] func normalizedToUnitLength(centralized: Bool) -> [Float] func normalizedToUnitVariance(centralized: Bool) -> [Float] func dotProduct(with: [Float]) -> Float
var mean: Float var sum: Float var length: Float var energy: Float var max: Float var min: Float var variance: Float var std: Float
Fast Fourier Transform and frequency-domain features
Note for FFT related methods:
fftIsSupportedto true when creating the buffer.
sizeshould be even. If you pass odd size when creating the buffer, it is automatically increased by 1.
- Only results in size/2+1 complex frequency bins from DC to Nyquist are returned.
// Perform FFT on buffer func fft() -> (real: [Float], imaginary: [Float]) // Get FFT sample frequencies func fftFrequencies(fs: Float) -> [Float] // Get FFT magnitudes func fftMagnitudes() -> [Float] // Square of FFT Magnitude, i.e. (abs(fft()))^2 func squaredPowerSpectrum() -> [Float] // Mean-squared power spectrum, i.e. (abs(fft()))^2 / N func meanSquaredPowerSpectrum() -> [Float] // Power spectral density (PSD), i.e. (abs(fft()))^2 / (fs*N) func powerSpectralDensity(fs: Float) -> [Float] // Average power over specified frequency band, i.e. mean(abs(fft(from...to))^2) func averageBandPower(fromFreq: Float = 0, toFreq: Float, fs: Float) -> Float
// Setup a FIR filter func setupFIRFilter(FIRTaps: [Float]) // Get latest FIR filter output func latestFIROutput() -> Float // Get FIR filtered signal series in buffer func FIRFiltered() -> [Float]
Vector module includes operations on regular arrays. All functions have two versions, for float and double type respectively.
AccelerateWatchDemoApp is a demo app showing how to integrate AccelerateWatch for watch target. For details, please see
DSBuffer.test() in DSBuffer.swift and
vTest() in Vector.swift.
- Setting any LLVM (v8) optimization level rather than
None [-O0]would probably cause unexpected behavior of DSBuffer.
How to contribute
kissfft is employed for FFT implementation. It is a lightweight and fast FFT library. Only the real-value FFT related part is included here.
For documentation generation.