Perancangan dan Implementasi Low Pass Filter Digital Dengan ESP32

Implementasi filter digital dengan ESP32, MCP3008 dan level converter

Perancangan dan Implementasi Low Pass Filter Digital Dengan ESP32

Perancangan Filter

Perancangan filter menggunakan tools dari https://fiiir.com/

Parameter yang digunakan:

  • Sampling rate: 20000 Hz
  • Cut off frequency 800 Hz
  • Transition bandwidth 1800 Hz
  • Window type : Blackman

Berikut ini karakteristik filter yang dapat dilihat di laman yang sama

Kode dalam bahasa Python untuk menghitung parameter filter dan konvolusinya juga dihasilkan dari laman yang sama, sebagai berikut:

from __future__ import print_function
from __future__ import division

import numpy as np

# Example code, computes the coefficients of a low-pass windowed-sinc filter.

# Configuration.
fS = 20000 # Sampling rate.
fL = 800 # Cutoff frequency.
N = 53 # Filter length, must be odd.

# Compute sinc filter.
h = np.sinc(2 * fL / fS * (np.arange(N) - (N - 1) / 2))

# Apply window.
h *= np.blackman(N)

# Normalize to get unity gain.
h /= np.sum(h)

print(h)

# Applying the filter to a signal s can be as simple as writing
# s = np.convolve(s, h)

Parameter filter yang dihasilkan adalah sebagai berikut  (sebagai Python array)

[-4.29317419e-20 -4.18549678e-21 -1.79819385e-05 -8.38178513e-05
 -2.28616892e-04 -4.79528638e-04 -8.51847897e-04 -1.33864303e-03
 -1.89910369e-03 -2.44776137e-03 -2.84740649e-03 -2.90866942e-03
 -2.39870072e-03 -1.06016948e-03  1.35995551e-03  5.07437980e-03
  1.02166209e-02  1.68050560e-02  2.47160945e-02  3.36720917e-02
  4.32479500e-02  5.28978134e-02  6.20002342e-02  6.99171799e-02
  7.60597872e-02  7.99523091e-02  8.12855501e-02  7.99523091e-02
  7.60597872e-02  6.99171799e-02  6.20002342e-02  5.28978134e-02
  4.32479500e-02  3.36720917e-02  2.47160945e-02  1.68050560e-02
  1.02166209e-02  5.07437980e-03  1.35995551e-03 -1.06016948e-03
 -2.39870072e-03 -2.90866942e-03 -2.84740649e-03 -2.44776137e-03
 -1.89910369e-03 -1.33864303e-03 -8.51847897e-04 -4.79528638e-04
 -2.28616892e-04 -8.38178513e-05 -1.79819385e-05 -4.18549678e-21
 -4.29317419e-20]

Simulasi dengan Python di Desktop

Berikut ini kode untuk simulasi filter tersebut di Jupyter Notebook dengan bahasa Python.

from __future__ import print_function
from __future__ import division

import numpy as np
import math
import matplotlib.pyplot as plt

# Example code, computes the coefficients of a low-pass windowed-sinc filter.

# Configuration.
fS = 20000 # Sampling rate.
fL = 800 # Cutoff frequency.
N = 53 # Filter length, must be odd.

# Compute sinc filter.
h = np.sinc(2 * fL / fS * (np.arange(N) - (N - 1) / 2))

# Apply window.
h *= np.blackman(N)

# Normalize to get unity gain.
h /= np.sum(h)

print(h)

# Applying the filter to a signal s can be as simple as writing
# s = np.convolve(s, h)

x = np.linspace(0,1, 20001)

# filter digital
signal_frequency=8000 # diubah-ubah sesuai keperluan
y=np.sin(x*2*math.pi * signal_frequency)
# Applying the filter to a signal s can be as simple as writing
y_out = np.convolve(y, h)
plt.figure(figsize=(16,6))
plt.plot(x, y_out[0:20001],label="output")
plt.plot(x, y[0:20001],label="input")
plt.title("signal:{} Hz".format(signal_frequency))
plt.legend()
plt.axis('tight')
plt.xlim([0, 0.01])
plt.savefig("simulasi-signal-{}.jpg".format(signal_frequency))

Hasil simulasi untuk frekuensi 8 Hz

Hasil simulasi untuk frekuensi 80 HzHasil simulasi untuk frekuensi 800 Hz

Hasil simulasi untuk frekuensi 8000 Hz

Simulasi dengan C di Desktop

Pada percobaan ini filter disimulasikan di Desktop PC untuk mengecek ketepatan perhitungan dibandingkan dengan versi Python.

Kode untuk simulasi C sebagai berikut:

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

