Python Forum
Improvements for first script?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Improvements for first script?
#6
If I see PLC Content, I can't resist...

Just as additional information:

You can have different measurement ranges.
The most used ranges I know:

Current:
  • 0 - 20 mA [no cable break detection]
  • 4 - 20 mA

Voltage:
  • 0 - 10 V
  • -10 V - +10V # also negative Voltages are possible


The namedtuple is very useful.
from collections import namedtuple


def select_range():
    Range = namedtuple("range", "text low high unit")
    # just to have dot access
    ranges = [
        Range("0 - 10 V", 0, 10, "V"),
        Range("-10 - +10 V", -10, 10, "V"),
        Range("0 - 20 mA", 0, 20, "mA"),
        Range("4 - 20 mA", 4, 20, "mA"),
    ]
    while True:
        for idx, key in enumerate(ranges, 1):
            print(f"{idx}) {key.text}")
        print()
        selector = input("Please select a range: ")
        try:
            # two possible Exceptions
            # ValueError if the conversion to an int is not possible
            # IndexError if you selected a not existing index
            return ranges[int(selector) - 1]
        except (ValueError, IndexError):
            # catching this two exceptions to continue the while True loop
            # and ask again
            print("Invalid input")
I named the namedtuple Range, which is not a good name. It has nothing to do with range().


If the input was valid, the return value is a namedtuple.
You can access the values with dot.:
my_range = select_range()
print(my_range.text)
low, high = my_range.low, my_range.high
unit = my_range.unit
And to normalize and scale, I use these functions:
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)
Example with selected range:
# normalize 0 .. 27648 to 0 .. 1
# scale 0 .. 1 to 0 .. 100
percent = scale(normalize(15000, 0, 27648), 0, 100)
The thing is, if you know the minimum range and maximum range of the detected physical quantity, the step to convert it to a current or voltage, is not required. Only on PLC-Side the right range must be selected and the right connections must be used.
Example: https://cdn.sick.com/media/pdf/7/47/747/dataSheet_UC30-214163_6054712_en.pdf

The operating range is: 350 mm ... 3400 mm

The scaling with a Siemens PLC will look like this:
input_value = 1337
normalized_value = normalize(input_value, 0, 27648) # 0 - 10 V range
# the 27648 is the highest value of Rated Range
scaled = scale(normalized_value, 350, 3400)
In real world applications you can get also values, which are out of normal range.
For example, the sensor could output a higher current/voltage than 10V/20mA to signalling the PLC that something is not in operation range. If the range is 4 - 20 mA, then you can also detect a broken cable. In this case, the current is 0 mA.

SIEMENS has defined these areas for example:
  • Underflow, at zero voltage and current
  • Undershoot range
  • Rated range
  • Overshoot range
  • Overflow, off power
Source: https://support.industry.siemens.com/cs/...8&lc=en-DE

I've also made for this a function (but without the units):
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
The interesting part here is the use of the bisect module.
Otherwise, you've a pattern like:
value = 32760 # overshoot range

# From High to low...

if 32512 <= value <= 32767:
    kind = "Overflow, off power"
elif 27649 <= value <= 32511:
    kind = "Overshoot range"
elif -27648 <= value <= 27648:
    kind = "Rated range"
elif -32512 <= value <= -27649:
    kind = "Undershoot range"
elif -32768 <= value <= -32513:
    kind = "Underflow, at zero voltage and current" 

print(kind)
alloydog likes this post
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply


Messages In This Thread
Improvements for first script? - by alloydog - Dec-27-2020, 03:57 PM
RE: Improvements for first script? - by perfringo - Dec-28-2020, 05:25 AM
RE: Improvements for first script? - by Mark17 - Dec-30-2020, 05:41 PM
RE: Improvements for first script? - by alloydog - Dec-28-2020, 07:55 AM
RE: Improvements for first script? - by perfringo - Dec-30-2020, 08:01 AM
RE: Improvements for first script? - by alloydog - Dec-30-2020, 09:25 AM
RE: Improvements for first script? - by DeaD_EyE - Dec-30-2020, 12:28 PM
RE: Improvements for first script? - by alloydog - Dec-30-2020, 05:28 PM
RE: Improvements for first script? - by alloydog - Jan-01-2021, 01:45 PM
RE: Improvements for first script? - by perfringo - Jan-01-2021, 02:50 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  Any improvements Chuck_Norwich 2 2,710 Jul-14-2020, 05:15 AM
Last Post: Gamo
  [split] Any improvements Adamstiffman 1 1,928 May-31-2020, 06:16 AM
Last Post: pyzyx3qwerty
  Coding improvements chris_drak 2 37,409 May-02-2020, 11:39 AM
Last Post: chris_drak

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020