Проблема в том, что я хочу контролировать значение символической переменной с помощью ползунка и динамически отображать результаты.Это очень медленная операция, и я не могу понять, как ее ускорить, сохраняя при этом преимущества использования символических выражений.
Я пытаюсь разработать интерфейс для построения дерева выражений, которое будет выводить уравнение, котороеподается в мой синтезатор.
Синтезатор генерирует таблицу из 256 значений, которые интерполируются в зависимости от того, как переменные используются в уравнении.Например, «w» относится к оси X одного сигнала.'y' оценивает текущую позицию в таблице, разделенную на 256. Таким образом, вы можете сгенерировать простую форму морфинга, например:
(1-y)*sin(w)+y*cos(w)
(https://i.imgur.com/2xh2Nc2.png)
Вот функция, которая обновляет график при смене ползунка.
this.plotLine = fplot(this.wavePlot, sym('x'));
function plotRefresh(src, event)
yVal = (event.Value-1)/255;
set(this.yLabel, 'Value', string(yVal));
set(this.zLabel, 'Value', string(yVal*2-1));
set(this.plotLine, 'Function', subs(this.eTree.activeSym, sym('y'), yVal));
end
Каждый узел в дереве имеет символическое выражение следующим образом. Когда новый узел добавляется в дерево, его дочерние элементы передаются ванонимная функция для генерации выражения в этой точке дерева.
case nTypes.W
sy = sym('w');
case nTypes.X
sy = sym('w')*2-1;
case nTypes.Y
sy = sym('y');
case nTypes.Z
sy = sym('y')*2-1;
case nTypes.ADD
sy = @(n)fold(@(a,b)a+b, n);
case nTypes.SUBTRACT
sy = @(n)fold(@(a,b)a-b, n);
case nTypes.MULTIPLY
sy = @(n)fold(@(a,b)a*b, n);
case nTypes.DIVIDE
sy = @(n)fold(@(a,b)a/b, n);
case nTypes.EXPONENTIATE
sy = @(n)fold(@(a,b)a^b, n);
case nTypes.AND
sy = @(n)fold(@(a,b)and(a, b), n);
case nTypes.OR
sy = @(n)fold(@(a,b)or(a, b), n);
case nTypes.EQUAL
sy = @(n)fold(@(a,b)eq(a, b), n);
case nTypes.NOTEQUAL
sy = @(n)fold(@(a,b)ne(a, b), n);
case nTypes.GREATER
sy = @(n)fold(@(a,b)gt(a, b), n);
case nTypes.LESSER
sy = @(n)fold(@(a,b)lt(a, b), n);
case nTypes.GREATEROREQ
sy = @(n)fold(@(a,b)ge(a, b), n);
case nTypes.LESSEROREQ
sy = @(n)fold(@(a,b)le(a, b), n);
case nTypes.MIN
sy = @(n)fold(@(a,b)piecewise(a<=b, a, a>b, b), n);
case nTypes.MAX
sy = @(n)fold(@(a,b)piecewise(a>=b, a, a<b, b), n);
case nTypes.SIN
sy = @(n)sin(n{:});
case nTypes.COS
sy = @(n)cos(n{:});
case nTypes.TAN
sy = @(n)tan(n{:});
Я попытался реализовать это без символьных выражений, и это работает намного быстрее. В этом случае каждый узел имел двойной / встроенный дескриптор,который взял бы своих потомков в качестве параметра для первой анонимной функции, а затем возвратил бы другую анонимную функцию, которая выполняла бы ее оценку, учитывая глобальные переменные w и y.
case nTypes.SIN
sy = @(children)@(w, y)sin(children(w, y));
Затем я сделал массив ячеек 512x256 для кэшированиязначения для каждой возможной позиции ползунка.
cached = cellfun(@(y)cellfun(@(w)tNode.sy(w, y), linspace(0, 1, 512)), linspace(0, 1, 256))
Затем, когда ползунок изменяется, я делаю set(gca, 'YData', cached{sliderPosition})
Имея значения cached сделал обновление сюжета намного более плавным.Однако, если есть способ кеширования аналогичным образом с использованием символьной оценки вместо дерева глубоко вложенных анонимных функций, это предпочтительнее.
Возможно ли это?