int main()
{

#define ORDE_FILTER 53
int i,j,k;
FILE * fp;
char filename[100];
printf("Hello world!\n");
// simulasi 1 detik saja

float signal_frequency=8; // frekuensi input signal
float filter_coefficients[]= {-4.29317419e-20, -4.18549678e-21, -1.79819385e-05, -8.38178513e-05,
-2.28616892e-04, -4.79528638e-04, -8.51847897e-04, -1.33864303e-03,
-1.89910369e-03, -2.44776137e-03, -2.84740649e-03, -2.90866942e-03,
-2.39870072e-03, -1.06016948e-03, 1.35995551e-03, 5.07437980e-03,
1.02166209e-02, 1.68050560e-02, 2.47160945e-02, 3.36720917e-02,
4.32479500e-02, 5.28978134e-02, 6.20002342e-02, 6.99171799e-02,
7.60597872e-02, 7.99523091e-02, 8.12855501e-02, 7.99523091e-02,
7.60597872e-02, 6.99171799e-02, 6.20002342e-02, 5.28978134e-02,
4.32479500e-02, 3.36720917e-02, 2.47160945e-02, 1.68050560e-02,
1.02166209e-02, 5.07437980e-03, 1.35995551e-03, -1.06016948e-03,
-2.39870072e-03, -2.90866942e-03, -2.84740649e-03, -2.44776137e-03,
-1.89910369e-03, -1.33864303e-03, -8.51847897e-04, -4.79528638e-04,
-2.28616892e-04, -8.38178513e-05, -1.79819385e-05, -4.18549678e-21,
-4.29317419e-20
};
int orde_filter=ORDE_FILTER;
float y_history[ORDE_FILTER];
signal_frequency=8000;
sprintf(filename,"simulasi-%d.csv",(int)signal_frequency);
fp = fopen (filename, "w");
fprintf(fp,"time,y,y_out\n");

// zeros y_history
for (i=0; i<orde_filter; i++)
{
y_history[i]=0;
}
for (i=0; i<20000; i++)
{
printf(".");
float t,y;
t=(float)i/(float)20000; // time axis
y=sin(2 * M_PI *signal_frequency* t);
// fprintf(fp,"%f,%f\n",t,y);

// hitung history signal
for (j=orde_filter-1; j>=1; j--)
{
int src=j-1;
int dst=j;
y_history[dst]=y_history[src];
// printf("%d %d\n",src,dst);
}
y_history[0]=y;

// hitung konvolusi
float y_out=0;
for (k=0; k<orde_filter; k++)
{
// fprintf(fp,"%5.3f ",y_history[k]);
y_out=y_out+y_history[k]*filter_coefficients[k];
}
// fprintf(fp,"\n");
fprintf(fp,"%f,%f,%f\n",t,y,y_out);
}
fclose(fp);
return 0;
}



// https://www.tutorialspoint.com/c_standard_library/c_function_fprintf.htm

Output kode C tersebut berupa file *.csv

Visualisasi data di file *.csv dilakukan menggunakan Jupyter Notebook dengan kode sebagai berikut:

import pandas as pd
import math
import matplotlib.pyplot as plt

name="simulasi-8"
name="simulasi-80"
name="simulasi-800"
name="simulasi-8000"
df = pd.read_csv('../filter-simulasi-c/{}.csv'.format(name))

plt.figure(figsize=(16,6))
plt.plot(df["time"], df["y"],marker='o',label="input")
plt.plot(df["time"], df["y_out"],marker='o',label="output")
plt.legend()
plt.axis('tight')
plt.xlim([0, 0.001])
plt.savefig("visualisasi-{}.jpg".format(name))

Tampilan Visualisasi untuk sinyal 8 Hz

nampak sinyal 8 Hz tidak teredam

Tampilan Visualisasi untuk sinyal 80 Hz

sinyal 80 Hz nampak teredam sedikit sekali dan ada lag

Tampilan Visualisasi untuk sinyal 800 Hz

nampak sinyal 800 Hz teredam sekitar 50%

Tampilan Visualisasi untuk sinyal 8000 Hz

nampak sinyal 8000 Hz teredam hampir semuanya

Simulasi dengan C di ESP32

pada percobaan ini kode dijalankan di ESP32 namun input adalah simulasi bukan dari generator sinyal. Output direkam ke port serial, bukan ke osiloskop.

Kode ESP32 adalah sebagai berikut

#define ORDE_FILTER 53

