Bluetooth in SWIFT: Get 19 bytes data and convert to UInt - swift

I would like to connect the Concept2 rower to my iPhone.
The corresponding Bluetooth data sheet can be found here : http://www.concept2.com/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf
I would like to get back the different data: ElapsedTime, Distance, Split/interval, etc..
From the UUID adress 0X0031 I get a 19 bytes data in the following order:Elapsed Time Lo (0.01 sec lsb), Elapsed Time Mid, Elapsed Time High, Distance Lo (0.1 m lsb), Distance Mid, Distance Hi, ...
So 1 byte corresponds to 1 attribute.
I need to extract the bytes corresponding to the attribute and convert them.
I think all bytes data are unsigned types (for extraction).
The ElapsedTime variable is on 3 bytes. SO to build the ElapsedTime variable I was computing like this:
class func dataToUnsignedBytes8(value:NSData) -> [UInt8]{
let count = value.length
var array = [UInt8](count: count, repeatedValue: 0)
value.getBytes(&array, length: count * sizeof(UInt8))
return array
}
class func getElapsedTime(value : NSData) -> Double {
let dataFromSensor = dataToSignedBytes8(value)
let elapsedTime = Double(dataFromSensor[2] * 65536 + dataFromSensor[1]*256 + dataFromSensor[0])
return elapsedTime
}
But I'm not sure about what I'm doing.
Does the ElapsedTime_Hi byte is at index 3 of dataFromSensor, ElapsedTime_Mid is at index 2 of dataFromSensor and ElapsedTime_Lo at index 0 dataFromSensor ?
What is the best way to extract the corresponding byte for other attributes ?
Thank you in advance
Regards

Related

Swift unreliable round() method to 2 decimal places

I'm trying to calculate the time between two doubles (distance, speed) to 2 decimal places using swift round() method but there are instances where its unreliable and I end up with something like 58.000000001. I tried to hack fix this by rounding again but even that doesn't work on larger numbers eg 734.00000001 Is there a way to fix this or another way to calculate time between two doubles?
var totalTime: Double = 0
for 0...100 {
let calcTime = 35.3 / 70
let roundedTime = round(calcTime * 100) / 100.0
print("TIME === \(roundedTime)")
totalTime += round(totalTime * 100) / 100 + roundedTime // round again to clamp the extra zero's
print("Total time \(totalTime)")
}

Perform normalization using Accelerate framework

I need to perform simple math operation on Data that contains RGB pixels data. Currently Im doing this like so:
let imageMean: Float = 127.5
let imageStd: Float = 127.5
let rgbData: Data // Some data containing RGB pixels
let floats = (0..<rgbData.count).map {
(Float(rgbData[$0]) - imageMean) / imageStd
}
return Data(bytes: floats, count: floats.count * MemoryLayout<Float>.size)
This works, but it's too slow. I was hoping I could use the Accelerate framework to calculate this faster, but have no idea how to do this. I reserved some space so that it's not allocated every time this function starts, like so:
inputBufferDataNormalized = malloc(width * height * 3) // 3 channels RGB
I tried few functions, like vDSP_vasm, but I couldn't make it work. Can someone direct me to how to use it? Basically I need to replace this map function, because it takes too long time. And probably it would be great to use pre-allocated space all the time.
Following up on my comment on your other related question. You can use SIMD to parallelize the operation, but you'd need to split the original array into chunks.
This is a simplified example that assumes that the array is exactly divisible by 64, for example, an array of 1024 elements:
let arr: [Float] = (0 ..< 1024).map { _ in Float.random(in: 0...1) }
let imageMean: Float = 127.5
let imageStd: Float = 127.5
var chunks = [SIMD64<Float>]()
chunks.reserveCapacity(arr.count / 64)
for i in stride(from: 0, to: arr.count, by: 64) {
let v = SIMD64.init(arr[i ..< i+64])
chunks.append((v - imageMean) / imageStd) // same calculation using SIMD
}
You can now access each chunk with a subscript:
var results: [Float] = []
results.reserveCapacity(arr.count)
for chunk in chunks {
for i in chunk.indices {
results.append(chunk[i])
}
}
Of course, you'd need to deal with a remainder if the array isn't exactly divisible by 64.
I have found a way to do this using Accelerate. First I reserve space for converted buffer like so
var inputBufferDataRawFloat = [Float](repeating: 0, count: width * height * 3)
Then I can use it like so:
let rawBytes = [UInt8](rgbData)
vDSP_vfltu8(rawBytes, 1, &inputBufferDataRawFloat, 1, vDSP_Length(rawBytes.count))
vDSP.add(inputBufferDataRawScalars.mean, inputBufferDataRawFloat, result: &inputBufferDataRawFloat)
vDSP.multiply(inputBufferDataRawScalars.std, inputBufferDataRawFloat, result: &inputBufferDataRawFloat)
return Data(bytes: inputBufferDataRawFloat, count: inputBufferDataRawFloat.count * MemoryLayout<Float>.size)
Works very fast. Maybe there is better function in Accelerate, if anyone know of it, please let me know. It need to perform function (A[n] + B) * C (or to be exact (A[n] - B) / C but the first one could be converted to this).

