Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import bisect
- import math
- import unittest
- import doctest
- def scale(value, low, high):
- """
- Scale the value from low .. high
- >>> scale(0, -10, 10)
- -10
- >>> scale(1, -10, 10)
- 10
- """
- return value * (high - low) + low
- def normalize(value, low, high):
- """
- Normalize value to 0 .. 1
- >>> normalize(0, 0, 10)
- 0.0
- >>> normalize(10, 0, 10)
- 1.0
- >>> normalize(5, 0, 10)
- 0.5
- """
- return (value - low) / (high - low)
- def scale_siemens(value, min_scale, max_scale, bipolar=False):
- """
- Scale Analog Values with siemens components:
- https://support.industry.siemens.com/cs/mdm/8859629?c=23218577931&t=1&s=27648&lc=en-DE
- Look at Table: Representation of analog values in the ±10 V output range
- """
- if bipolar:
- normalized = normalize(value, -27648, 27648)
- else:
- normalized = normalize(value, 0, 27648)
- ranges = (-32513, -27649, 27648, 32511, 32767)
- areas = [
- "Underflow, at zero voltage and current",
- "Undershoot range",
- "Rated range",
- "Overshoot range",
- "Overflow, off power",
- ]
- idx = bisect.bisect_left(ranges, value)
- try:
- kind = areas[idx]
- except IndexError:
- kind = areas[-1]
- if idx == 0 or idx + 1 >= len(ranges):
- return 0.0, kind
- return scale(normalized, min_scale, max_scale), kind
- class TestNormalize(unittest.TestCase):
- def test_lower(self):
- normalized = normalize(-1024, -1024, 1023)
- self.assertTrue(math.isclose(normalized, 0))
- def test_upper(self):
- normalized = normalize(1023, -1024, 1023)
- self.assertTrue(math.isclose(normalized, 1))
- def test_half_lower(self):
- normalized = normalize(512, 0, 1024)
- self.assertTrue(math.isclose(normalized, 0.5))
- def test_siemens_upper(self):
- normalized1 = normalize(0, 0, 27648)
- normalized2 = normalize(27648, 0, 27648)
- self.assertTrue(math.isclose(normalized1, 0))
- self.assertTrue(math.isclose(normalized2, 1))
- class TestScale(unittest.TestCase):
- def test_lower(self):
- normalized = scale(0, -10, 10)
- self.assertTrue(math.isclose(normalized, -10))
- def test_upper(self):
- normalized = scale(1, -10, 10)
- self.assertTrue(math.isclose(normalized, 10))
- def test_zero(self):
- normalized = scale(0.5, -10, 10)
- self.assertTrue(math.isclose(normalized, 0))
- class TestScaleSiemens(unittest.TestCase):
- def test_kind(self):
- values = (
- 32767,
- 32512,
- 32511,
- 27649,
- 27648,
- 20736,
- 1,
- 0,
- -1,
- -20736,
- -27648,
- -27649,
- -32512,
- -32513,
- -32768,
- )
- areas = (
- *["Overflow, off power"] * 2,
- *["Overshoot range"] * 2,
- *["Rated range"] * 7,
- *["Undershoot range"] * 2,
- *["Underflow, at zero voltage and current"] * 2,
- )
- for value, area in zip(values, areas):
- scaled, kind = scale_siemens(value, -10, 10, True)
- self.assertEqual(area, kind)
- def test_zero_values(self):
- lower_zero = -32513
- upper_zero = 32512
- value, _ = scale_siemens(lower_zero, -10, 10, True)
- self.assertEqual(value, 0.0)
- value, _ = scale_siemens(upper_zero, -10, 10, True)
- self.assertEqual(value, 0.0)
- def test_undershoot(self):
- value, _ = scale_siemens(-32512, -10, 10, True)
- value = round(value, 2)
- orig = round(-11.76, 2)
- self.assertTrue(math.isclose(value, orig))
- def test_rated_low(self):
- value, _ = scale_siemens(-27648, -10, 10, True)
- self.assertTrue(math.isclose(value, -10))
- def test_rated_high(self):
- value, _ = scale_siemens(27648, -10, 10, True)
- self.assertTrue(math.isclose(value, 10))
- def test_half_high(self):
- value, _ = scale_siemens(27648 // 2, -10, 10, True)
- self.assertTrue(math.isclose(value, 5))
- def test_half_low(self):
- value, _ = scale_siemens(-27648 // 2, -10, 10, True)
- self.assertTrue(math.isclose(value, -5))
- if __name__ == "__main__":
- doctest.testmod()
- unittest.main()
Add Comment
Please, Sign In to add comment