void setup() {

  Serial.begin(115200);

  //

  int i, j, k;

  char filename[100];

  // simulasi 1 detik saja

  float signal_frequency = 8;  // frekuensi input signal

  float filter_coefficients[] = { -4.29317419e-20, -4.18549678e-21, -1.79819385e-05, -8.38178513e-05,

                                  -2.28616892e-04, -4.79528638e-04, -8.51847897e-04, -1.33864303e-03,

                                  -1.89910369e-03, -2.44776137e-03, -2.84740649e-03, -2.90866942e-03,

                                  -2.39870072e-03, -1.06016948e-03, 1.35995551e-03, 5.07437980e-03,

                                  1.02166209e-02, 1.68050560e-02, 2.47160945e-02, 3.36720917e-02,

                                  4.32479500e-02, 5.28978134e-02, 6.20002342e-02, 6.99171799e-02,

                                  7.60597872e-02, 7.99523091e-02, 8.12855501e-02, 7.99523091e-02,

                                  7.60597872e-02, 6.99171799e-02, 6.20002342e-02, 5.28978134e-02,

                                  4.32479500e-02, 3.36720917e-02, 2.47160945e-02, 1.68050560e-02,

                                  1.02166209e-02, 5.07437980e-03, 1.35995551e-03, -1.06016948e-03,

                                  -2.39870072e-03, -2.90866942e-03, -2.84740649e-03, -2.44776137e-03,

                                  -1.89910369e-03, -1.33864303e-03, -8.51847897e-04, -4.79528638e-04,

                                  -2.28616892e-04, -8.38178513e-05, -1.79819385e-05, -4.18549678e-21,

                                  -4.29317419e-20 };

  int orde_filter = ORDE_FILTER;

  float y_history[ORDE_FILTER];

  signal_frequency = 800;

//  signal_frequency = 80;

//  signal_frequency = 8;

  sprintf(filename, "simulasi-%d.csv", (int)signal_frequency);

  printf("time,y,y_out\n");

  // zeros y_history

  for (i = 0; i < orde_filter; i++) {

    y_history[i] = 0;

  }

  for (i = 0; i < 20000; i++) {

    float t, y;

    t = (float)i / (float)20000;  //  time axis

    y = sin(2 * M_PI * signal_frequency * t);

    //        fprintf(fp,"%f,%f\n",t,y);

    // hitung history signal

    for (j = orde_filter - 1; j >= 1; j--) {

      int src = j - 1;

      int dst = j;

      y_history[dst] = y_history[src];

      //            printf("%d %d\n",src,dst);

    }
  y_history[0] = y;
    // hitung konvolusi
    float y_out = 0;
    for (k = 0; k < orde_filter; k++) {
      y_out = y_out + y_history[k] * filter_coefficients[k];
    }

    //        fprintf(fp,"\n");

    printf("%f,%f,%f\n", t, y, y_out);

  }

}

void loop() {

  // put your main code here, to run repeatedly:

}

Output dari ESP32 direkam dengan software RealTerm ke sebuah file *.txt

File *.txt tersebut dirapikan dan disimpan sebagai *.csv

File *.csv ini kemudian divisualisasikan dengan Jupyter Notebook

Kode visualisasi sebagai berikut

# graph simulasi C filter
import pandas as pd
import math
import matplotlib.pyplot as plt

name="esp32-8.csv"
name="esp32-80.csv"
#name="esp32-800.csv"
#name="esp32-8000.csv"
df = pd.read_csv('{}'.format(name))

plt.figure(figsize=(16,6))
plt.plot(df["time"], df["y"],label="input")
plt.plot(df["time"], df["y_out"],label="output")
plt.legend()
plt.axis('tight')
plt.xlim([0, 0.1])
plt.title(name)
plt.savefig("visualisasi-{}.jpg".format(name))

Sinyal 8 Hz:

Sinyal 80 Hz

Sinyal 800 Hz

Sinyal 8000 Hz

Kesimpulan: output dari software LPF di ESP32 sama dengan output dari software C di Desktop

Profiling di ESP32

Pada percobaan ini waktu yang diperlukan untuk menghitung filter diukur di ESP32.

Pewaktuan menggunakan fungsi millis(). Fungsi millis() tidak 100% akurat. Untuk lebih tepat perlu interupsi timer, atau dengan osiloskop.

Kode profiling:

