An
MCP6004 quad-op-amp is used since it is a rail-to-rail op-amp capable of running from a 0-5V source (with a 2.5V virtual ground).
Two of the four op-amps are employed to generate the triangle wave. An op-amp is configured as a
relaxation oscillator feeding a square wave to a second op-amp that is configured as an integrator. The result is a triangle wave running at about 3 kHz for the values specified in the schematic. The triangle wave is independent of either
X or
Y multiplicands. It does though make use of virtual ground (
VREF)—or 2.5V in this case.
Rather than a dedicated comparator, it was easy (lazy) to use another of the MCP6004 op-amps. The comparator takes the X multiplicand at one input and the triangle wave for the other input. The output of the comparator is either high or low (~5V or ~0V) depending upon the compared voltages. Were the X voltage right in the middle of the range, or 2.5V, half the time the triangle wave is above 2.5V and half the time below. The output then would be a square wave with a 50% duty cycle. Varying the voltage of X then will vary the duty cycle of the output.
That duty-cycled output (PWM) feeds into an analog switch: the
CD4053B multiplexer. One of the analog switches is used—its output is our
X×Y. What does it switch between? It switches between the
Y multiplicand voltage and the negated
Y (
-Y) multiplicand voltage (we get our negative
Y by using the last of the four op-amps as an inverter). For the previous example of a 50% duty cycle, the analog switch will output a signal that averages "machine 0" volts (in the case of our virtual ground, that would be 2.5V).
I've attached a photo of my breadboard prototype as well as a custom perfboard prototype.