I am using CODESYS to plot an array of voltage values in an XY chart in the visualization. The voltage values are updated every second, but I am encountering an issue where the XY chart connects the most recent value to (0,0), causing a line to appear between the current value and the origin. This line is not desired and makes the plot look incorrect. I tried to initialize the array with 5, the effect is, that the line unwanted lie is drawn to (0,5) instead of (0,0)
How can I fix this?
Here is my code:
PROGRAM PLC_PRG
VAR
// *** Constants and Parameters ***
Max_Samples : INT := 20; // Maximum number of samples to be collected
// *** ADC Input Reading ***
ADC_1 : INT; // Raw ADC value from the input
// *** Data Storage Arrays ***
arr_Voltages : ARRAY[0..20] OF REAL; // Array initialized with NaN (Not-a-Number) values
arr_Time : ARRAY[0..20] OF INT; // Array to store time-related sample indices
// *** Timer and Counters ***
Sample_Timer : TON; // Timer instance for sampling intervals (TON type)
Sample_Time : TIME := T#1s; // Sampling interval duration (1 second)
sample_index : INT := 0; // Current index for writing data into arrays
start_Timing : BOOL; // Control signal to start or stop the timer
i : INT; // General counter variable
// *** Web Visualization Variables ***
start_Measurement : BOOL := FALSE; // Control flag for starting the measurement process
reset_Visu : BOOL := FALSE; // Control flag for resetting the visualization
status_LED : BOOL := FALSE; // Status indicator (e.g., for LED on the Web Visu)
END_VAR
// Timer configuration: The timer is controlled by 'start_Timing' and runs for 'Sample_Time'.
Sample_Timer(IN := start_Timing, PT := Sample_Time); // Timer runs with a duration of 1 second.
IF start_Measurement THEN // Check if measurement should start.
start_Timing := TRUE; // Activate the timer to begin the sampling process.
status_LED := TRUE;
END_IF
IF Sample_Timer.Q THEN // Check if the timer has completed (Q = TRUE indicates the timer is done).
start_Timing := FALSE; // Stop the timer to reset its state.
Sample_Timer(IN := FALSE); // Explicitly reset the timer to prepare for the next interval.
IF sample_index <= Max_Samples THEN // Ensure the index is within the allowed range.
arr_Time[sample_index] := sample_index; // Store the current index as the timestamp.
arr_Voltages[sample_index] := get_Voltage(ADC_1); // Record the measured voltage from the ADC.
sample_index := sample_index + 1; // Increment the sample index for the next measurement.
ELSE
sample_index := 0; // Reset the sample index to the beginning.
start_Measurement := FALSE; // Stop the measurement process as the maximum samples are reached.
status_LED := FALSE;
END_IF
END_IF
IF reset_Visu THEN
// Reset all elements of arr_Time to 0
FOR i := 0 TO Max_Samples DO
arr_Time[i] := 0;
arr_Voltages[i] := 0.0; // Use 0.0 for REAL array elements
END_FOR
sample_index := 0; // Reset the sample index
END_IF
EDIT
Specific solution
I added a variable to plot the curve and added it to the Array Indexes Maximum.
plot_Index := sample_index-1;
The -1 adjustment was necessary because the first array index is 0 but the sample_index is incremented to 1. So without this, the unwanted line back to the origin would still be plotted.
Additionally, are arrays in Codesys automatically initialized to 0? I simply declared my array, and all values seem to default to 0. Thanks for the help.
The XY Chart doesn't require the data on X axis be ordered, in other words the line can go both right and left. Also, by default, the Chart takes all elements of your arrays and plots them. This means that, in your case, since all elements are initialized as zeroes, when the sample_index
is less than the array upper bound, there are [0,0]
elements at the end of the array, resulting in the chart plotting several points at the origin ([0,0]
).
To solve this, you need to tell the Chart which elements to plot. You can do this by specifying the start and end indexes:
In your case, the starting index would be fixed at 0, and the end index would increase as you add new samples to the array.
A possible solution:
PROGRAM PLC_PRG
VAR
...
sample_index : INT := 0; // Current index for writing data into arrays
plot_Index : INT := 0; // Current index of the last valid element
...
END_VAR
...
IF Sample_Timer.Q THEN
...
IF sample_index <= Max_Samples THEN
...
plot_Index := sample_index; // Set plot_Index to sample_index which is the index of the last written data
sample_index := sample_index + 1; // Increment the sample index for the next measurement.
ELSE
sample_index := 0; // Reset the sample index to the beginning.
plot_Index := Max_Samples;
...
END_IF
END_IF
IF reset_Visu THEN
...
sample_index := 0; // Reset the sample index
plot_Index := 0;
END_IF