Я обрабатываю форму волны в PHP, понижая ее с помощью хромого кодировщика, а затем вытягивая форму волны из результирующих точек данных. В настоящее время я получаю изображения следующим образом:
То, что я хотел бы сделать, это изменить мой код, чтобы кажущийся динамический диапазон формы сигнала был по существу «сжат». Чтобы создать форму волны, которая выглядит более точно:
Используемое мной уравнение для отображения высоты каждой точки данных выглядит следующим образом:
// draw this data point // relative value based on height of image being generated // data values can range between 0 and 255 $v = (int) ( $data / 255 * $height ); // don't print flat values on the canvas if not necessary if (!($v / $height == 0.5 && !$draw_flat)) // draw the line on the image using the $v value and centering it vertically on the canvas imageline( $img, // x1 (int) ($data_point / DETAIL), // y1: height of the image minus $v as a percentage of the height for the wave amplitude $height * $wav - $v, // x2 (int) ($data_point / DETAIL), // y2: same as y1, but from the bottom of the image $height * $wav - ($height - $v), imagecolorallocate($img, $r, $g, $b) );
При фактической амплитуде, определяемой первой строкой этого кода: –
$v = (int) ( $data / 255 * $height );
К сожалению, мой математический навык в лучшем случае беден. То, что мне нужно сделать, по существу, применяет «кривую» к значению $ v, так что, когда число, вводимое в уравнение, меньше, результирующий выход выше, а при увеличении входного числа уравнение уменьшает усиление до тех пор, пока, наконец, вход достигает 255, выход должен также быть 255. Также кривая должна быть такой, чтобы при вводе 0 выход был также 0.
Прошу прощения, если это неясно, но я очень затрудняюсь сформулировать этот вопрос с моим ограниченным математическим опытом.
Возможно, визуальное представление поможет описать мое намерение:
Когда значение $ v равно либо 0, либо 255, выход уравнения должен быть точно входом (0 или 255). Однако, когда вход представляет собой значение между ними, он должен следовать результирующему выходу кривой выше. (приведенное выше было только грубым рисунком, чтобы проиллюстрировать.)
РЕДАКТИРОВАТЬ:
Основываясь на решении функции «pow» от Alnitiks, я теперь генерирую сигналы, которые выглядят так:
Используя уравнение замены для переменной $ v следующим образом:
$v = pow($data / 255.0, 0.4) * $height;
Я попытался повысить значение 0,4, но результат все еще не так, как предполагалось.
EDIT 2:
В соответствии с запрошенным здесь является исходным datadump моей переменной $ data:
Необработанные данные
Это передается в уравнение, чтобы возвращать $ v перед тем, как его использовать для рисования формы волны (вы можете видеть, что я делаю с переменной $ v в исходном коде, который я разместил выше. $ Height просто число пикселей в высоком я установил изображение визуализировать.
Эти данные представляют собой разделенный запятыми список значений. Надеюсь, это поможет. Похоже, ваше утверждение о том, что среднее значение равно 128, является правильным. До сих пор я не мог задуматься об этом. Боюсь, что это немного превышает мое нынешнее понимание.
Без математических навыков (и, вероятно, полезно иметь быстрый дисплей):
У вас есть 256 возможных значений. Создайте массив, который содержит «динамическое» значение для каждого из этих значений:
$dynamic = array( 0 => 0, 1 => 2, ... );
Это сделано, вы можете легко получить динамическое значение:
$v = (int) ($dynamic[(int) $data / 255] * $height);
Вы можете потерять некоторую точность, но это, вероятно, полезно.
Естественные динамические значения генерируются функциями математического синуса и косинуса, в PHP это sin
Docs (и другие, связанные с ним).
Вы можете использовать цикл и эту функцию для предварительной заливки массива и повторно использовать массив, чтобы вы предварительно рассчитали значения:
$sine = function($v) { return sin($v * 0.5 * M_PI); }; $dynamic = array(); $base = 255; for ($i = 0; $i <= $base; $i++) { $dynamic[$i] = $i/$base; } $dynamic = array_map($sine, $dynamic);
Здесь я использую переменную функцию, поэтому вы можете писать несколько и можете легко проверить, какая из них соответствует вашим потребностям.
Вам нужно что-то подобное гамма-коррекции.
Для входных значений x в диапазоне 0.0 -> 1.0 возьмите y = pow(x, n)
когда n
должно находиться в диапазоне 0,2 – 0,7 (ish). Просто выберите число, которое дает желаемую кривую.
Поскольку ваши значения находятся в диапазоне 0 -> 255, вам необходимо разделить на 255,0, применить функцию pow
, а затем снова умножить на 255, например
$y = 255 * pow($x / 255.0, 0.4);
Формула pow
удовлетворяет критериям, которые 0 и 1 сопоставляют себе, а более мелкие значения «усиливаются» больше, чем более высокие значения.
Вот график, показывающий гамма-кривые для n = 1 / 1,6, 1/2, 1 / 2,4 и 1 / 2,8, против кривой sin
(красным):
Чем меньше значение n
, тем больше «сжатие» применяется к нижнему концу, поэтому светло-синяя линия соответствует значению n = 1 / 2.8.
Обратите внимание на то, что кривая sin
почти линейна в диапазоне от 0 до 0,5, поэтому практически не имеет сжатия в нижнем конце.
Если, как я подозреваю, ваши значения на самом деле сосредоточены вокруг 128, вам нужно немного изменить формулу:
$v = ($x - 128.0) / 128.0; $y = 128 + 127 * sign($v) * pow(abs($v), 0.4);
хотя я вижу, что разработчики PHP не включили функцию sign
в библиотеку PHP.