How to get the binary inverse of a number in Swift?

If we have a given number, say 9 (binary representation is 1001). How can we most efficiently get it's inverse 6 (binary representation is 0110)? i.e replacing 0 with 1 and 1 with 0.
I have written a code of order O(1) complexity? But can there be a better way? Does Swift provide an elegant way of handling this?
Note negate function ~9 results in -10. This is not what I am seeking.
func inverse(of givenNumber: Int) -> Int // eg. 9
{
let binaryRepresentation = String(givenNumber, radix: 2) // "1001"
let binaryRepresentationLength = binaryRepresentation.count // 4
let maxValueInLength = (1 << binaryRepresentationLength) - 1 // 15, i.e., 1111
let answer = givenNumber ^ maxValueInLength // 6, i.e., 0110
return answer
}
Edit 1: givenNumber > 0
For positive numbers you can use the following:
func intInverse<T: FixedWidthInteger>(of givenNumber: T) -> T
{
assert(!T.isSigned || givenNumber & (T(1) << (givenNumber.bitWidth - 1)) == 0)
let binaryRepresentationLength = givenNumber.bitWidth - givenNumber.leadingZeroBitCount
let maxValueInLength = givenNumber.leadingZeroBitCount > 0 ? (~(~T(0) << binaryRepresentationLength)) : ~0
let answer = givenNumber ^ maxValueInLength
return answer
}
Which is identical to your algorithm but doesn't require stringifying the number. It doesn't work for negative numbers, but then neither does your algorithm because your algorithm sticks a - on the front of the number.
Probably the easiest way to extend this to cover negative numbers is to invert all the bits to get the binaryRepresentationLength
EDIT
I changed the way the exclusive or mask is created because the old one crashed for unsigned values with the top bit set and for signed values with the second highest bit set.
The code becomes much simpler using the property binade of a floating-point value.
func inverse(of givenNumber: Int) -> Int // eg. 9
{
let maxValueInLength = Int((Double(givenNumber).binade * 2) - 1) // 15, i.e., 1111
let answer = givenNumber ^ maxValueInLength // 6, i.e., 0110
return answer
}

Relative Strength Index in Swift

