DeaD_EyE

scale_siemens

Dec 27th, 2020 (edited)
829
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.40 KB | None | 0 0
  1. import bisect
  2. import math
  3. import unittest
  4. import doctest
  5.  
  6.  
  7. def scale(value, low, high):
  8.     """
  9.    Scale the value from low .. high
  10.  
  11.    >>> scale(0, -10, 10)
  12.    -10
  13.  
  14.    >>> scale(1, -10, 10)
  15.    10
  16.    """
  17.     return value * (high - low) + low
  18.  
  19.  
  20. def normalize(value, low, high):
  21.     """
  22.    Normalize value to 0 .. 1
  23.  
  24.    >>> normalize(0, 0, 10)
  25.    0.0
  26.  
  27.    >>> normalize(10, 0, 10)
  28.    1.0
  29.  
  30.    >>> normalize(5, 0, 10)
  31.    0.5
  32.    """
  33.     return (value - low) / (high - low)
  34.  
  35.  
  36. def scale_siemens(value, min_scale, max_scale, bipolar=False):
  37.     """
  38.    Scale Analog Values with siemens components:
  39.    https://support.industry.siemens.com/cs/mdm/8859629?c=23218577931&t=1&s=27648&lc=en-DE
  40.    Look at Table: Representation of analog values in the ±10 V output range
  41.    """
  42.     if bipolar:
  43.         normalized = normalize(value, -27648, 27648)
  44.     else:
  45.         normalized = normalize(value, 0, 27648)
  46.     ranges = (-32513, -27649, 27648, 32511, 32767)
  47.     areas = [
  48.         "Underflow, at zero voltage and current",
  49.         "Undershoot range",
  50.         "Rated range",
  51.         "Overshoot range",
  52.         "Overflow, off power",
  53.     ]
  54.     idx = bisect.bisect_left(ranges, value)
  55.     try:
  56.         kind = areas[idx]
  57.     except IndexError:
  58.         kind = areas[-1]
  59.     if idx == 0 or idx + 1 >= len(ranges):
  60.         return 0.0, kind
  61.     return scale(normalized, min_scale, max_scale), kind
  62.  
  63.  
  64. class TestNormalize(unittest.TestCase):
  65.     def test_lower(self):
  66.         normalized = normalize(-1024, -1024, 1023)
  67.         self.assertTrue(math.isclose(normalized, 0))
  68.  
  69.     def test_upper(self):
  70.         normalized = normalize(1023, -1024, 1023)
  71.         self.assertTrue(math.isclose(normalized, 1))
  72.  
  73.     def test_half_lower(self):
  74.         normalized = normalize(512, 0, 1024)
  75.         self.assertTrue(math.isclose(normalized, 0.5))
  76.  
  77.     def test_siemens_upper(self):
  78.         normalized1 = normalize(0, 0, 27648)
  79.         normalized2 = normalize(27648, 0, 27648)
  80.         self.assertTrue(math.isclose(normalized1, 0))
  81.         self.assertTrue(math.isclose(normalized2, 1))
  82.  
  83.  
  84. class TestScale(unittest.TestCase):
  85.     def test_lower(self):
  86.         normalized = scale(0, -10, 10)
  87.         self.assertTrue(math.isclose(normalized, -10))
  88.  
  89.     def test_upper(self):
  90.         normalized = scale(1, -10, 10)
  91.         self.assertTrue(math.isclose(normalized, 10))
  92.  
  93.     def test_zero(self):
  94.         normalized = scale(0.5, -10, 10)
  95.         self.assertTrue(math.isclose(normalized, 0))
  96.  
  97.  
  98. class TestScaleSiemens(unittest.TestCase):
  99.     def test_kind(self):
  100.         values = (
  101.             32767,
  102.             32512,
  103.             32511,
  104.             27649,
  105.             27648,
  106.             20736,
  107.             1,
  108.             0,
  109.             -1,
  110.             -20736,
  111.             -27648,
  112.             -27649,
  113.             -32512,
  114.             -32513,
  115.             -32768,
  116.         )
  117.         areas = (
  118.             *["Overflow, off power"] * 2,
  119.             *["Overshoot range"] * 2,
  120.             *["Rated range"] * 7,
  121.             *["Undershoot range"] * 2,
  122.             *["Underflow, at zero voltage and current"] * 2,
  123.         )
  124.         for value, area in zip(values, areas):
  125.             scaled, kind = scale_siemens(value, -10, 10, True)
  126.             self.assertEqual(area, kind)
  127.  
  128.     def test_zero_values(self):
  129.         lower_zero = -32513
  130.         upper_zero = 32512
  131.         value, _ = scale_siemens(lower_zero, -10, 10, True)
  132.         self.assertEqual(value, 0.0)
  133.         value, _ = scale_siemens(upper_zero, -10, 10, True)
  134.         self.assertEqual(value, 0.0)
  135.  
  136.     def test_undershoot(self):
  137.         value, _ = scale_siemens(-32512, -10, 10, True)
  138.         value = round(value, 2)
  139.         orig = round(-11.76, 2)
  140.         self.assertTrue(math.isclose(value, orig))
  141.  
  142.     def test_rated_low(self):
  143.         value, _ = scale_siemens(-27648, -10, 10, True)
  144.         self.assertTrue(math.isclose(value, -10))
  145.  
  146.     def test_rated_high(self):
  147.         value, _ = scale_siemens(27648, -10, 10, True)
  148.         self.assertTrue(math.isclose(value, 10))
  149.  
  150.     def test_half_high(self):
  151.         value, _ = scale_siemens(27648 // 2, -10, 10, True)
  152.         self.assertTrue(math.isclose(value, 5))
  153.  
  154.     def test_half_low(self):
  155.         value, _ = scale_siemens(-27648 // 2, -10, 10, True)
  156.         self.assertTrue(math.isclose(value, -5))
  157.  
  158.  
  159. if __name__ == "__main__":
  160.     doctest.testmod()
  161.     unittest.main()
  162.  
  163.  
Add Comment
Please, Sign In to add comment