Проблема с арифметикой массива Bash Script для простого генератора синусоидальных волн

Я новичок в сценариях bash и Linux в целом. Я пытаюсь отправить серию быстрых команд регулятору давления (с разницей в полсекунды), что я обычно делаю с помощью простого прямоугольного импульса с использованием сценариев bash. Однако я не могу понять правильный синтаксис для синусоидального импульса. Я не мог найти способ использовать настоящую синусоидальную функцию, но серия небольших дискретных шагов сработала бы точно так же.

Вот мой сценарий:

#!/bin/bash

Pmax="90"
Pmin="10"
Rcor="7.91"  #This converts the pressure setting into the devices scaled range.
declare -a Sinewave20=(0 0.309 0.588 0.809  0.951  1  0.951  0.809  0.580 0.309 0 -0.309 -0.588 -0.809 -0.951 -1 -0.951 -0.809 -0.588 -0.309)
Amplitude=$(( $Pmax-$Pmin ))
Offset=$(( $Pmin+$Amplitude/2  ))

# 6 cycles of Sinewave20 corresponds to 1 min of .1 hz sine wave
for i in {0..6}
do
        # Let's send the commands for a 20 pt sine wave
        for x in "${!Sinewave20[@]}";
        do
                Value=$(( $Amplitude*$Rcor*$Sinewave20[x]+{Offset*$Rcor ))

                echo -e "SET ${Value}\r"  > /dev/ttyUSB1
                sleep 0.5
        done
done

Это приводит к следующему сообщению об ошибке:

строка 18: 80*7.91*0[x]+{Offset*7.91: синтаксическая ошибка: неверный арифметический оператор (токен ошибки ".91*0[x]+{Offset*7.91")

Я пробовал разные способы написания, но не нашел подходящего. Команда для изменения давления проста:

echo -e "SET 100\r" > /dev/ttyUSB1


person Daniel Max Sherman    schedule 05.12.2019    source источник


Ответы (3)


Арифметика Bash ограничена целыми числами.

Рассмотрите возможность использования механизма сценариев со встроенной поддержкой чисел с плавающей запятой. Либо облегченный awk или bc, либо один из full языков: Python, Perl и т. д.

См.: Как использовать деление с плавающей запятой в bash? и https://unix.stackexchange.com/questions/40786/how-to-do-integer-float-calculations-in-bash-or-other-languages-frameworks/40787#40787

person dash-o    schedule 05.12.2019
comment
На самом деле, просто зная, что Bash ограничен целочисленной математикой, я понял, как обойти проблему, с которой я столкнулся. Я только что вычислил все точки в электронной таблице, убедился, что это целые значения, поместил их в массив, который будет прочитан сценарием Bash и передан эхом на устройство. Это сработало, это не очень гибко, но это обошло проблему. Сегодня коллега дал мне скрипт на Python, который я могу начать адаптировать. Спасибо за своевременный совет! - person Daniel Max Sherman; 07.12.2019
comment
@DanielMaxSherman Я заметил несколько опечаток в решении awk, из-за которых оно не работало. Публикация слегка измененного скрипта, если вы хотите использовать более простой awk вместо python. Что бы ни работало... - person dash-o; 07.12.2019

Не могли бы вы попробовать замену на awk:

Pmax="90"
Pmin="10"
Rcor="7.91"

awk -v Pmax="$Pmax" -v Pmin="$Pmin" -v Rcor="$Rcor" '
BEGIN {
    PI = atan2(0, -1)
    Amplitude = Pmax - Pmin
    Offset = Pmin + Amplitude / 2
    for (i = 0; i <= 6; i++) {
        for (j = 0; j < 20; j++) {
            Value = (Amplitude * sin(j / 10 * PI) + Offset) * Rcor
            printf("SET %f\r\n", Value) > /dev/ttyUSB1
            system("sleep 0.5")
        }
    }
}'

Надеюсь это поможет.

person tshiono    schedule 05.12.2019
comment
Я попробовал это сегодня, и хотя это не дало ошибки, это не сработало. Я недостаточно знаком с операторами awk, чтобы устранять ошибки. По причине, указанной выше, я собираюсь дать лучший ответ на комментарий выше. - person Daniel Max Sherman; 07.12.2019

Это модифицированная версия скрипта tshiono awk, исправляющая несколько опечаток (/dev/... нужно заключать в кавычки, ...), технические проблемы (устройство должно быть закрыто на каждой итерации, ...) и слегка упрощенная.

Чтобы ПРОВЕРИТЬ скрипт: bash script.sh, он покажет значения, которые будут отправлены (без задержки)

Чтобы ЗАПУСТИТЬ скрипт: bash script.sh /dev/ttyUSB1.

Файл: script.sh

#! /bin/bash
awk -v Device="$1" '
BEGIN {
    Pmax=90
    Pmin=10
    Rcor=7.91
    PI = atan2(0, -1)
    Amplitude = Pmax - Pmin
    Offset = Pmin + Amplitude / 2
    for (i = 0; i <= 6; i++) {
        for (j = 0; j < 20; j++) {
            Value = (Amplitude * sin(j / 10 * PI) + Offset) * Rcor
            printf "Sending: SET %f\r\n", Value > "/dev/stderr"
            if ( Device ) {
                printf "SET %f\r\n", Value > Device
                close(Device)
                system("sleep 0.5")
            }  
        }
    }
}'
person dash-o    schedule 07.12.2019