Plotting Taylor Series Sine Waves

Previous posts have included an SVG library, memoization of factorials and Taylor Polynomials. In this post I will bring these all together to plot various sine waves created using Taylor Polynomials.

Very briefly, Taylor Polynomials are used to approximate functions, in this case sine and cosine, to any level of accuracy. We can plot these levels to show how they become increasingly accurate, which is the subject of this post.

A couple of examples are shown below. The dark blue circles show the sines calculated by the C Library's sin function; this can be taken as a definitive set of values. The other colours are sines calculated using Taylor Polynomials to various degrees, ie levels of accuracy. (Note that the degree of a Taylor Polynomial is not related to the degree as a unit of angle.) As you can see, the higher the degree the better the accuracy, the light blue degree 11 being the best. There is no theoretical limit to the degree, although the higher the degree the longer the calculation takes.

taylor series sine wave
taylor series sine wave

The three previous posts were:

Writing an SVG Library

Memoization of Factorials

Sines and Cosines with Taylor Polynomials

I won't go over these topics again in this post, but you might like to either read these posts before this one, or just regard them as black boxes which provide the necessary functionality for this project.

All the files needed for this project are included in the download from the Downloads page, but the new files are

  • taylorseriesplot.h
  • taylorseriesplot.c
  • main.c

Let's start by looking at the very simple header file, just one function prototype.

taylorseriesplot.h

//--------------------------------------------------------
// FUNCTION PROTOTYPES
//--------------------------------------------------------
void taylor_sin_plot(int maxsin, int maxdegrees, int step, int width, int height, char* filename);

And now taylorseriesplot.c where we will implement the function.

taylorseriesplot.c

#include<stdio.h>
#include<math.h>

#include"svg.h"
#include"taylorseries.h"

// --------------------------------------------------------
// FUNCTION taylor_init
// --------------------------------------------------------
void taylor_sin_plot(int maxsin, int maxdegrees, int step, int width, int height, char* filename)
{
    int topmargin = 64;
    int bottommargin = 32;
    int leftmargin = 32;
    int rightmargin = 128;

    int graph_height = height - topmargin - bottommargin;
    int graph_width = width - leftmargin - rightmargin;
    double pixels_per_unit_x = (double)graph_width / (double)maxdegrees;
    double pixels_per_unit_y = (double)graph_height / ((double)maxsin * 2.0);
    double x;
    double y;
    char number_string[8];
    double yzero = topmargin + (graph_height / 2);
    double sine;
    double radians;
    int colourindex;

    char colours[6][7] = {"blue", "red", "orange", "purple", "green", "cyan"};

    // Create svg struct
    svg* psvg;
    psvg = svg_create(width, height);

    if(psvg == NULL)
    {
        puts("psvg is NULL");
    }
    else
    {
        svg_fill(psvg, "#FFFFFF");

        // header text and border lines
        svg_text(psvg, leftmargin, 38, "sans-serif", 16, "#000000", "#000000", "start", "Sines calculated with Taylor Polynomials to degree 3, 5, 7, 9 and 11");
        svg_line(psvg, "#808080", 2, leftmargin, topmargin, leftmargin, height - bottommargin);
        svg_line(psvg, "#808080", 2, leftmargin, height - bottommargin, width - rightmargin, height - bottommargin);

        // y axis indexes and values
        y = topmargin;
        for(int s = maxsin; s >= (maxsin * -1); s--)
        {
            svg_line(psvg, "#808080", 1, leftmargin - 8, y, width - rightmargin, y);

            sprintf(number_string, "%d", s);
            svg_text(psvg, 20, y + 4, "sans-serif", 12, "#000000", "#000000", "end", number_string);

            y += pixels_per_unit_y;
        }

        // x axis indexes and values
        x = leftmargin;
        for(int d = 0; d <= maxdegrees; d+= 90)
        {
            svg_line(psvg, "#808080", 1, x, topmargin, x, height - bottommargin + 8);

            sprintf(number_string, "%d", d);
            svg_text(psvg, x, height - bottommargin + 24, "sans-serif", 12, "#000000", "#000000", "middle", number_string);

            x += (pixels_per_unit_x * 90);
        }

        // key
        x = width - rightmargin + 16;
        y = topmargin + 16;
        int currdegree = 3;
        char sdegree[3];
        for(colourindex = 0; colourindex <= 5; colourindex++)
        {
            svg_circle(psvg, colours[colourindex], 0, colours[colourindex], 6, x, y);

            if(colourindex == 0)
            {
                svg_text(psvg, x + 16, y + 4, "sans-serif", 12, "#000000", "#000000", "start", "math.h sin");
            }
            else
            {
                sprintf(sdegree, "%d", currdegree);
                svg_text(psvg, x + 16, y + 4, "sans-serif", 12, "#000000", "#000000", "start", sdegree);
                currdegree += 2;
            }

            y+= 24;
        }

        if(taylor_init(11))
        {
            x = leftmargin;

            for(double degree = 0; degree <= maxdegrees; degree+= step)
            {
                radians = degree / DEGREES_IN_RADIAN;

                // C Library sin
                sine = sin(radians);

                y = yzero - (sine * pixels_per_unit_y);

                colourindex = 0;

                svg_circle(psvg, colours[colourindex], 0, colours[colourindex], 3, x, y);

                // Taylor Polynomials
                for(int poly_degree = 3; poly_degree <= 11; poly_degree+= 2)
                {
                    colourindex++;

                    sine = taylor_sin_rad(radians, poly_degree);

                    if(sine <= maxsin && sine >= (maxsin * -1))
                    {
                        y = yzero - (sine * pixels_per_unit_y);

                        svg_circle(psvg, colours[colourindex], 0, colours[colourindex], 3, x, y);
                    }
                }

                x += pixels_per_unit_x * step;
            }

            taylor_free();
        }

        svg_finalize(psvg);

        svg_save(psvg, filename);

        puts("File saved");

        svg_free(psvg);
    }
}

