{"id":105,"date":"2019-10-01T16:04:51","date_gmt":"2019-10-01T16:04:51","guid":{"rendered":"https:\/\/synthnotes.ucsd.edu\/wp7\/?p=105"},"modified":"2020-09-17T20:36:08","modified_gmt":"2020-09-17T20:36:08","slug":"simple-square-and-triangle-oscillators","status":"publish","type":"post","link":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/2019\/10\/01\/simple-square-and-triangle-oscillators\/","title":{"rendered":"Simple Square and Triangle Oscillators"},"content":{"rendered":"<h1>Square and Triangle<\/h1>\n<p>Two other simple waveforms, the square and triangle, can also be created with the phasor as input. As with the simple ramp and sawtooth, these are more useful as low frequency modulating oscillators\u00a0than they are as audio oscillators.<\/p>\n<h2>Square<\/h2>\n<p>The square wave is just that: a waveform that resembles a square. It is a special case of the pulse wave, which we will see later, where the duty cycle (the ratio between the high and low points) is 50%. It can be created algebraically or via logic operations.<\/p>\n<h3>Using algebra<\/h3>\n<p><em>Caveat: this method resembled the engineering technique BFI more than a clean algebraic method.<\/em><\/p>\n<p>One method of this is to create a ramp or sawtooth, multiply it by some very high number, and clip it at -1 and +1: `(ramp*9999999).clip(-1,1)`.<\/p>\n<pre>\/\/ make a clip function\n\nfloat clip(float n, float lower, float upper)\n{\n    if(n&lt;lower) return lower;\n    else if (n&gt;upper) return upper;\n    else return n;\n}\n\nvoid Osc::Square(float *frequency, float *output, long samplesPerBlock)\n{\n    long sample;\n    float rampPhase;\n    \/\/ calculate for each sample in a block\n    for(sample = 0; sample&lt;samplesPerBlock; sample++)\n    {\n        \/\/ get the phase increment for this sample\n        phaseIncrement = *(frequency + sample)\/sampleRate; \n        \/\/ make a ramp (-1 to +1)\n        rampPhase = (phase*2.0) - 1.0; \n        \/\/ get the output for this sample\n        *(output+sample) = clip(ramp*9999999999, -1.0, 1.0); \n        \/\/ increment the phase\n        phase = phase + phaseIncrement; \n    }\n}<\/pre>\n<p><a href=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/squareClip_blockDiagram.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-155\" src=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/squareClip_blockDiagram.png\" alt=\"\" width=\"406\" height=\"317\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/squareClip_blockDiagram.png 406w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/squareClip_blockDiagram-300x234.png 300w\" sizes=\"auto, (max-width: 406px) 100vw, 406px\" \/><\/a><\/p>\n<p>This method is very closely related to the sign method of creating the square wave in which the sign of a sinusoid is used to get either -1 or +1:<\/p>\n<span class=\"wp-katex-eq\" data-display=\"false\">x(t) = sgn(sin fT)<\/span>\n<h4>Counting samples<\/h4>\n<p>One can also count the number of samples in a period. That is, if we know our sample rate is 1000Hz and we want a square wave at a frequency of 50Hz, we know that a complete period of the square wave will be 1000\/50 or `samplerate\/frequency`. This means that a 50Hz square wave (or any waveform, for that matter) at a 1000Hz sample rate is going to have a period of 20 samples. Since we know that a square wave&#8217;s duty cycle is 50%, we know that the wave will be +1 for 10 samples, then -1 for 10 samples.<\/p>\n<p><em>NOTE: This is related to BLIP and BLEP<\/em><\/p>\n<h3>Using logic<\/h3>\n<p>Perhaps a bit cleaner is to use logical operations on a phasor:<\/p>\n<pre>void Osc::Square(float *frequency, float *output, long samplesPerBlock)\n{\n    long sample;\n    \/\/ calculate for each sample in a block\n    for(sample = 0; sample&lt;samplesPerBlock; sample++)\n    {\n        \/\/ get the phase increment for this sample\n        phaseIncrement = *(frequency + sample)\/sampleRate; \n\n        \/\/ calculate the output for this sample\n        if(phase &lt;= 0) *(output+sample) = -1.0;\n        else *(output+sample) = 1.0;\n        \/\/ increment the phase\n        phase = phase + phaseIncrement; \n    }\n}<\/pre>\n<h3>Combining a ramp and a sawtooth<\/h3>\n<p>One can also sum a ramp and a sawtooth, offset in phase by 1\/2 of a cycle to create a square. We will see this method in the future when we use it to create pulses of different lengths in pulse width modulation.<\/p>\n<pre>float phaseRamp, phaseSaw;<br \/><br \/>void Osc::SquarePMW(float frequency, float width, float *output, long samplesPerBlock)<br \/>{<br \/>    \/\/ width varies between 0.0 and 1.0, width is 0.5 for square\n    long sample;<br \/>    float ramp, saw, square;\n    \/\/ calculate for each sample in a block\n    for(sample = 0; sample&lt;samplesPerBlock; sample++)\n    {\n        phasePerSample = frequency\/sampleRate;<br \/>        ramp = (phaseRamp * 2.0) - 1.0;<br \/>        saw = -1.0 * ((phaseSaw * 2.0) - 1.0);<br \/>        square = ramp + saw;<br \/>        \/\/ ((width - 0.5) * 2) needs to be added to<br \/>        \/\/ the sum to make waveform symmetrical around 0<br \/>        square = square + ((width - 0.5) * 2.0);\n        *(output+sample) = square;<br \/>\n        phaseRamp = phaseRamp + phasePerSample; <br \/>\u00a0       if(phaseRamp &gt; 1.0) phaseRamp = phaseRamp - 1.0;<br \/>        if(phaseRamp &lt;= 0.0) phaseRamp = phaseRamp + 1.0;  <br \/>\u00a0       phaseSaw = phaseRamp + width;<br \/>        if(phaseSaw &gt; 1.0) phaseSaw = phaseSaw - 1.0;     <br \/>    }<br \/>} <\/pre>\n<p>Whatever method is used, the result looks something like this:<\/p>\n<p><a href=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/square.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-157\" src=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/square.png\" alt=\"\" width=\"1821\" height=\"487\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/square.png 1821w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/square-300x80.png 300w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/square-768x205.png 768w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/square-1024x274.png 1024w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/square-624x167.png 624w\" sizes=\"auto, (max-width: 1821px) 100vw, 1821px\" \/><\/a><\/p>\n<h2>Triangle<\/h2>\n<p>The triangle wave is another of the basic waveforms. It forms a triangle, centered about 0, that linearly ascends from -1 to +1, then from +1 to -1.<\/p>\n<h3>Using algebra<\/h3>\n<p>If the input is a phasor, we can create a triangle wave using absolute value and some multiplication:<\/p>\n<p>`triangle = (abs(phasor-0.5)*4)-1;`<\/p>\n<p><a href=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle1_blockDiagram.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-158\" src=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle1_blockDiagram.png\" alt=\"\" width=\"566\" height=\"272\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle1_blockDiagram.png 566w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle1_blockDiagram-300x144.png 300w\" sizes=\"auto, (max-width: 566px) 100vw, 566px\" \/><\/a><\/p>\n<p>This method creates a triangle wave that begins it&#8217;s cycle at the crest of the waveform. Here are the first 512 samples of a 100Hz triangle wave sampled at 8kHz.<\/p>\n<p><a href=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-159\" src=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle.png\" alt=\"\" width=\"1395\" height=\"251\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle.png 1395w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle-300x54.png 300w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle-768x138.png 768w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle-1024x184.png 1024w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle-624x112.png 624w\" sizes=\"auto, (max-width: 1395px) 100vw, 1395px\" \/><\/a><\/p>\n<p>We can also use a slightly different method but using the floor function, or truncation, in addition to absolute value, where truncation removes the decimal portion of a floating point value (essentially rounding _down_ to the nearest integer).<\/p>\n<span class=\"wp-katex-eq\" data-display=\"false\">x_{triangle}(t) = 2 \\bigg| 2 \\bigg(\\frac{t}{p} - \\bigg\\lfloor \\frac{t}{p} + \\frac{1}{2} \\bigg\\rfloor \\bigg) -1 \\bigg| - 1<\/span>\n<p>where _p_ is the period and _t_ is time in seconds.<\/p>\n<p>`triangle(f) = (4 * abs(phasor(f) &#8211; trunc(phasor(f) + 0.5))) &#8211; 1`<\/p>\n<p><a href=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle2_blockDiagram.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-160\" src=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle2_blockDiagram.png\" alt=\"\" width=\"857\" height=\"212\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle2_blockDiagram.png 857w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle2_blockDiagram-300x74.png 300w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle2_blockDiagram-768x190.png 768w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle2_blockDiagram-624x154.png 624w\" sizes=\"auto, (max-width: 857px) 100vw, 857px\" \/><\/a><\/p>\n<p>This method, as opposed to the one above, creates a triangle wave that begins its cycle at the trough:<\/p>\n<p><a href=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle_trough.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-161\" src=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle_trough.png\" alt=\"\" width=\"1849\" height=\"336\" srcset=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle_trough.png 1849w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle_trough-300x55.png 300w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle_trough-768x140.png 768w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle_trough-1024x186.png 1024w, https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/triangle_trough-624x113.png 624w\" sizes=\"auto, (max-width: 1849px) 100vw, 1849px\" \/><\/a><\/p>\n<p>When implemented either way, the result sounds like this:<\/p>\n\n\n<figure class=\"wp-block-audio\"><audio controls src=\"https:\/\/synthnotes.ucsd.edu\/wp7\/wp-content\/uploads\/2019\/10\/tri.wav\"><\/audio><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Square and Triangle Two other simple waveforms, the square and triangle, can also be created with the phasor as input. As with the simple ramp and sawtooth, these are more useful as low frequency modulating oscillators\u00a0than they are as audio oscillators. Square The square wave is just that: a waveform that resembles a square. It [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-105","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/wp-json\/wp\/v2\/posts\/105","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/wp-json\/wp\/v2\/comments?post=105"}],"version-history":[{"count":8,"href":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/wp-json\/wp\/v2\/posts\/105\/revisions"}],"predecessor-version":[{"id":574,"href":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/wp-json\/wp\/v2\/posts\/105\/revisions\/574"}],"wp:attachment":[{"href":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/wp-json\/wp\/v2\/media?parent=105"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/wp-json\/wp\/v2\/categories?post=105"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/synthnotes.ucsd.edu\/wp7\/index.php\/wp-json\/wp\/v2\/tags?post=105"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}