Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion ShimmerBLE/ShimmerBLEAPI/Sensors/SensorGSR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,16 @@ public class SensorGSR : Sensor
protected SensorSetting GSROversamplingRateSetting = Sensor.UnknownSetting;
public const double LIMIT_FOR_MINIMUM_VALID_GSR_CONDUCTANCE_US = 0.03;
public const int GSR_UNCAL_LIMIT_RANGE3_SR62 = 683;
public const int GSR_UNCAL_LIMIT_RANGE3_SR68 = 1134;
/// <summary>
/// Range-3 codes below this are raised to it before calibration so that an open circuit
/// reads as open, which only works if the limit is above the amplifier reference. 1138 is
/// the first code above 0.5 V at the SR68's 1.8 V full scale (0.5 V = code 1137.5), so it
/// also clears the 0.4986 V that CalibrateGsrDataToKOhmsUsingAmplifierEq divides by (code
/// 1134.3); the Java driver divides by 0.5 V, and 1138 is correct under both. It was 1134,
/// the last code below 0.4986 V: that decoded to a negative resistance, nudged to 8 kOhm,
/// so an open circuit read 125 uS and counted as Connected (DEV-1067).
/// </summary>
public const int GSR_UNCAL_LIMIT_RANGE3_SR68 = 1138;

/// <summary>
/// GSR range setting
Expand Down
82 changes: 82 additions & 0 deletions ShimmerBLE/ShimmerBLETests/Sensors/SensorGSROpenCircuitTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using NUnit.Framework;
using shimmer.Sensors;
using ShimmerAPI;
using static ShimmerBLEAPI.Devices.VerisenseDevice;

namespace ShimmerBLETests
{
/// <summary>
/// An open circuit on GSR range 3 of a Verisense Pulse+ (SR68) has to decode as open (DEV-1067).
/// With nothing across the electrodes the amplifier output settles on its reference, so the ADC
/// reads a few codes either side of it: an SR68-9 open-circuit recording (DEV-793 dataset B6)
/// peaks at codes 1126-1136. The range-3 limit was 1134, itself below the 0.4986 V reference
/// (code 1134.3), so every clamped sample decoded to a negative resistance, which the auto-range
/// nudge floored at 8 kOhm: an open circuit read 125 uS and counted as Connected.
/// </summary>
public class SensorGSROpenCircuitTest
{
const int Range3 = 3;
/// <summary>Top of range 3, 4.7 MOhm - an open circuit should read at least this.</summary>
const double Range3MaxKOhms = 4700.0;

[Test]
public void TestOpenCircuitOnRange3ReadsOpenInAutoRange()
{
var sensor = CreateSR68Sensor(SensorGSR.GSRRange.Range_Auto);
for (int code = 1134; code <= 1138; code++)
{
AssertReadsOpen(sensor, code, "auto-range");
Assert.That(sensor.GetGSRConnectivityLevel(), Is.EqualTo(SensorGSR.GSRConnectivityLevel.Disconnected), "auto-range, code " + code);
}
}

/// <summary>
/// A fixed range pins the reading to that range's limits, so here an open circuit reads
/// 4.7 MOhm (0.213 uS, still above the 0.03 uS connectivity threshold) rather than the
/// 680 kOhm bottom of the range that 1134 produced.
/// </summary>
[Test]
public void TestOpenCircuitOnRange3ReadsOpenInFixedRange3()
{
var sensor = CreateSR68Sensor(SensorGSR.GSRRange.Range_3);
for (int code = 1134; code <= 1138; code++)
{
AssertReadsOpen(sensor, code, "fixed range 3");
}
}

/// <summary>
/// The Java driver divides by 0.5 V where this API uses 0.4986 V, so the limit is the first
/// code above 0.5 V: correct under both references.
/// </summary>
[Test]
public void TestLimitIsTheFirstCodeAboveHalfAVolt()
{
int limit = SensorGSR.GSR_UNCAL_LIMIT_RANGE3_SR68;
Assert.That(CalibrateADCValueToVolts(limit, HardwareIdentifier.VERISENSE_PULSE_PLUS), Is.GreaterThan(0.5));
Assert.That(CalibrateADCValueToVolts(limit - 1, HardwareIdentifier.VERISENSE_PULSE_PLUS), Is.LessThan(0.5));
}

private static SensorGSR CreateSR68Sensor(Sensor.SensorSetting range)
{
var sensor = new SensorGSR();
sensor.SetDeviceHardwareIdentifier(HardwareIdentifier.VERISENSE_PULSE_PLUS);
sensor.SetGSREnabled(true);
sensor.SetGSRRange(range);
return sensor;
}

private static void AssertReadsOpen(SensorGSR sensor, int code, string rangeLabel)
{
// One GSR sample as the firmware sends it: range in bits 15-14 over the 12-bit code, LSB first.
int raw = (Range3 << 14) | code;
var ojc = sensor.ParseSensorData(new byte[] { (byte)(raw & 0xFF), (byte)(raw >> 8) }, new ObjectCluster("", ""));
double kOhms = ojc.GetData(SensorGSR.ObjectClusterSensorName.GSR, ShimmerConfiguration.SignalFormats.CAL, ShimmerConfiguration.SignalUnits.KiloOhms).Data;
double uS = ojc.GetData(SensorGSR.ObjectClusterSensorName.GSR, ShimmerConfiguration.SignalFormats.CAL, ShimmerConfiguration.SignalUnits.MicroSiemens).Data;

string context = rangeLabel + ", code " + code;
Assert.That(kOhms, Is.GreaterThanOrEqualTo(Range3MaxKOhms), context);
Assert.That(uS, Is.GreaterThan(0).And.LessThanOrEqualTo(1000.0 / Range3MaxKOhms), context);
}
}
}
Loading