78

In a similar way that modulo generates a sawtooth wave. It doesn't have to be continuous.

here is what i mean:

int m = 10;
int x = 0;
int i = 0;
while (i < m*3) {
    printf("%d ", x);
    x++;
    x = x % m;
    i++;
}

generates a sequence 0..9, three times which looks like this:

sawtooth wave graph

note that the slope on the right side of the peak is just a graphing artifact

The one-liner in this case is x = i++ % m


What I want is this:

triangle wave graph

If you know one-liners for the other wave forms (sine, square), that would be good to know as well.

Update: everyone's answers have been very helpful and I have a follow-up question.

What would be added to the triangle wave function to make the slope of the lines curve in or out like this:

bulging waveforms

Thanks everyone, your varied answers helped me see the problem from a larger perspective. Special thanks to Noldorin for his take on extending the equation to quadratic curves.

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
willc2
  • 38,991
  • 25
  • 88
  • 99

8 Answers8

115

Triangular Wave

y = abs((x++ % 6) - 3);

This gives a triangular wave of period 6, oscillating between 3 and 0.

Square Wave

y = (x++ % 6) < 3 ? 3 : 0;

This gives a regular square wave of period 6, oscillating between 3 and 0.

Sine Wave

y = 3 * sin((float)x / 10);

This gives a sine wave of period 20 pi, oscillating between 3 and -3.


Update:

Curvy Triangular Wave

To get a variation of the triangular wave that has curves rather than straight lines, you just need to introduce an exponent into the equation to make it quadratic.

Concave curves (i.e. x^2 shape):

y = pow(abs((x++ % 6) - 3), 2.0);

Concave curves (i.e. sqrt(x) shape):

y = pow(abs((x++ % 6) - 3), 0.5);

Alternatively to using the pow function, you could simply define a square function and use the sqrt function in math.h, which would probably improve performance a bit.

Also, if you want to make the curves steeper/shallower, just try changing the indices.


In all of these cases you should easily be able to adjust constants and add scaling factors in the right places to give variations of the given waveforms (different periods, ampltiudes, asymmetries, etc.).

Noldorin
  • 144,213
  • 56
  • 264
  • 302
  • 2
    Note that my x does not correspond to your x in the question. The x I used here represents the conventional value along the x-axis, and similarly y represents the value along the y-axis. The x here seems to be the i in your question. – Noldorin Jul 02 '09 at 10:43
  • I could add these waveforms to get more complicated ones as well, yes? – willc2 Jul 02 '09 at 11:16
  • 1
    Doesn't that triangular wave oscillate between 3 and *0*? – Keith Smith Jul 02 '09 at 11:18
  • @willc2: Yes, of course. :) If you're wondering how to get another specific waveform, just ask, and I can suggest something - these provide good starting blocks however. – Noldorin Jul 02 '09 at 12:01
  • @litb: Thanks... And yeah, I thought I had answered the question rather completely, but never mind. – Noldorin Jul 08 '09 at 07:45
  • just checking in the square wave example, the first 3 is the period/2 correct? i.e. y = (x++ % period) < period/2 ? 3 : 0; – Max MacLeod Feb 22 '12 at 12:23
  • @MaxMacLeod: Correct. The second 3 is just the amplitude/height, which is independent. `period/2` gives a symmetric square wave (mark-space ratio of 1). – Noldorin Feb 22 '12 at 15:18
  • thanks @Noldoring! one other question for you. When I graph the results, it doesn't look square. However, looking at all square wave graphs, they all of course appear square. I take it that they are not functions of x and y. Rather they are a chart of y against time with most of the factors not represented? – Max MacLeod Feb 22 '12 at 16:44
  • @MaxMacLeod: I'm not sure how you're plotting the graphs; there could be some mistranslation going on there. But the functions I've listed are simple Cartesian y = f(t) graphs really. y can be any quantity here (it's the oscillating variable), and t doesn't have to be time of course, though it often is. That's generally the easier form to represent a wave/graph in most contexts. – Noldorin Feb 22 '12 at 21:46
  • The triangular wave equation you have given is not triangular.. its sawtooth, isn't it? – Rajavanya Subramaniyan Sep 26 '12 at 09:15
  • @Quakeboy: Nope, it's pretty definitely triangular. Sawtooth would just be `y = x++ % 6` or such. – Noldorin Sep 26 '12 at 17:08
  • @Noldorin: When I used your curvy triangular wave, the result doesn't seem symmetric at the peaks, is that normal? Also do you know how to plot a gaussian wave? Thanks. – Joan Venge Oct 27 '12 at 22:11
  • @Noldorin: Sorry forgot to ask, do you also know the meaning of 3 in your curvy triangle wave? First is frequence, last number (2.0) is amplitude but couldn't decide what 3 is? – Joan Venge Oct 27 '12 at 22:14
  • 1
    @JoanVenge: The subtraction of a constant is to offset the position of the curve so it's symmetric around the x-axis. Thus 3 is actually the amplitude (half of the peak-trough distance, which is 6). The `pow(..., 2.0)` is to form the quadratic curve. – Noldorin Oct 27 '12 at 23:33
  • @Noldorin: Thanks Noldorin, I changed it like you said, so made 3 the amp and left 2 as is and got this: http://i.imgur.com/1oSt7.png Is this correct? I was hoping to get something symmetric like UUUU if that makes sense? – Joan Venge Oct 27 '12 at 23:37