I am trying to code an RSI (which has been a good way for me to learn API data fetching and algorithms already).
The API I am fetching data from comes from a reputable exchange so I know the values my algorithm is analyzing are correct, that's a good start.
The issue I'm having is that the result of my calculations are completely off from what I can read on that particular exchange and which also provides an RSI indicator (I assume they analyze their own data, so the same data as I have).
I used the exact same API to translate the Ichimoku indicator into code and this time everything is correct! I believe my RSI calculations might be wrong somehow but I've checked and re-checked many times.
I also have a "literal" version of the code where every step is calculated like an excel sheet. It's pretty stupid in code but it validates the logic of the calculation and the results are the same as the following code.
Here is my code to calculate the RSI :
let period = 14
// Upward Movements and Downward Movements
var upwardMovements : [Double] = []
var downwardMovements : [Double] = []
for idx in 0..<15 {
let diff = items[idx + 1].close - items[idx].close
upwardMovements.append(max(diff, 0))
downwardMovements.append(max(-diff, 0))
}
// Average Upward Movements and Average Downward Movements
let averageUpwardMovement1 = upwardMovements[0..<period].reduce(0, +) / Double(period)
let averageDownwardMovement1 = downwardMovements[0..<period].reduce(0, +) / Double(period)
let averageUpwardMovement2 = (averageUpwardMovement1 * Double(period - 1) + upwardMovements[period]) / Double(period)
let averageDownwardMovement2 = (averageDownwardMovement1 * Double(period - 1) + downwardMovements[period]) / Double(period)
// Relative Strength
let relativeStrength1 = averageUpwardMovement1 / averageDownwardMovement1
let relativeStrength2 = averageUpwardMovement2 / averageDownwardMovement2
// Relative Strength Index
let rSI1 = 100 - (100 / (relativeStrength1 + 1))
let rSI2 = 100 - (100 / (relativeStrength2 + 1))
// Relative Strength Index Average
let relativeStrengthAverage = (rSI1 + rSI2) / 2
BitcoinRelativeStrengthIndex.bitcoinRSI = relativeStrengthAverage
Readings at 3:23pm this afternoon give 73.93 for my algorithm and 18.74 on the exchange. As the markets are crashing right now and I have access to different RSIs on different exchanges, they all display an RSI below 20 so my calculations are off.
Do you guys have any idea?
I am answering this 2 years later, but hopefully it helps someone.
RSI gets more precise the more data points you feed into it. For a default RSI period of 14, you should have at least 200 previous data points. The more, the better!
Let's suppose you have an array of close candle prices for a given market. The following function will return RSI values for each candle. You should always ignore the first data points, since they are not precise enough or the number of candles is not the 14 (or whatever your periods number is).
func computeRSI(on prices: [Double], periods: Int = 14, minimumPoints: Int = 200) -> [Double] {
precondition(periods > 1 && minimumPoints > periods && prices.count >= minimumPoints)
return Array(unsafeUninitializedCapacity: prices.count) { (buffer, count) in
buffer.initialize(repeating: 50)
var (previousPrice, gain, loss) = (prices[0], 0.0, 0.0)
for p in stride(from: 1, through: periods, by: 1) {
let price = prices[p]
let value = price - previousPrice
if value > 0 {
gain += value
} else {
loss -= value
}
previousPrice = price
}
let (numPeriods, numPeriodsMinusOne) = (Double(periods), Double(periods &- 1))
var avg = (gain: gain / numPeriods, loss: loss /numPeriods)
buffer[periods] = (avg.loss > .zero) ? 100 - 100 / (1 + avg.gain/avg.loss) : 100
for p in stride(from: periods &+ 1, to: prices.count, by: 1) {
let price = prices[p]
avg.gain *= numPeriodsMinusOne
avg.loss *= numPeriodsMinusOne
let value = price - previousPrice
if value > 0 {
avg.gain += value
} else {
avg.loss -= value
}
avg.gain /= numPeriods
avg.loss /= numPeriods
if avgLoss > .zero {
buffer[p] = 100 - 100 / (1 + avg.gain/avg.loss)
} else {
buffer[p] = 100
}
previousPrice = price
}
count = prices.count
}
}
Please note that the code is very imperative to reduce the amount of operations/loops and get the maximum compiler optimizations. You might be able to squeeze more performance using the Accelerate framework, though. We are also handling the edge case where you might get all gains or losses in a periods range.
If you want to have a running RSI calculation. Just store the last RSI value and perform the RSI equation for the new price.

Really fast addition of Strings in swift

The code below shows two ways of building a spreadsheet :
by using:
str = str + "\(number) ; "
or
str.append("\(number)");
Both are really slow because, I think, they discard both strings and make a third one which is the concatenation of the first two.
Now, If I repeat this operation hundreds of thousands of times to grow a spreadsheet... that makes a lot of allocations.
For instance, the code below takes 11 seconds to execute on my MacBook Pro 2016:
let start = Date()
var str = "";
for i in 0 ..< 86400
{
for j in 0 ..< 80
{
// Use either one, no difference
// str = str + "\(Double(j) * 1.23456789086756 + Double(i)) ; "
str.append("\(Double(j) * 1.23456789086756 + Double(i)) ; ");
}
str.append("\n")
}
let duration = Date().timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate;
print(duration);
How can I solve this issue without having to convert the doubles to string myself ? I have been stuck on this for 3 days... my programming skills are pretty limited, as you can probably see from the code above...
I tried:
var str = NSMutableString(capacity: 86400*80*20);
but the compiler tells me:
Variable 'str' was never mutated; consider changing to 'let' constant
despite the
str.append("\(Double(j) * 1.23456789086756 + Double(i)) ; ");
So apparently, calling append does not mutate the string...
I tried writing it to an array and the limiting factor seems to be the conversion of a double to a string.
The code below takes 13 seconds or so on my air
doing this
arr[i][j] = "1.23456789086756"
drops the execution time to 2 seconds so 11 seconds is taken up in converting Double to String. You might be able to shave off some time by writing your own conversion routine but that seems the limiting factor. I tried using memory streams and that seems even slower.
var start = Date()
var arr = Array(repeating: Array(repeating: "1.23456789086756", count: 80), count: 86400 )
var duration = Date().timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate;
print(duration); //0.007
start = Date()
var a = 1.23456789086756
for i in 0 ..< 86400
{
for j in 0 ..< 80
{
arr[i][j] = "\(a)" // "1.23456789086756" //String(a)
}
}
duration = Date().timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate;
print(duration); //13.46 or 2.3 with the string