Graph of data points larger than the horizontal resolution of LCD.. - Page 1
Forum section: electronics / general

author: Siddharth
author_rank: Newbie
timestamp: April 05, 2018, 06:31:39 pm
content: Hi, I am working on an project in which I have to draw the graph of large data (2048 horizontal points) on a 7" TFT LCD display. The data is coming from a spectrometer. I have a horizontal resolution of 800 pixels on the LCD. So I am little bit confused about how to display all the data at once on the screen without loosing any critical information like peaks in the graph. I tried down sampling the graph to fit on the screen by plotting every 3rd data point and leaving the remaining points?. But this has created a problem that sometimes few narrow peaks are not visible on the graph. I have seen applications like LabView draw the same graph on same LCD with much clearer details, no matter how much you shrink the area(obviously with some limit there). I don't know how they are doing this in Labview! I am using STM32F407 and a waveshare 7" TFT LCD with 800 x 480 resolution. I know libraries like stemwin can do this task without much effort but this particular topic seems to be very interesting to me that I decided to do this from scratch using the LCD's drawing functions. Also I have tried to display all the data points by displaying 3 data points on a single column but this also didn't work for me as the graph started looking a bit weird with serpentine rising edges and square peaks...I don't know why this is happening? maybe I am doing something wrong. I have plenty of time with this project so I am willing to do this task without any libraries...Just for some fun... Please share with me the actual method of doing this to get beautiful graphs....

author: asmi
author_rank: Super Contributor
timestamp: April 05, 2018, 06:58:24 pm
content: It depends on the nature of data and your goal. In some cases you can display an average of several data points, but this will smooth the graph and will not display actual peak values. If preserving peaks is important, a minimum (or maximum) value among data points being merged can be displayed. The choice of algorithm for data compression depends on your requirements.

author: pelule
author_rank: Frequent Contributor
timestamp: April 05, 2018, 10:31:28 pm
content: There is a simple solution is to calculate the horizontal position (x-disp) with a factor kx.Example:Data: x-data(max) = 2048, x-data(min) = 0TFT: x-tft(max) = 800, x-tft(min) = 0dx-data = x-data(max) - x-data(min) = 2048dx-tft = x-tft(max) - x-tft(min) = 800kx = dx-tft / dx-data = 0,390625Calculate horizontal position on the TFT:x-tft(x) = x-data(x) * kxExample: at position 1024x-data(x) = 1024x-tft(x) = 1024 * 0,390625 = 400So one can calculate each display position for any data position./PeLuLe

author: David Chamberlain
author_rank: Frequent Contributor
timestamp: April 06, 2018, 10:07:59 am
content: ULTRA, INFINIIVISION, SUPER PHOSPHOR ... just some of the marketing names attached to the methods cleaver engineers came up with to solve the same problems your having, consider they are working with many megabytes of memory depth + display updates and must make a decision as to what the user wants to see in the data and display it on a screen of limited resolution.If you have an array of data points along the x axes (as pelule has said) then x_target = floor(x_source * (800 / 2048));Given you are wanting to show max peek values I would just run a loop from 0 to 2047 on the above equation and draw a vertical line. Some results will overlap but the high peek will not get overwritten on the display for a single pass if that makes sense?

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 06, 2018, 01:35:07 pm
content: Only drawing one vertical line with min and max y value for all the points that lie on the same destination (display) x (integer) is enough. You don't need to use all the points that lie on the same x.Whether the end result will be visually satisfying really depends on the data itself, but at least you won't miss peaks.Just averaging the points lying on the same x gives aliasing problems.

author: Siddharth
author_rank: Newbie
timestamp: April 06, 2018, 02:16:06 pm
content: Thanks, I will try this. But since I have to scale the y-axis too according to the vertical resolution of the display, some of the points which are close in values comes in same row and form almost a straight line in the graph which makes some peaks look a little bit square in shape, which doesn't looks nice. The idea should work best for the data having y-axis values within the vertical pixel resolution of the graph area but, for scaled down y-axis data the results are not so good.

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 06, 2018, 02:54:36 pm
content: If your display allows it (either grayscale or RGB), you can try modifying pixel luminance depending on how far the point would lie from the exact integer position (the furthest away, the darkest). I think that's what a lot of digital oscilloscopes do. It will probably look a lot more "natural" but will require more processing.

author: Nominal Animal
author_rank: Super Contributor
timestamp: April 06, 2018, 03:58:51 pm
content: Because 2048/800 = 64/25, each set of 64 samples encodes 25 pixel columns. If you use an intensity buffer of 25×480 bytes (12000 bytes), you can fully antialiase the data display.Because 25/64 = 100/256, each sample is worth 25 intensity units out of 64, and each sample is 100/256 = 0.390625 pixels wide.Something like the following pseudo-C code should work:Code:static const uint16_t colormap = { /* Color codes for 65 intensities, from dark to bright, optionally followed by 191 overlay colors */ };/* Data buffer, assume floating-point for now */float sample;/* Intensity cache, used only during update */unsigned char intensity;/* Helper function */static inline void intensity_add(const unsigned char *column, const int yfrom, const int yto, const unsigned char value){int y;if (yfrom <= yto) {for (y = yfrom; y <= yto; y++)column += value;} else {for (y = yto; y <= yfrom; y++)column += value;}}/* Helper function */static inline int ylimit(const float value){if (value <= 0.0f)return 0;elseif (value >= 479.0f)return 479;elsereturn (int)(value + 0.5f);}/* Display samples, scaling min to max to fit in display */void update_display(const float min, const float max){const float offset = min;const float scale = 479.0f / (max - min);int curr, prev, b, i, x, y, xf;curr = ylimit(479.0f - scale * (sample - offset));/* Loop over groups of 25-pixels/64-samples */for (b = 0; b < 32; b++) {/* Clear intensity cache */memset(intensity, 0, sizeof intensity);x = 0; /* Pixel x coordinate within the block */xf = 0; /* Fractional x coordinate within pixel, 0..63 */for (i = 0; i < 64; i++) {prev = curr;curr = ylimit(479.0f - scale * (sample[b*64 + i] - offset));if (xf <= 38) { /* 64-25 = 38 */intensity_add(&(intensity), prev, curr, 25);xf += 25;} else {intensity_add(&(intensity), prev, curr, 64 - xf);x += 1;xf -= 38;intensity_add(&(intensity), prev, curr, xf);}}/* Optional: If you have an overlay over the data,add the overlay for pixel columns (b*25) to (b*25+24)to intensity[][] here.*//* Send intensity cache to display, in column-major order. */for (x = 0; x < 25; x++) {/* We'll send 480 pixels, for column (b*25 + x). */for (y = 0; y < 480; y++)display_send_color(colortable[intensity]);}}}If the intensity cache (12000 bytes) is too large, it is possible to do the same using just one 480-byte array. You just move the final loop over display_send_color() (or whatever you use to send a 16-bit color code to the display) to just before the x += 1; statement.I've attached examples of how a curve and the same curve drawn as bar graph (prev always 479) drawn thus would look like, in grayscale.

author: Siddharth
author_rank: Newbie
timestamp: April 06, 2018, 04:51:12 pm
content: Thanks for your code. The idea seems very interesting to add anti-aliasing to the graph.. Definitely will improve the looks. I am going to try this out once I get the proper plotting of the data done.. I will upload the results afterwards.

author: David Chamberlain
author_rank: Frequent Contributor
timestamp: April 06, 2018, 09:04:56 pm
content: BTW i was talking about the vertical scale thing in this post.https://www.eevblog.com/forum/microcontrollers/data-logging-and-graphing-data-on-a-tft-display/msg1423319/