53

Expanding on Eric Bainville's answer:

y = (A/P) * (P - abs(x % (2*P) - P) )

Where x is a running integer, and y the triangle wave output. A is the amplitude of the wave, and P the half-period. For instance, A=5 will produce a wave which goes from 0 to 5; P=10 will produce a wave with a period of 20. The wave starts at y=0 for x=0.

Note that y will be a floating-point number unless P is a factor of A. And, yes, for the mathematical purists: A is technically twice the amplitude of the wave, but look at the picture below and you'll understand what I mean.

Visualised:

Lightsider
  • 630
  • 5
  • 5
30
x = m - abs(i % (2*m) - m)
Eric Bainville
  • 9,738
  • 1
  • 25
  • 27
11

I know this is an old post but for anyone that is searching for something similar I recommend looking at. http://en.wikipedia.org/wiki/Triangle_wave

The last formula y(x)=(2a/π)arcsin(sin((2π/p)*x))

or.

(2 * amplitudeConstant / Math.PI) * Math.Asin(Math.Sin(2 * (Math.PI / periodConstant) * Convert.ToDouble(variableX)))
Morgan
  • 111
  • 1
  • 2
  • 1
    The OP specified that the function doesn't have to be continuous, but in case it does need to work for fractional and negative values, this version is useful. – PeterT Dec 19 '15 at 18:18
  • 1
    Also note it outputs negative as well as positive values. – PeterT Dec 19 '15 at 18:41
  • This answer gives a simple triangle waveform without all the tweaks of the other answers. It's clear and concise, and I thank you! – Syndog Jul 30 '19 at 07:00
  • This is one of the few answers that works in Desmos or graphing calculators – Kartik Chugh Nov 02 '22 at 18:23
6
y = abs( amplitude - x % (2*amplitude) )

Changing the wavelength just needs a factor for x.

Edit: What I call amplitude is actually not the amplitude, but the maximum value (i.e. 5 if the curve oscillates betwen 0 and 5). The amplitude in the mathematical sense is half of that. But you get the point.

balpha
  • 50,022
  • 18
  • 110
  • 131
  • this results in a "V" wave; you'd need to add "y = m - y" to get a triangle wave – bubaker Jul 02 '09 at 10:58
  • A wave is usually considered infinite, making a "V wave" and a triangle wave essentially identical. But you're right in so far that if you want f(0) = 0, you have to do a shift. – balpha Jul 02 '09 at 11:09
0

Try this:

x = m - abs(m - 2*(i++ % m))
bubaker
  • 2,279
  • 1
  • 18
  • 13
0

