I'm going to draw two graphs using potentiometer. I'm trying to get the same graph with the same shape even though it's 0.5 seconds behind the potentiometer's without using delay.
I think the problem is (void delayBox::calc(){}
). I tried to construct the code with mathematical formulas using the z-conversion and the Laplace transformation in (void delayBox::calc(){}
), but failed.
The code I tried is as follows. When i upload my Arduino kit and turn on Serial plotter, the potentiometer's graph is working but the delayed graph is not working. Please help it.
unsigned int data;
float sample_time = 0.01;
float delay_time = 0.5;
uint32_t start_Time;
uint32_t MicroSampleTime;;
class delayBox
{
public:
delayBox(float delay_time, float Ts);
~delayBox();
void calc();
public:
unsigned int *x, k, uk, yk;
};
delayBox *delayBox1;
void setup() {
Serial.begin(115200);
delayBox1 = new delayBox(0.3, sample_time);
MicroSampleTime = (uint32_t)(sample_time*1e6);
start_Time = micros() + MicroSampleTime;
}
void loop() {
data = analogRead(A0);
delayBox1->uk = (float)data;
delayBox1->calc();
Serial.print(data);
Serial.print(" ");
Serial.println(delayBox1->yk);
while(!(start_Time-micros()) & 0x80000000);
start_Time += MicroSampleTime;
}
**delayBox::delayBox(float delay_time,float Ts)
{
k = delay_time/Ts;
x = new int[k];
for(int i=0; i<k; i++)
{
x[i] = 0;
}
}
void delayBox::calc() // How can i construct here?
{
for(int i=0; i<k; i++)
{
x[i] = uk;
}
yk = x[k];
}**
delayBox::~delayBox()
{
}
Your calc()
function rewrites every element with the same current data. You need a circular buffer, where you take the oldest (delayed sample) and replace that with the new sample, and update the index to that of the next oldest sample.
It would be wise to encapsulate all the timing within delayBox
since your interface suggests that you may have multiple instances with different timing. For the same reason all that global and static data should be avoided. Moreover the floating point use is ill-advised and unnecessary.
For example:
class delayBox
{
public:
delayBox( unsigned delay_us, unsigned sample_interval_us ) ;
~delayBox();
bool update( int new_sample, int& delayed_sample ) ;
private :
unsigned m_sample_interval_us ;
unsigned m_delay_length ;
unsigned m_previous_sample_time ;
int* m_delay_buff ;
unsigned m_buff_idx ;
};
void setup()
{
Serial.begin(115200);
}
void loop()
{
static delayBox delayBox1( 300000u, 10000u ) ; // 0.3s delay, 0.01us sample interval
int data = analogRead(A0) ;
int delayed_data = 0 ;
// Update delay, output new and delayed sample at sample interval
if( delayBox1.update( data, delayed_data ) )
{
Serial.print( data ) ;
Serial.print( " " ) ;
Serial.println( delayed_data ) ;
}
// Do other stuff here
}
delayBox::delayBox( unsigned delay_us, unsigned sample_interval_us )
{
m_sample_interval_us = sample_interval_us ;
m_delay_length = delay_us / sample_interval_us ;
m_delay_buff = new int[m_delay_length] ;
memset( m_delay_buff, 0, m_delay_length ) ;
m_buff_idx = 0 ;
m_previous_sample_time = micros() ;
}
delayBox::~delayBox()
{
delete[] m_delay_buff ;
}
bool delayBox::update( int new_sample, int& delayed_sample )
{
bool delayed_sample_valid = micros() - m_previous_sample_time >= m_sample_interval_us ;
// After sample interval...
if( delayed_sample_valid )
{
// Timestamp sample
m_previous_sample_time += m_sample_interval_us ;
// Get oldest, replace with newest, update index
delayed_sample = m_delay_buff[m_buff_idx] ;
m_delay_buff[m_buff_idx] = new_sample ;
m_buff_idx = (m_buff_idx + 1) % m_delay_length ;
}
return delayed_sample_valid ;
}
Note that in this implementation the timing is handled in the class, the update()
function can be called more frequently than the desired sample rate, and produces a result at the sample interval, that leaves the loop()
free to perform other functions with different timing requirements without being impacted by the analogue sampling or delay processing. Note also that there is no global data - a concept that most Arduino Sketch examples seem to struggle with!
The use of dynamic memory allocation is also not really advised on very resource constrained Arduinos. You could avoid that by having a fixed buffer large enough for all instances, or use a class template perhaps.