15/03/2021 To 21/03/2021
1. Tuning amplifier circuit and reading drop signal
Amplified drop signal detecting by using PC based Oscilloscope
Signal at not dropping situation
Original drop signal with drop detection pulse detect from Atmega328p microcontroller serial output
2. Arduino Filter Codes
Moving Average Filter code
float RealTimeData[200] = {0};
float SmoothedData[200] = {0};
float Filter_Order = 15.0;
void setup() {
Serial.begin(9600);
}
void loop() {
Moving_Average_Filter(RealTimeData,Filter_Order,200);
}
void Moving_Average_Filter(float* Input,float Order,int filter_range){
for (int r=0;r<filter_range;r++){
float avg=0;
for (int j=0;j<Order;j++){
if (r-j>=0){
avg = avg+ Input[r-j];
}
}
SmoothedData[r] = avg/Order;
}
}
Derivative Filter Code
float RealTimeData[200] = {0};
float SmoothedData[200] = {0};
float DerivativedData[200] = {0};
float Filter_Order = 15.0;
void setup() {
Serial.begin(9600);
}
void loop() {
// How to call Derivative Filter
Derivative_Filter(SmoothedData,DerivativedData,199);
}
void Derivative_Filter(float* X,float* D,int filter_range){
for(int i=0;i<filter_range;i++){
D[i] = X[i+1]-X[i];
}
}
Savitzky golay filter codes
3. Data Processing Code
#include <SoftwareSerial.h>
int Window_Size = 100;
int Interval =100;
SoftwareSerial WebServer(2, 3);
String wifi_send="";
int Person_ID= 1;
float avgdropvolume = 0.0257;
float Urine_Volume = 0.0;
float RealTimeData[200] = {0};
float SmoothedData[200] = {0};
float DerivativedData[200] = {0};
int Buffer_Count = 1;
int Buffer_Mode =1;
int Process_front_end = 50;
int reverse_interval = 50;
int Process_back_end = 200-reverse_interval;
float Filter_Order = 15.0;
long int No_Sample = 1;
float Input;
int Peak_Count =0;
int k=0;
float threshold=450.0;
float Current_peak_location = 0.0;
float Past_peak_location = 0.0;
float Peak_Time_Gap = 0.0;
float Flow_rate = 0.0;
void setup() {
Serial.begin(9600);
}
void loop() {
// Calling Data Processing Functions one by one
}
void Push(float InputRead){
for (int i=1; i< 200; i++){
RealTimeData[i-1] = RealTimeData[i];
}
RealTimeData[199] = InputRead;
No_Sample += 1;
}
void Moving_Average_Filter(float* Input,float Order,int filter_range){
for (int r=0;r<filter_range;r++){
float avg=0;
for (int j=0;j<Order;j++){
if (r-j>=0){
avg = avg+ Input[r-j];
}
}
SmoothedData[r] = avg/Order;
}
}
void Derivative_Filter(float* X,float* D,int filter_range){
for(int i=0;i<filter_range;i++){
D[i] = X[i+1]-X[i];
}
}
void Data_Processing(){
Moving_Average_Filter(RealTimeData,Filter_Order,200);
Derivative_Filter(SmoothedData,DerivativedData,199);
Clear_SmoothData_Array();
Moving_Average_Filter(DerivativedData,Filter_Order,199);
Clear_Derivative_Array();
Derivative_Filter(SmoothedData,DerivativedData,198);
Clear_SmoothData_Array();
Moving_Average_Filter(DerivativedData,Filter_Order,198);
Peak_Detecting(SmoothedData);
}
void Clear_SmoothData_Array(){
for(int i=0;i<200;i++){
SmoothedData[i] = 0;
}
}
void Clear_Derivative_Array(){
for(int i=0;i<200;i++){
DerivativedData[i] = 0;
}
}
void Peak_Detecting(float* Input_Array){
for (int i=Process_front_end;i<Process_back_end;i++){
if (k!=1){
if(Input_Array[i] > threshold){
k= 1;
}
}
if(k==1){
if(Input_Array[i] < 425){
Peak_Count += 1;
k=0;
Current_peak_location = (i+1)*0.01;
Peak_Time_Gap = Current_peak_location - Past_peak_location;
Past_peak_location = Current_peak_location;
Urine_Volume = Urine_Volume+ avgdropvolume;
Flow_rate = (avgdropvolume)/(Peak_Time_Gap/3600.0);
wifi_send = "*" + String(Person_ID)+ "," + String(Peak_Count) + "," + String(Peak_Time_Gap) + "," + String(Urine_Volume)+ "," + String(Flow_rate) + "," + "#";
}
}
}
}
4. Data Processing Code (With buffer array)
#include <SoftwareSerial.h>
int Window_Size = 100;
int Interval =100;
SoftwareSerial WebServer(2, 3);
String wifi_send="";
int Person_ID= 1;
float avgdropvolume = 0.0257;
float Urine_Volume = 0.0;
float RealTimeData[200] = {0};
float SmoothedData[200] = {0};
float DerivativedData[10] = {0};
//float Buffer1[100] = {0};
//float Buffer2[100] = {0};
int Buffer_Count = 1;
int Buffer_Mode =1;
int Process_front_end = 50;
int reverse_interval = 50;
int Process_back_end = 200-reverse_interval;
float Filter_Order = 15.0;
long int No_Sample = 1;
float Input;
int Peak_Count =0;
int k=0;
float threshold=450.0;
float Current_peak_location = 0.0;
float Past_peak_location = 0.0;
float Peak_Time_Gap = 0.0;
float Flow_rate = 0.0;
void setup() {
Serial.begin(9600);
WebServer.begin(115200);
}
void loop() {
if ((No_Sample % Interval)== 0){
if (No_Sample == Interval ){
RealTimeData[99] = analogRead(A0);
delay(10);
No_Sample += 1;
}
else if (No_Sample == 200 ){
//// {{ The First Task
RealTimeData[199] = analogRead(A0);
No_Sample += 1;
//Process 1
Data_Processing();
//// }}
//// {{ The second Task
for (int t=0;t<100;t++){
// Buffer1[t] = analogRead(A0);
delay(10);
No_Sample += 1;
}
Buffer_Mode =2;
//// }}
}
else {
Input = analogRead(A0);
Push(Input);
//Processing Part 2
Data_Processing();
}
}
else{
if (No_Sample < 200){
RealTimeData[No_Sample-1] = analogRead(A0);
delay(10);
No_Sample += 1;
}
else {
Input = analogRead(A0);
Push(Input);
}
}
}
void Push(float InputRead){
for (int i=1; i< 200; i++){
RealTimeData[i-1] = RealTimeData[i];
}
RealTimeData[199] = InputRead;
No_Sample += 1;
}
void Moving_Average_Filter(float* Input,float Order,int filter_range){
for (int r=0;r<filter_range;r++){
float avg=0;
for (int j=0;j<Order;j++){
if (r-j>=0){
avg = avg+ Input[r-j];
}
}
SmoothedData[r] = avg/Order;
}
}
void Derivative_Filter(float* X,float* D,int filter_range){
for(int i=0;i<filter_range;i++){
D[i] = X[i+1]-X[i];
}
}
void Data_Processing(){
Moving_Average_Filter(RealTimeData,Filter_Order,200);
Derivative_Filter(SmoothedData,DerivativedData,199);
Clear_SmoothData_Array();
Moving_Average_Filter(DerivativedData,Filter_Order,199);
Clear_Derivative_Array();
Derivative_Filter(SmoothedData,DerivativedData,198);
Clear_SmoothData_Array();
Moving_Average_Filter(DerivativedData,Filter_Order,198);
Peak_Detecting(SmoothedData);
}
void Clear_SmoothData_Array(){
for(int i=0;i<200;i++){
SmoothedData[i] = 0;
}
}
void Clear_Derivative_Array(){
for(int i=0;i<200;i++){
DerivativedData[i] = 0;
}
}
void Peak_Detecting(float* Input_Array){
for (int i=Process_front_end;i<Process_back_end;i++){
if (k!=1){
if(Input_Array[i] > threshold){
k= 1;
}
}
if(k==1){
if(Input_Array[i] < 425){
Peak_Count += 1;
k=0;
Current_peak_location = (i+1)*0.01;
Peak_Time_Gap = Current_peak_location - Past_peak_location;
Past_peak_location = Current_peak_location;
Urine_Volume = Urine_Volume+ avgdropvolume;
Flow_rate = (avgdropvolume)/(Peak_Time_Gap/3600.0);
wifi_send = "*" + String(Person_ID)+ "," + String(Peak_Count) + "," + String(Peak_Time_Gap) + "," + String(Urine_Volume)+ "," + String(Flow_rate) + "," + "#";
}
}
}
}
5. Arduino libraries
6. FreeRTOS
Most operating systems appear to allow multiple programs or threads to execute at the same time. This is called multi-tasking. In reality, each processor core can only be running a single program at any given point in time. A part of the operating system called the scheduler is responsible for deciding which program to run when, and provides the illusion of simultaneous execution by rapidly switching between each program.
The scheduler in a Real Time Operating System (RTOS) is designed to provide a predictable (normally described as deterministic) execution pattern. This is particularly interesting for embedded systems, like the Arduino devices, as embedded systems often have real time requirements.
Traditional real time schedulers, such as the scheduler used in FreeRTOS, achieve determinism by allowing the user to assign a priority to each thread of execution. The scheduler then uses the priority to know which thread of execution to run next. In FreeRTOS, a thread of execution is called a Task.
FreeRTOS Library
FeerRTOS Sample code
#include <Arduino_FreeRTOS.h>
// define two tasks for Blink & AnalogRead
void TaskBlink( void *pvParameters );
void TaskAnalogRead( void *pvParameters );
// the setup function runs once when you press reset or power the board
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards.
}
// Now set up two tasks to run independently.
xTaskCreate(
TaskBlink
, "Blink" // A name just for humans
, 128 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL
, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL );
xTaskCreate(
TaskAnalogRead
, "AnalogRead"
, 128 // Stack size
, NULL
, 1 // Priority
, NULL );
// Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}
void loop()
{
// Empty. Things are done in Tasks.
}
/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/
void TaskBlink(void *pvParameters) // This is a task.
{
(void) pvParameters;
/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.
Most Arduinos have an on-board LED you can control. On the UNO, LEONARDO, MEGA, and ZERO
it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN takes care
of use the correct LED pin whatever is the board used.
The MICRO does not have a LED_BUILTIN available. For the MICRO board please substitute
the LED_BUILTIN definition with either LED_BUILTIN_RX or LED_BUILTIN_TX.
e.g. pinMode(LED_BUILTIN_RX, OUTPUT); etc.
If you want to know what pin the on-board LED is connected to on your Arduino model, check
the Technical Specs of your board at https://www.arduino.cc/en/Main/Products
This example code is in the public domain.
modified 8 May 2014
by Scott Fitzgerald
modified 2 Sep 2016
by Arturo Guadalupi
*/
// initialize digital LED_BUILTIN on pin 13 as an output.
pinMode(LED_BUILTIN, OUTPUT);
for (;;) // A Task shall never return or exit.
{
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
}
}
void TaskAnalogRead(void *pvParameters) // This is a task.
{
(void) pvParameters;
/*
AnalogReadSerial
Reads an analog input on pin 0, prints the result to the serial monitor.
Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.
This example code is in the public domain.
*/
for (;;)
{
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
vTaskDelay(1); // one tick delay (15ms) in between reads for stability
}
}
FreeRTOS Tutorial