I have written large amounts of code over the years in various languages to create graphs of one kind or another. I always end up with many variable for sizes, positions and scaling factors, and this one is no different. It's probably best to ignore their declarations and initializations and just deal with them as and when they are used.

Firstly we need to create an svg struct, as described in the SVG Library post. The rest of the function basically calls functions from this library to add the various components of the graphic.

The basic framework is added first: the header, axes, indexes and numeric labels, followed by the key. The code to draw the key iterates the array of colours, drawing a circle in each colour as well as its description. Note the use of sprintf to populate a string from a number, which is then passed to the svg_text function.

We then start to use the Taylor Polynomials library to plot various sine waves. We call taylor_init and if this is successful enter a for loop from 0° to the maximum degrees. The function has a step argument so we do not cram the graph with a value for each degree, especially important with higher values of maxdegrees. We then call the C library's sin function (using radians rather than degrees), then calculate the position of the circle to draw for this value. We then call svg_circle to plot the value.

Next we enter a for loop to plot the Taylor Polynomial calculated sines from degree 3 to 11. Having checked the result isn't outside the requested maximum values we calculate the position of and draw a circle in the same way as with the sin() values. Note we increment colourindex in the loop so we cycle through the colours.

At the end of the outer loop we call taylor_free, as it uses dynamic memory. We then call svg_finalize to add the closing tag, and then svg_save. The SVG library also uses malloc and realloc so again the memory needs to be freed.

We can now write the main function which as you can see is very simple, just a few calls to the taylor_sin_plot function.

main.c

#include<stdio.h>

#include"taylorseriesplot.h"

//--------------------------------------------------------
// FUNCTION main
//--------------------------------------------------------
void main(void)
{
    puts("----------------------------------------------------\n| code-in-c.com - Taylor Series Trigonometric Plot |\n----------------------------------------------------\n");

    taylor_sin_plot(2, 360, 8, 1440, 800, "tsp.svg");

    taylor_sin_plot(2, 360, 4, 720, 400, "1.svg");
    taylor_sin_plot(4, 720, 8, 720, 400, "2.svg");
}

Compile and Run

That's the coding finished so we can compile and run the program with the following terminal commands.

Compile and run

gcc main.c taylorseries.c taylorseriesplot.c memoizationfactorials.c svg.c -std=c11 -lm -o main

./main

The output is pretty boring but if you open the folder where your code is you'll find three .svg files have been created, including the two shown at the top of the page. If you double click them they should open with your default image viewer.

Program Output

----------------------------------------------------
| code-in-c.com - Taylor Series Trigonometric Plot |
----------------------------------------------------

File saved
File saved
File saved

You might want to play around with the arguments to "zoom in" or "zoom out" or to create larger images.

Please let me have any comments or suggestions you may have, and follow Code in C on Twitter to keep up with future posts.

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *