Математика — это язык, на котором говорит природа, и язык, на котором должна говорить программа для ПЛК. Когда инженер-автоматизатор пишет программу управления технологическим процессом, он постоянно выполняет математические операции: вычисляет средние значения датчиков, масштабирует аналоговые сигналы, рассчитывает мощность потребления, определяет необходимые корректировки.
Арифметические операции в Structured Text (ST) — это базовый инструмент, которым должен владеть каждый программист, работающий с ПЛК. На первый взгляд сложение и вычитание кажутся тривиальными действиями, однако подводные камни, связанные с типами данных, порядком операций и точностью вычислений, часто приводят к серьезным ошибкам. Давайте разберемся во всех аспектах арифметических вычислений в ST.
Основные математические операторы в ST
В Structured Text используются четыре основных оператора для арифметических операций:
+ (плюс) — сложение
- (минус) — вычитание
* (звездочка) — умножение
/ (косая черта) — деление
Кроме того, существуют ещё два оператора, которые часто используются при работе с целыми числами:
MOD (модуль) — остаток от деления
** или ^ — возведение в степень
Давайте рассмотрим каждый из них:
Сложение (+)
Сложение — это, пожалуй, самая простая операция:
VAR
value1: INT := 100;
value2: INT := 50;
sum: INT;
END_VAR
sum := value1 + value2; (* sum = 150 *)
Сложение работает со всеми численными типами данных: INT, DINT, REAL, LREAL. Результат имеет тип, соответствующий одному из операндов (обычно более широкому типу):
VAR
intValue: INT := 100;
realValue: REAL := 25.5;
result: REAL;
END_VAR
result := intValue + realValue; (* результат: 125.5 (REAL) *)
Вычитание (-)
Вычитание работает аналогично сложению:
VAR
temperature: REAL := 25.5;
offset: REAL := 2.0;
correctedTemp: REAL;
END_VAR
correctedTemp := temperature - offset; (* correctedTemp = 23.5 *)
Одна из особенностей вычитания — это унарный минус, который позволяет поменять знак числа:
VAR
value: INT := 100;
inverted: INT;
END_VAR
inverted := -value; (* inverted = -100 *)
Умножение (*)
Умножение часто используется при масштабировании значений. Например, преобразование напряжения (0-10V) в физическую величину (0-100°C):
VAR
voltage: REAL := 5.0; (* 5 вольт *)
temp: REAL;
END_VAR
temp := voltage * 10.0; (* результат: 50°C *)
Множество промышленных задач требует умножения. Например, расчет потребленной энергии:
VAR
power: REAL := 2.5; (* киловатты *)
hours: REAL := 8.0; (* часов работы *)
energyConsumed: REAL;
END_VAR
energyConsumed := power * hours; (* результат: 20.0 кВт?ч *)
Деление (/)
Деление — это операция, требующая особого внимания, особенно при работе с целыми числами:
VAR
totalDistance: REAL := 150.0; (* километры *)
travelTime: REAL := 3.0; (* часы *)
averageSpeed: REAL;
END_VAR
averageSpeed := totalDistance / travelTime; (* результат: 50.0 км/ч *)
Однако при делении целых чисел результат также будет целым числом, и дробная часть будет отброшена:
VAR
total: INT := 10;
divisor: INT := 3;
result: INT;
END_VAR
result := total / divisor; (* результат: 3 (а не 3.333...) *)
Это важно помнить, так как потеря точности может привести к ошибкам в расчетах.
Остаток от деления (MOD)
Оператор MOD возвращает остаток от деления одного целого числа на другое:
VAR
number: INT := 17;
divisor: INT := 5;
remainder: INT;
END_VAR
remainder := number MOD divisor; (* результат: 2, так как 17 = 5*3 + 2 *)
MOD часто используется для определения четности/нечетности числа или для циклических расчетов:
itemCount: INT := 100;
itemsPerBox: INT := 12;
remainingItems: INT;
END_VAR
remainingItems := itemCount MOD itemsPerBox; (* сколько товара останется *)
Возведение в степень ( или ^)**
Возведение в степень используется реже, но может быть полезно при расчетах:
VAR
base: REAL := 2.0;
exponent: REAL := 3.0;
result: REAL;
END_VAR
result := base ** exponent; (* результат: 8.0 *)
(* или *)
result := base ^ exponent; (* то же самое *)
Порядок вычисления операций: в каком порядке считать?
Когда в одном выражении несколько операций, порядок их выполнения определяется правилами приоритета, которые известны со школьной скамьи: сначала выполняются операции с более высоким приоритетом, а затем — с более низким.
Приоритет операций в ST (от высшего к низшему):
- Возведение в степень: ** или ^
- Унарный минус: -value
- Умножение и деление: *, /, MOD
- Сложение и вычитание: +, -
Например, рассмотрим выражение:
result := 2 + 3 * 4;
Здесь сначала выполнится умножение (3 * 4 = 12), затем сложение (2 + 12 = 14). Результат: 14.
Если бы мы хотели сначала сложить, то нужны скобки:
result := (2 + 3) * 4; (* сначала 2+3=5, затем 5*4=20 *)
Это простое правило часто забывают, и результат оказывается совсем не тем, который ожидалось:
VAR
speed: INT := 10; (* м/с *)
time: INT := 5; (* секунды *)
acceleration: INT := 2; (* м/с? *)
distance: INT;
END_VAR
(* неправильно *)
distance := speed * time + acceleration * time;
(* правильный расчет для равноускоренного движения *)
distance := speed * time + (acceleration * time * time) / 2;
Практический пример с порядком операций
Представим, что мы рассчитываем стоимость электроэнергии:
VAR
baseCost: REAL := 50.0; (* базовая стоимость *)
powerUsed: REAL := 100.0; (* киловатт-часы *)
pricePerKwh: REAL := 5.5; (* рублей за кВт?ч *)
taxRate: REAL := 0.18; (* налог 18% *)
totalCost: REAL;
END_VAR
(* расчет стоимости *)
totalCost := baseCost + powerUsed * pricePerKwh * (1 + taxRate);
(* порядок выполнения:
1. powerUsed * pricePerKwh = 100 * 5.5 = 550
2. 1 + taxRate = 1 + 0.18 = 1.18
3. 550 * 1.18 = 649
4. baseCost + 649 = 50 + 649 = 699 *)
«
Углубленное изучение программируемых логических контроллеров (ПЛК) и всех аспектов промышленной автоматизации в Telegram:
ПЛК и автоматизация
Работа с целыми и вещественными числами
Одна из самых подвижных областей при работе с арифметикой в ПЛК — это различия между целыми числами (INT, DINT) и вещественными числами (REAL, LREAL).
Целые числа: точность без дробей
Целые числа хранятся в памяти точно. Если вы сохраняете значение 100, оно останется ровно 100, без какой-либо потери точности. Однако целые числа имеют ограниченный диапазон значений.
VAR
count: INT := 100;
doubled: INT;
END_VAR
doubled := count * 2; (* точный результат: 200 *)
Деление целых чисел выполняется с отсечением дробной части:
VAR
result: INT;
END_VAR
result := 10 / 3; (* результат: 3 (не 3.333...) *)
result := 10 / 4; (* результат: 2 (не 2.5) *)
Вещественные числа: диапазон ценой точности
Вещественные числа используют стандарт IEEE 754 и могут хранить дробные части. Однако они имеют ограниченную точность:
VAR
temperature: REAL := 25.5;
corrected: REAL;
END_VAR
corrected := temperature * 1.01; (* результат: 25.755 *)
Точность REAL — около 6-7 значащих цифр. Это означает, что если число имеет много цифр, точность может быть потеряна:
VAR
largeValue: REAL := 123456789.0; (* большое число *)
small: REAL := 0.0001;
result: REAL;
END_VAR
result := largeValue + small; (* может потерять точность *)
Для высокоточных вычислений используется LREAL (64-битное вещественное число):
VAR
pi: LREAL := 3.141592653589793;
radius: LREAL := 10.0;
circumference: LREAL;
END_VAR
circumference := 2 * pi * radius; (* высокая точность *)
Смешивание типов данных при операциях
Когда вы складываете или умножаете значения разных типов, контроллер автоматически преобразует их к общему типу. Правило простое: результат будет иметь более «широкий» тип:
VAR
intValue: INT := 100;
realValue: REAL := 25.5;
result: REAL;
END_VAR
result := intValue + realValue; (* INT преобразуется в REAL, результат: 125.5 *)
Однако при присваивании результата переменной другого типа может произойти преобразование:
VAR
realValue: REAL := 25.7;
intValue: INT;
END_VAR
intValue := realValue; (* будет ошибка типа данных! *)
(* нужно явное преобразование *)
intValue := INT(realValue); (* результат: 25 *)
Практический пример: масштабирование аналогового сигнала
Один из типичных применений арифметики в ПЛК — преобразование аналогового сигнала. Предположим, датчик давления выдает напряжение от 0 до 10 вольт, что соответствует давлению от 0 до 100 бар:
VAR
rawVoltage: REAL; (* сырой сигнал от датчика *)
minVoltage: REAL := 0.0; (* минимальный сигнал *)
maxVoltage: REAL := 10.0; (* максимальный сигнал *)
minPressure: REAL := 0.0; (* минимальное давление *)
maxPressure: REAL := 100.0; (* максимальное давление *)
pressure: REAL;
END_VAR
(* формула масштабирования *)
pressure := minPressure + (rawVoltage - minVoltage) *
(maxPressure - minPressure) / (maxVoltage - minVoltage);
(* если rawVoltage = 5V, то:
pressure = 0 + (5 - 0) * (100 - 0) / (10 - 0)
pressure = 0 + 5 * 100 / 10
pressure = 500 / 10
pressure = 50.0 бар *)
Типичные ошибки при расчетах
Ошибка 1: Деление целых чисел вместо вещественных
(* неправильно *)
VAR
average: INT;
END_VAR
average := (10 + 20 + 30) / 3; (* результат: 20, а не 20.0 *)
(* правильно *)
VAR
average: REAL;
END_VAR
average := (10.0 + 20.0 + 30.0) / 3.0; (* результат: 20.0 *)
Ошибка 2: Неправильный порядок операций
(* неправильно - вычисляем процент неправильно *)
VAR
price: REAL := 100.0;
discountPercent: REAL := 10.0;
finalPrice: REAL;
END_VAR
finalPrice := price - discountPercent / 100 * price; (* нарушен порядок *)
(* правильно *)
finalPrice := price * (1 - discountPercent / 100);
(* или *)
finalPrice := price - (price * discountPercent / 100);
Ошибка 3: Переполнение при умножении
VAR
a: INT := 32000;
b: INT := 5;
result: INT;
END_VAR
result := a * b; (* переполнение! INT не может хранить 160000 *)
(* правильно - используем больший тип *)
VAR
a: INT := 32000;
b: INT := 5;
result: DINT;
END_VAR
result := a * b; (* результат: 160000 *)
Ошибка 4: Потеря точности при суммировании больших последовательностей
VAR sum: REAL := 0.0;
i: INT;
END_VAR
(* суммируем много маленьких чисел *)
FOR i := 0 TO 10000 DO
sum := sum + 0.0001;
END_FOR;
(* из-за округления REAL результат может быть неточным *)
Ошибка 5: Деление на ноль
VAR
numerator: REAL := 100.0;
denominator: REAL := 0.0;
result: REAL;
END_VAR
result := numerator / denominator; (* критическая ошибка! *)
(* правильно - проверяем знаменатель *)
IF denominator <> 0.0 THEN
result := numerator / denominator;
ELSE
(* обработка ошибки *)
END_IF;
Ошибка 6: Сравнение вещественных чисел с точным равенством
VAR
a: REAL := 0.1 + 0.2;
b: REAL := 0.3;
END_VAR
(* неправильно *)
IF a = b THEN
(* из-за ошибок округления это может быть FALSE! *)
END_IF;
(* правильно - используем epsilon *)
IF ABS(a - b) < 0.0001 THEN
(* числа практически равны *)
END_IF;
Практический пример: полный расчет с обработкой ошибок
PROGRAM TemperatureAverage
VAR
sensor1: REAL := 25.5;
sensor2: REAL := 26.3;
sensor3: REAL := 24.8;
average: REAL;
minTemp: REAL := 20.0;
maxTemp: REAL := 30.0;
isValid: BOOL;
errorMessage: STRING := '';
END_VAR
(* расчет среднего значения *)
average := (sensor1 + sensor2 + sensor3) / 3.0;
(* проверка диапазона *)
IF average < minTemp THEN
isValid := FALSE;
errorMessage := 'Temperature too low';
ELSIF average > maxTemp THEN
isValid := FALSE;
errorMessage := 'Temperature too high';
ELSE
isValid := TRUE;
errorMessage := '';
END_IF;
END_PROGRAM
Оптимизация арифметических операций
В некоторых случаях производительность критична. Вот несколько советов по оптимизации:
Избегайте возведения в степень в циклах. Умножение быстрее, чем возведение в степень.
Используйте целые числа вместо вещественных, где это возможно. Целые числа вычисляются быстрее.
Кэшируйте результаты часто используемых вычислений.
(* неэффективно *)
FOR i := 0 TO 1000 DO
temp := sensorValue * 10.0 / (maxValue - minValue);
END_FOR;
(* эффективнее *)
VAR
scale: REAL := 10.0 / (maxValue - minValue);
END_VAR
FOR i := 0 TO 1000 DO
temp := sensorValue * scale;
END_FOR;
Математика как основа надежности
Арифметические операции — это не просто способ выполнения расчетов. Это способ выражения логики управления, трансформирования сырых сигналов в полезную информацию. Правильное использование арифметики, понимание особенностей целых и вещественных чисел, соблюдение порядка операций и обработка граничных случаев — это признак хорошего инженера.
Каждая статья, которую вы читаете про ПЛК, каждая программа, которую вы пишете, использует арифметику. От простого сложения счетчиков до сложных расчетов в ПИД-регуляторах — математика неотделима от промышленной автоматизации.
Расширьте ваши знания о программировании ПЛК
Если вы хотите изучить более продвинутые техники вычислений, узнать о численных методах, оптимизации сложных расчетов и увидеть примеры из реальных промышленных приложений, рекомендуем подписаться на канал «ПЛК и автоматизация» в Telegram — https://t.me/plcmasters.
Этот канал посвящен углубленному изучению программируемых логических контроллеров и всех аспектов промышленной автоматизации.