#define ORDE_FILTER 53
float buffer[100];
void setup() {
  int buffer_index = 0;
  int durasi;
  Serial.begin(115200);
  //
  long int i;
  int j, k;
  char filename[100];
  // simulasi 1 detik saja

  float signal_frequency = 8;  // frekuensi input signal
  float filter_coefficients[] = { -4.29317419e-20, -4.18549678e-21, -1.79819385e-05, -8.38178513e-05,
                                  -2.28616892e-04, -4.79528638e-04, -8.51847897e-04, -1.33864303e-03,
                                  -1.89910369e-03, -2.44776137e-03, -2.84740649e-03, -2.90866942e-03,
                                  -2.39870072e-03, -1.06016948e-03, 1.35995551e-03, 5.07437980e-03,
                                  1.02166209e-02, 1.68050560e-02, 2.47160945e-02, 3.36720917e-02,
                                  4.32479500e-02, 5.28978134e-02, 6.20002342e-02, 6.99171799e-02,
                                  7.60597872e-02, 7.99523091e-02, 8.12855501e-02, 7.99523091e-02,
                                  7.60597872e-02, 6.99171799e-02, 6.20002342e-02, 5.28978134e-02,
                                  4.32479500e-02, 3.36720917e-02, 2.47160945e-02, 1.68050560e-02,
                                  1.02166209e-02, 5.07437980e-03, 1.35995551e-03, -1.06016948e-03,
                                  -2.39870072e-03, -2.90866942e-03, -2.84740649e-03, -2.44776137e-03,
                                  -1.89910369e-03, -1.33864303e-03, -8.51847897e-04, -4.79528638e-04,
                                  -2.28616892e-04, -8.38178513e-05, -1.79819385e-05, -4.18549678e-21,
                                  -4.29317419e-20 };
  int orde_filter = ORDE_FILTER;
  float y_history[ORDE_FILTER];
  signal_frequency = 800;
  //  signal_frequency = 80;
  //  signal_frequency = 8;
  printf(“time,y,y_out\n”);

  // zeros y_history
  for (i = 0; i < orde_filter; i++) {
    y_history[i] = 0;
  }
  int time_start = millis();

  for (i = 0; i < 1000000L; i++) {
    float t, y;
    t = (float)i / (float)20000;  //  time axis
    y = sin(2 * M_PI * signal_frequency * t);
    //        fprintf(fp,”%f,%f\n”,t,y);

    // hitung history signal
    for (j = orde_filter – 1; j >= 1; j–) {
      int src = j – 1;
      int dst = j;
      y_history[dst] = y_history[src];
      //            printf(“%d %d\n”,src,dst);
    }
    y_history[0] = y;

    // hitung konvolusi
    float y_out = 0;
    for (k = 0; k < orde_filter; k++) {
      y_out = y_out + y_history[k] * filter_coefficients[k];
    }
    //        fprintf(fp,”\n”);
    //    Serial.print(“.”);
    buffer[buffer_index] = y_out;
    buffer_index++;
    if (buffer_index>100){
      buffer_index=0;
    }
  }
  int time_end = millis();
  durasi = time_end – time_start;
  Serial.println(“durasi”);
  Serial.println(durasi);
}

void loop() {
  // put your main code here, to run repeatedly:
}

Hasil profiling: kode memerlukan 16479 ms untuk menjalankan 1000000 kali perhitungan. jadi setiap perhitungan memerlukan 16.479 us

Konversi DAC di ESP32 memerlukan sekitar 20 us (pesimis), jadi jika kode sekuensial maka didapatkan perioda 36.479 us, atau frekuensi = 27413 Hz.

Frekuensi filter yang dirancang adalah 20000 Hz, jadi masih di bawah batas 27413 Hz.

Pengujian Dengan Sinyal Sesungguhnya

Pada percobaan ini kode dijalankan di ESP32 dengan input dari generator sinyal dan output diamati di osiloskop

Berikut ini implementasi rangkaian:

Implementasi filter digital dengan ESP32, MCP3008 dan level converter
Implementasi filter digital dengan ESP32, MCP3008 dan level converter

Implementasi software dapat dilihat di https://github.com/waskita/embedded/tree/master/esp32_mcp3008_baker_adc_dac_filter-timer

Sinual input didapat dari  generator sinyal GW Instek AFG-2012

Pengukuran output menggunakan osiloskop GW Instek-1152A-U

Berikut ini pengukuran pada frekuensi cut off = 100 Hz jauh di bawah frekuensi cut off.

Berikut ini pengukuran pada frekuensi cut off = 800 Hz. Amplitudo sinyal output sekitar 50% sinyal input.

Berikut ini pengukuran pada frekuensi 1600 Hz, jauh di atas cut off. Amplitudo sinyal output kecil sekali hampir tidak ada.

Berikut ini pengukuran pada frekuensi input 19200 Hz. Terjadi aliasing karena pada sistem ini tidak ada filter anti aliasing.

Referensi

Tinggalkan Balasan

Situs ini menggunakan Akismet untuk mengurangi spam. Pelajari bagaimana data komentar Anda diproses.