Skip to content

Commit

Permalink
Support remaining strain gauge configurations (#268)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamreeve committed Mar 10, 2022
1 parent 9ad82c8 commit 6d14c91
Show file tree
Hide file tree
Showing 2 changed files with 264 additions and 39 deletions.
84 changes: 79 additions & 5 deletions nptdms/scaling.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# coding: utf-8

import numpy as np
import numpy.polynomial.polynomial as poly
import re
Expand Down Expand Up @@ -197,12 +199,84 @@ def from_properties(properties, scale_index):
def scale(self, data):
""" Convert voltage data to strain
"""
# For a Wheatstone bridge, Vo = [R3 / (R3 + R4) - R2 / (R1 + R2)] Vex
# The input data for this scaling is the output voltage (Vo) and we
# want to compute the strain (ε)
voltage_out = data.astype(np.double)
if self.initial_bridge_voltage != 0.0:
voltage_out -= self.initial_bridge_voltage
if self.configuration == StrainScaling.FULL_BRIDGE_1:
if self.initial_bridge_voltage != 0.0:
voltage_diff = data - self.initial_bridge_voltage
else:
voltage_diff = data
return voltage_diff * (-self.gain_adjustment / (self.voltage_excitation * self.gage_factor))
# In the full bridge type I configuration:
# R1 = R3 = R0 (1 - ε G)
# R2 = R4 = R0 (1 + ε G)
# where G is the gauge factor and R0 is the base gague resistance.
# This gives Vo = -ε G Vex
strain = voltage_out
strain *= (-self.gain_adjustment / (self.voltage_excitation * self.gage_factor))
return strain
elif self.configuration == StrainScaling.FULL_BRIDGE_2:
# In the full bridge type II configuration:
# R1 = R0 (1 - ε ν G)
# R2 = R0 (1 + ε ν G)
# R3 = R0 (1 - ε G)
# R4 = R0 (1 + ε G)
# This gives Vo = - (1/2) ε G Vex (1 + ν)
strain = voltage_out
strain *= (-self.gain_adjustment * 2.0 / (
self.voltage_excitation * self.gage_factor * (1.0 + self.poisson_ratio)))
return strain
elif self.configuration == StrainScaling.FULL_BRIDGE_3:
# In the full bridge type III configuration:
# R1 = R3 = R0 (1 - ε ν G)
# R2 = R4 = R0 (1 + ε G)
# This gives Vo = - ε G (1 + ν) Vex / (2 + ε G (1 - ν))
# Rearranging for strain:
# ε = - 2 Vo / (G Vex (1 + ν + (Vo/Vex) (1 - ν)))
common_factor = -0.5 / self.gain_adjustment
temp = voltage_out.copy()
temp *= common_factor * (1.0 - self.poisson_ratio) * self.gage_factor
temp += common_factor * self.voltage_excitation * self.gage_factor * (1.0 + self.poisson_ratio)
strain = voltage_out
strain /= temp
return strain
elif self.configuration == StrainScaling.HALF_BRIDGE_1:
# In the half bridge type I configuration:
# R1 = R2 = R0
# R3 = R0 (1 + ε ν G)
# R4 = R0 (1 + ε G)
# Which gives Vo = [(1 - ε ν G) / (2 + ε G - ε ν G) - 1/2] Vex
# Rearranging for strain:
# ε = -4 (Vo / Vex) / [G (1 + ν + 2 (Vo / Vex) (1 - ν))]
lead_adjustment = 1.0 / (1.0 + self.lead_wire_resistance / self.gage_resistance)
common_factor = -self.gage_factor * self.voltage_excitation * lead_adjustment / (
4.0 * self.gain_adjustment)
temp = voltage_out.copy()
temp *= common_factor * 2.0 * (1.0 - self.poisson_ratio) / self.voltage_excitation
temp += common_factor * (1.0 + self.poisson_ratio)
strain = voltage_out
strain /= temp
return strain
elif self.configuration == StrainScaling.HALF_BRIDGE_2:
lead_adjustment = 1.0 / (1.0 + self.lead_wire_resistance / self.gage_resistance)
strain = voltage_out
strain *= -2.0 * self.gain_adjustment / (
self.gage_factor * self.voltage_excitation * lead_adjustment)
return strain
elif self.configuration in (StrainScaling.QUARTER_BRIDGE_1, StrainScaling.QUARTER_BRIDGE_2):
# In the quarter bridge configuration:
# R1 = R2 = R3 = R0
# R4 = R0 (1 + ε G)
# Which gives Vo = [1 / (2 + ε G) - (1 / 2)] Vex
# Rearranging for strain:
# ε = -2 / G [1 - 1 / (1 + 2 Vo / Vex)]
lead_adjustment = 1.0 / (1.0 + self.lead_wire_resistance / self.gage_resistance)
strain = voltage_out
strain *= 2.0 / self.voltage_excitation
strain += 1.0
np.reciprocal(strain, out=strain)
strain -= 1.0
strain *= 2.0 * self.gain_adjustment / (self.gage_factor * lead_adjustment)
return strain

raise Exception("Strain gauge configuration %d is not supported" % self.configuration)

Expand Down
219 changes: 185 additions & 34 deletions nptdms/test/test_scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,46 +437,197 @@ def test_thermistor_scaling_with_invalid_excitation_type():
assert "Invalid excitation type: 12345" in str(exc_info.value)


def test_strain_scaling_full_bridge_type_i():
_strain_scaling_test(
[0.00068827, 0.00068036, 0.000688, 0.00068545, 0.00069104,
0.00068033, 0.00068023, 0.00068316, 0.00067672, 0.000679],
[-0.0001311, -0.00012959, -0.00013105, -0.00013056, -0.00013163,
-0.00012959, -0.00012957, -0.00013013, -0.0001289, -0.00012933])


def test_strain_scaling_full_bridge_type_i_with_adjustment():
_strain_scaling_test(
[0.00068827, 0.00068036, 0.000688, 0.00068545, 0.00069104,
0.00068033, 0.00068023, 0.00068316, 0.00067672, 0.000679],
[-0.00014722, -0.00014553, -0.00014717, -0.00014662, -0.00014782,
-0.00014553, -0.0001455, -0.00014613, -0.00014475, -0.00014524],
calibration_adjustment=1.123)


def test_strain_scaling_full_bridge_type_i_with_initial_voltage():
_strain_scaling_test(
[0.00068827, 0.00068036, 0.000688, 0.00068545, 0.00069104,
0.00068033, 0.00068023, 0.00068316, 0.00067672, 0.000679],
[0.00012604, 0.00012755, 0.0001261, 0.00012658, 0.00012552,
0.00012756, 0.00012758, 0.00012702, 0.00012824, 0.00012781],
initial_bridge_voltage=0.00135)


def _strain_scaling_test(input_data, expected_data, initial_bridge_voltage=0.0, calibration_adjustment=1.0):
data = StubTdmsData(np.array(input_data))
expected_data = np.array(expected_data)
_strain_voltage = [
0.0068827, 0.0068036, 0.00688, 0.0068545, 0.0069104,
0.0068033, 0.0068023, 0.0068316, 0.0067672, 0.00679]

_measured_strain = {
10183: {
'baseline': [
-1.310990e-03, -1.295924e-03, -1.310476e-03, -1.305619e-03, -1.316267e-03,
-1.295867e-03, -1.295676e-03, -1.301257e-03, -1.288990e-03, -1.293333e-03,
],
'with_adjustment': [
-1.472242e-03, -1.455322e-03, -1.471665e-03, -1.466210e-03, -1.478167e-03,
-1.455258e-03, -1.455044e-03, -1.461312e-03, -1.447536e-03, -1.452413e-03,
],
'with_initial_voltage': [
-1.053848e-03, -1.038781e-03, -1.053333e-03, -1.048476e-03, -1.059124e-03,
-1.038724e-03, -1.038533e-03, -1.044114e-03, -1.031848e-03, -1.036190e-03,
],
'with_lead_resistance': [
-1.310990e-03, -1.295924e-03, -1.310476e-03, -1.305619e-03, -1.316267e-03,
-1.295867e-03, -1.295676e-03, -1.301257e-03, -1.288990e-03, -1.293333e-03,
],
'with_all': [
-1.183471e-03, -1.166551e-03, -1.182893e-03, -1.177439e-03, -1.189396e-03,
-1.166487e-03, -1.166273e-03, -1.172540e-03, -1.158765e-03, -1.163642e-03,
],
},
10184: {
'baseline': [
-2.016908e-03, -1.993729e-03, -2.016117e-03, -2.008645e-03, -2.025026e-03,
-1.993641e-03, -1.993348e-03, -2.001934e-03, -1.983062e-03, -1.989744e-03,
],
'with_adjustment': [
-2.264988e-03, -2.238958e-03, -2.264100e-03, -2.255708e-03, -2.274104e-03,
-2.238859e-03, -2.238530e-03, -2.248172e-03, -2.226979e-03, -2.234482e-03,
],
'with_initial_voltage': [
-1.621304e-03, -1.598125e-03, -1.620513e-03, -1.613040e-03, -1.629421e-03,
-1.598037e-03, -1.597744e-03, -1.606330e-03, -1.587458e-03, -1.594139e-03,
],
'with_lead_resistance': [
-2.016908e-03, -1.993729e-03, -2.016117e-03, -2.008645e-03, -2.025026e-03,
-1.993641e-03, -1.993348e-03, -2.001934e-03, -1.983062e-03, -1.989744e-03,
],
'with_all': [
-1.820724e-03, -1.794694e-03, -1.819836e-03, -1.811444e-03, -1.829840e-03,
-1.794595e-03, -1.794266e-03, -1.803908e-03, -1.782715e-03, -1.790218e-03,
],
},
10185: {
'baseline': [
-2.013923e-03, -1.990812e-03, -2.013134e-03, -2.005684e-03, -2.022016e-03,
-1.990724e-03, -1.990432e-03, -1.998993e-03, -1.980176e-03, -1.986838e-03,
],
'with_adjustment': [
-2.261635e-03, -2.235681e-03, -2.260750e-03, -2.252383e-03, -2.270724e-03,
-2.235583e-03, -2.235255e-03, -2.244869e-03, -2.223738e-03, -2.231219e-03,
],
'with_initial_voltage': [
-1.619374e-03, -1.596250e-03, -1.618585e-03, -1.611130e-03, -1.627472e-03,
-1.596162e-03, -1.595869e-03, -1.604435e-03, -1.585608e-03, -1.592274e-03,
],
'with_lead_resistance': [
-2.013923e-03, -1.990812e-03, -2.013134e-03, -2.005684e-03, -2.022016e-03,
-1.990724e-03, -1.990432e-03, -1.998993e-03, -1.980176e-03, -1.986838e-03,
],
'with_all': [
-1.818557e-03, -1.792588e-03, -1.817671e-03, -1.809299e-03, -1.827651e-03,
-1.792490e-03, -1.792161e-03, -1.801781e-03, -1.780638e-03, -1.788123e-03,
],
},
10188: {
'baseline': [
-4.021893e-03, -3.975806e-03, -4.020319e-03, -4.005462e-03, -4.038031e-03,
-3.975631e-03, -3.975048e-03, -3.992120e-03, -3.954596e-03, -3.967881e-03,
],
'with_adjustment': [
-4.516585e-03, -4.464830e-03, -4.514819e-03, -4.498134e-03, -4.534709e-03,
-4.464633e-03, -4.463979e-03, -4.483151e-03, -4.441012e-03, -4.455931e-03,
],
'with_initial_voltage': [
-3.234898e-03, -3.188758e-03, -3.233323e-03, -3.218449e-03, -3.251055e-03,
-3.188583e-03, -3.188000e-03, -3.205091e-03, -3.167524e-03, -3.180824e-03,
],
'with_lead_resistance': [
-4.036073e-03, -3.989823e-03, -4.034494e-03, -4.019585e-03, -4.052268e-03,
-3.989648e-03, -3.989063e-03, -4.006195e-03, -3.968539e-03, -3.981871e-03,
],
'with_all': [
-3.645599e-03, -3.593601e-03, -3.643824e-03, -3.627061e-03, -3.663807e-03,
-3.593403e-03, -3.592746e-03, -3.612008e-03, -3.569671e-03, -3.584660e-03,
],
},
10189: {
'baseline': [
-2.621981e-03, -2.591848e-03, -2.620952e-03, -2.611238e-03, -2.632533e-03,
-2.591733e-03, -2.591352e-03, -2.602514e-03, -2.577981e-03, -2.586667e-03,
],
'with_adjustment': [
-2.944485e-03, -2.910645e-03, -2.943330e-03, -2.932420e-03, -2.956335e-03,
-2.910517e-03, -2.910089e-03, -2.922624e-03, -2.895073e-03, -2.904827e-03,
],
'with_initial_voltage': [
-2.107695e-03, -2.077562e-03, -2.106667e-03, -2.096952e-03, -2.118248e-03,
-2.077448e-03, -2.077067e-03, -2.088229e-03, -2.063695e-03, -2.072381e-03,
],
'with_lead_resistance': [
-2.631225e-03, -2.600986e-03, -2.630193e-03, -2.620445e-03, -2.641815e-03,
-2.600871e-03, -2.600489e-03, -2.611690e-03, -2.587070e-03, -2.595787e-03,
],
'with_all': [
-2.375287e-03, -2.341328e-03, -2.374128e-03, -2.363180e-03, -2.387179e-03,
-2.341199e-03, -2.340770e-03, -2.353349e-03, -2.325701e-03, -2.335489e-03,
],
},
10271: {
'baseline': [
-5.215246e-03, -5.155634e-03, -5.213211e-03, -5.193994e-03, -5.236120e-03,
-5.155408e-03, -5.154654e-03, -5.176736e-03, -5.128199e-03, -5.145384e-03,
],
'with_adjustment': [
-5.856721e-03, -5.789777e-03, -5.854436e-03, -5.832856e-03, -5.880162e-03,
-5.789523e-03, -5.788676e-03, -5.813475e-03, -5.758968e-03, -5.778266e-03,
],
'with_initial_voltage': [
-4.196815e-03, -4.137074e-03, -4.194776e-03, -4.175517e-03, -4.217733e-03,
-4.136848e-03, -4.136092e-03, -4.158222e-03, -4.109581e-03, -4.126802e-03,
],
'with_lead_resistance': [
-5.233633e-03, -5.173811e-03, -5.231592e-03, -5.212307e-03, -5.254581e-03,
-5.173584e-03, -5.172828e-03, -5.194988e-03, -5.146280e-03, -5.163525e-03,
],
'with_all': [
-4.729640e-03, -4.662315e-03, -4.727342e-03, -4.705639e-03, -4.753214e-03,
-4.662059e-03, -4.661208e-03, -4.686147e-03, -4.631330e-03, -4.650738e-03,
],
},
10272: {
'baseline': [
-5.215246e-03, -5.155634e-03, -5.213211e-03, -5.193994e-03, -5.236120e-03,
-5.155408e-03, -5.154654e-03, -5.176736e-03, -5.128199e-03, -5.145384e-03,
],
'with_adjustment': [
-5.856721e-03, -5.789777e-03, -5.854436e-03, -5.832856e-03, -5.880162e-03,
-5.789523e-03, -5.788676e-03, -5.813475e-03, -5.758968e-03, -5.778266e-03,
],
'with_initial_voltage': [
-4.196815e-03, -4.137074e-03, -4.194776e-03, -4.175517e-03, -4.217733e-03,
-4.136848e-03, -4.136092e-03, -4.158222e-03, -4.109581e-03, -4.126802e-03,
],
'with_lead_resistance': [
-5.233633e-03, -5.173811e-03, -5.231592e-03, -5.212307e-03, -5.254581e-03,
-5.173584e-03, -5.172828e-03, -5.194988e-03, -5.146280e-03, -5.163525e-03,
],
'with_all': [
-4.729640e-03, -4.662315e-03, -4.727342e-03, -4.705639e-03, -4.753214e-03,
-4.662059e-03, -4.661208e-03, -4.686147e-03, -4.631330e-03, -4.650738e-03,
],
},
}


@pytest.mark.parametrize("configuration", [
10183, 10184, 10185, 10188, 10189, 10271, 10272])
@pytest.mark.parametrize("key", [
"baseline", "with_adjustment", "with_initial_voltage", "with_lead_resistance", "with_all"])
def test_strain_scaling(configuration, key):
data = StubTdmsData(np.array(_strain_voltage))
expected_data = np.array(_measured_strain[configuration][key])

lead_wire_resistance = 0.0
initial_bridge_voltage = 0.0
gain_adjustment = 1.0

if key in ("with_adjustment", "with_all"):
gain_adjustment = 1.123
if key in ("with_initial_voltage", "with_all"):
initial_bridge_voltage = 0.00135
if key in ("with_lead_resistance", "with_all"):
lead_wire_resistance = 1.234

properties = {
"NI_Number_Of_Scales": 1,
"NI_Scale[0]_Scale_Type": "Strain",
"NI_Scale[0]_Strain_Configuration": 10183,
"NI_Scale[0]_Strain_Configuration": configuration,
"NI_Scale[0]_Strain_Poisson_Ratio": 0.3,
"NI_Scale[0]_Strain_Gage_Resistance": 350.0,
"NI_Scale[0]_Strain_Lead_Wire_Resistance": 0.0,
"NI_Scale[0]_Strain_Lead_Wire_Resistance": lead_wire_resistance,
"NI_Scale[0]_Strain_Initial_Bridge_Voltage": initial_bridge_voltage,
"NI_Scale[0]_Strain_Gage_Factor": 2.1,
"NI_Scale[0]_Strain_Bridge_Shunt_Calibration_Gain_Adjustment": calibration_adjustment,
"NI_Scale[0]_Strain_Bridge_Shunt_Calibration_Gain_Adjustment": gain_adjustment,
"NI_Scale[0]_Strain_Voltage_Excitation": 2.5,
"NI_Scale[0]_Strain_Input_Source": 0xFFFFFFFF,
}
Expand All @@ -493,7 +644,7 @@ def test_unsupported_strain_configuration():
properties = {
"NI_Number_Of_Scales": 1,
"NI_Scale[0]_Scale_Type": "Strain",
"NI_Scale[0]_Strain_Configuration": 10184,
"NI_Scale[0]_Strain_Configuration": 12345,
"NI_Scale[0]_Strain_Poisson_Ratio": 0.3,
"NI_Scale[0]_Strain_Gage_Resistance": 350.0,
"NI_Scale[0]_Strain_Lead_Wire_Resistance": 0.0,
Expand All @@ -508,7 +659,7 @@ def test_unsupported_strain_configuration():

with pytest.raises(Exception) as exc_info:
_ = scaling.scale(data)
assert str(exc_info.value) == "Strain gauge configuration 10184 is not supported"
assert str(exc_info.value) == "Strain gauge configuration 12345 is not supported"


def test_multiple_scalings_applied_in_order():
Expand Down

0 comments on commit 6d14c91

Please sign in to comment.