Here is a periodic function that looks like a distant sine approximation; essentially it's a Sinuating paraboloid, using X squared:

function  xs ( xx : float ): float{

    var xd =Mathf.Abs((Mathf.Abs(xx) % 2.4) - 1.2);

    if (  Mathf.Abs(Mathf.Abs(xx) % 4.8)  > 2.4){ 
        xd=(-xd*xd)+2.88;
    }else{
        xd = xd*xd;
    }

    return xd;

}
David Gorsline
  • 4,933
  • 12
  • 31
  • 36
bandybabboon
  • 2,210
  • 1
  • 23
  • 33
-4

I've tested it with a simple loop and you guys haven't answered the man's question at all. Cut and pasting won't help people. No wonder so many mass media hoaxes have so much success. With a folks that repeats mistakes of others that cannot be any surprise is it. And people even give positive reputation rates for these wrong answers?! Unbelievable! But again, this parallels with my previous remark.

So first off we are going to explain to our folks what a TRIANGLE wave IS. Well it is a wave which has a period consisting of TWO equal sloped ramps. A ramp sloped UP and a ramp equally as the first but sloped DOWN contrary to a SAWTOOTH which has a ramp sloped UP or a ramp sloped DOWN repeated after a reversed talud.

PS: The last one who gave "y(x)=(2a/π)arcsin(sin((2π/p)*x))" is too complicated, we are looking for a fast c++ routine so trigonometry is absolutely out of the question.

Test routine:

(...)

for (byte V=0; V<255; V++)
{
unsigned int x = evenramp(V);
plotRGB(0,0,x,x,x);
delay(100); // make sure you have your own delay function declared of course

/* use your own graphic function !!! plotRGB(row,column,R,G,B) */
/* the light intensity will give you the change of value V in time */
/* all functions suggested as answer give SAWTOOTH and NOT TRIANGLE */
/* it is a TRIANGLE the man wants */
}

float triangleattempt(unsigned int x) // place any answered formula after '255 *' behind return.
{
return 255 * (255 - abs(255 - 2*(x % 255))); // this will show a SAWTOOTH
}

//All given answers up to now excluding "function  xs ( xx : float ): float" (this is not the requested one-liner, sorry) that are not a symmetrical triangle wave

// m - abs(i % (2*m) - m); (this is still a SAWTOOTH wave and not a TRIANGLE wave)
// abs((x++ % 6) - 3); (this is still a SAWTOOTH wave and not a TRIANGLE wave)
// abs(amplitude - x % (2*amplitude)); (this is still a SAWTOOTH wave and not a TRIANGLE wave)

=> I found a source which tells exactly what the answer is in mathematical notation: http://mathworld.wolfram.com/TriangleWave.html

I have tested the formula on a Linux program called KmPlot. Linux users can get kmplot via the root terminal typing apt-get install kmplot and if that doesn't work try using the regular terminal and type sudo apt-get install kmplot and if that doesn't work watch this youtube video for general instructions on installing a Linux program http://www.youtube.com/watch?v=IkhcwxC0oUg

SO A CORRECT ANSWER to the thread question is an example of a symmetrical triangle function declaration in c++ form shown below:

(...)

int symetrictriangle(float x)
{
unsigned int period = 30; // number of increases of x before a new cycle begins
unsigned int amplitude = 100; // top to bottom value while the bottom value is always zero
return amplitude * 2 * abs(round(x/period)-(x/period));
}

(...)

Cheerz!

user232365
  • 137
  • 6
  • 7
    The other answers were clear and concise, much more directly answering the question with a "one liner". From the question itself it's clear that the OP was aware of what a triangle wave is, so unsure why this is so hostile towards them. – Luke Briggs Sep 17 '15 at 11:33
  • Altought the other answers were clear, this answer is indeed the simplest to understand, and the fastest to execute since it only involves `abs` and basic math. However the hostility is unnecesary. – RegularGuy Aug 11 '20 at 14:38
  • Galileo died, but his answer was the best! – Florian Fasmeyer Jul 23 '23 at 02:27