public static double[] DecodePPGSamples(string bits) { // Each packet contains a 16 bit timestamp, followed by 6, 24-bit samples. double[] samples = new double[Constants.MUSE_PPG_SAMPLE_COUNT]; for (int i = 0; i < Constants.MUSE_PPG_SAMPLE_COUNT; i++) { samples[i] = PacketConversion.ToUInt24(bits, 16 + (i * 24)); // Initial offset by 16 bits for the timestamp. } return(samples); }
public static double[] DecodeEEGSamples(string bits) { // Each packet contains a 16 bit timestamp, followed by 12, 12-bit samples. double[] samples = new double[12]; for (int i = 0; i < 12; i++) { samples[i] = PacketConversion.ToUInt12(bits, 16 + (i * 12)); // Initial offset by 16 bits for the timestamp. samples[i] = (samples[i] - 2048d) * 0.48828125d; // 12 bits on a 2 mVpp range. } return(samples); }
private double[] GetTimeSamples(string bits) { // Extract our 12, 12-bit samples. double[] timeSamples = new double[Constants.MUSE_SAMPLE_COUNT]; for (int i = 0; i < Constants.MUSE_SAMPLE_COUNT; i++) { timeSamples[i] = PacketConversion.ToFakeUInt12(bits, 16 + (i * 12)); // Initial offset by 16 bits for the timestamp. timeSamples[i] = (timeSamples[i] - 2048d) * 0.48828125d; // 12 bits on a 2 mVpp range. } return(timeSamples); }
public static double[,] DecodeGyroscopeSamples(string bits) { // Each packet contains a 16 bit timestamp, followed by 9, 16 bit values representing 3 "xyz" samples. double[,] samples = new double[Constants.MUSE_GYROSCOPE_SAMPLE_COUNT, Constants.MUSE_GYROSCOPE_CHANNEL_COUNT]; for (int i = 0; i < Constants.MUSE_GYROSCOPE_SAMPLE_COUNT; i++) { for (int j = 0; j < Constants.MUSE_GYROSCOPE_CHANNEL_COUNT; j++) { samples[i, j] = PacketConversion.ToInt16(bits, 16 + (((i * Constants.MUSE_GYROSCOPE_CHANNEL_COUNT) + j) * 16)); // Initial offset by 16 bits for the timestamp. samples[i, j] *= Constants.MUSE_GYROSCOPE_SCALE_FACTOR; } } return(samples); }
public static double[] DecodeTelemetrySamples(string bits) { // Each packet contains a 16 bit timestamp, followed by 4, 16-bit values representing battery, "fuel_gauge?", adc voltage, and temperature. double[] samples = new double[Constants.MUSE_TELEMETRY_CHANNEL_COUNT]; for (int i = 0; i < Constants.MUSE_TELEMETRY_CHANNEL_COUNT; i++) { samples[i] = PacketConversion.ToUInt16(bits, 16 + (i * 16)); // Initial offset by 16 bits for the timestamp. } // The following conversion are from muse-lsl (inside muse.py). Not sure how accurate this info is. 2/13/2020. // Battery. samples[0] = samples[0] / 512; // Fuel guage... samples[1] = samples[1] * 2.2d; return(samples); }
private async void Channel_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args) { if (isStreaming) { string bits = GetBits(args.CharacteristicValue); ushort museTimestamp = PacketConversion.ToUInt16(bits, 0); // Zero bit offset, since first 16 bits represent Muse timestamp. MuseSample sample; lock (sampleBuffer) { if (!sampleBuffer.ContainsKey(museTimestamp)) { sample = new MuseSample(); sampleBuffer.Add(museTimestamp, sample); sample.BaseTimestamp = TimestampFormat.GetNow(); // This is the real timestamp, not the Muse timestamp which we use to group channel data. sample.BasetimeStamp2 = TimestampFormat.GetType() != TimestampFormat2.GetType() ? TimestampFormat2.GetNow() // This is the real timestamp (format 2), not the Muse timestamp which we use to group channel data. : sample.BasetimeStamp2 = sample.BaseTimestamp; // Ensures they are equal if using same timestamp format. } else { sample = sampleBuffer[museTimestamp]; } // Get time samples. sample.ChannelData[sender.Uuid] = GetTimeSamples(bits); } // If we have all 5 channels, we can push the 12 samples for each channel. if (sample.ChannelData.Count == channelCount) { await LSLPushChunk(sample); lock (sampleBuffer) sampleBuffer.Remove(museTimestamp); } } }