Hi,

Ik ben weer met een kleine schakeling bezig die waarschijnlijk wat filtering kan gebruiken voro wat sensoren.

Hardbass had een tijd terug een filterclass voor mij geschreven maar ik heb er nu al twee keer naar gezocht op CO en hier in mijn Arduino code.
Dus Hardbass, of iemand anders die me hier mee kan helpen de code hier nog ene keer te laten zien.

Mijn dank is groot!
Bram

Hi Rob W.

Yep dat is hem, dank je! ;)

Groet,
Bram

Hi,

Ik zal wel weer stekenblind zijn en het is niet de drank... :+

Stukje code waarmee ik op het ogenblik test en dit betreft ondermeer het Filter Class.
Ik krijg een melding als ik het goed begrijp dat ik niets niet goed heb aangegeven en dat zal ook wel maar er vallen hier geen kwartjes *grin*

De code:


#include <Adafruit_ADS1X15.h>
#include <PID_v1.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Extra font voor het display
//#include <Fonts/FreeSans9pt7b.h>
// *Extra font voor het display


Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */

// -------------------------------------------------------------------------
//  Filter Classsetup
// -------------------------------------------------------------------------
template <class T>
class Filter 
{
public:
  int N = 0;                                                                          // Aantal te middelen waarde
  float *meetwaardes;                                                                 // Opslag individuele meetwaarden
  float accumulator = 0;                                                              // Optelsom van alle individuele meetwaarden
  int index = 0;                                                                      // Meetwaarden teller

  Filter(const int n)
  {
    meetwaardes = new float[n];
    N = n;
    for(int i = 0; i < n; i++)
    {  
      meetwaardes[i] = 0;
    }
  }

  ~Filter()
  {
    delete[] meetwaardes;
  }

  void AddSample(float NewSample)
  {  
    accumulator -= meetwaardes[index];        
    meetwaardes[index] = NewSample;                                                   // Bewaar nieuwe meetwaarde
    accumulator += meetwaardes[index];                                                // Accumuleer nieuwste meetwaarde
    index++; 
    index %= N;                                                                       // Teller loopt van 0 tot N-1
  }

  float Average()
  {  
    return accumulator/N;                                                             // Bereken de gemmiddelde waarde
  }
};


// Variabelen voor corectiewaarden van temperatuur sensoren
// int corr_pid_float = 0;
// int corr_ref_float = 0;



//=====================================================================
//=====================================================================
void setup(void)
{
  Serial.begin(9600);
  Serial.println("Hello!");

  Wire.begin();
  Wire.setClock(4000000);                                              // Set de i2c bus op 400KHz werkfrequentie

// Setup ads1115 ADC
ads.setGain(GAIN_FOUR);                                               // 4x gain   +/- 1.024V  1 bit = 0.5mV    0.03125mV
ads.setDataRate(3);                                                   // DATA RATE ADS1115


  if (!ads.begin()) {
    Serial.println("Failed to initialize ADS.");
    while (1);
  }

// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

// Configuration averaging for the ADC inputs
Filter<float> Filter_TMP37_1(32);
Filter<float> Filter_TMP37_2(16); 

}


//=====================================================================
//=====================================================================
void loop(void)
{
   display.clearDisplay();
 
int16_t adc0, adc1;

//Temperatuur van de TMP37_1
	float sample_TMP37_1 = (float)analogRead(A0);
	float TMP37_1_Celcius = sample_TMP37_1 * (1.025/32768 / 0.02);	

//Temperatuur van de TMP37_2


//Samples toevoegen aan het filter.
	Filter_TMP37_1.AddSample(TMP37_1_Celcius);


	//Uitlezen resultaat filters.
	float avg_TMP37_1_Celcius = Filter_TMP37_1.Average();

 // text display tests
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(20,20);
  display.println(avg_TMP37_1_Celcius);
  
  display.setCursor(20,40);
 // display.println(xxxx);
  
  display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
  
  display.display();
  
  delay(10);
}


En dit zijn de error meldingen:
C:\Users\xxxxx\Documents\Arduino\Buis-Oven\Buis-Oven-01\Buis-Oven-02.ino\Buis-Oven-02.ino.ino: In function 'void loop()':
C:\Users\xxxxx\Documents\Arduino\Buis-Oven\Buis-Oven-01\Buis-Oven-02.ino\Buis-Oven-02.ino.ino:122:2: error: 'Filter_TMP37_1' was not declared in this scope
Filter_TMP37_1.AddSample(TMP37_1_Celcius);
^~~~~~~~~~~~~~
C:\Users\xxxxx\Documents\Arduino\Buis-Oven\Buis-Oven-01\Buis-Oven-02.ino\Buis-Oven-02.ino.ino:122:2: note: suggested alternative: 'sample_TMP37_1'
Filter_TMP37_1.AddSample(TMP37_1_Celcius);
^~~~~~~~~~~~~~
sample_TMP37_1
Multiple libraries were found for "Adafruit_SSD1306.h"
Used: C:\Users\xxxxx\Documents\Arduino\libraries\Adafruit_SSD1306
Not used: C:\Users\xxxxx\Documents\Arduino\libraries\Adafruit_SSD1306_Wemos_Mini_OLED
exit status 1

Compilation error: 'Filter_TMP37_1' was not declared in this scope

Wie helpt mij met mijn blinde vlek!

Dank en groet,
Bram

De regel Filter<float> Filter_TMP37_1(32); in functie setup() moet je verhuizen naar een plekkie bovenin de functie loop()

Hi 575, :-)

De error is nu weg als ik de variabelen bovenin plaats, dank daarvoor, maar ik heb nog meer vergissingen/fouten in mijn code.

Het toevoegen en uitlezen van de waarden van de filter class gaat niet goed, de enige regel die ik op het display plaats, geeft nog onzin aan.

Nog even verder frutten...

Groet,
Bram

Hi,

Rare waarden kreeg ik, dus nog voldoende fouten waarvan ik kan leren...

Dus weer de code in stukjes gehakt om te kijken waar een aantal zaken mis gaan.
Dat heeft nu werkende TMP37 temeratuur sensor code opgelevert.

Met deze nu werkende code ga ik de sample tijd en de filtermiddeling testen zodat het optimaal wordt.


#include <Adafruit_ADS1X15.h>
#include <PID_v1.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Extra font voor het display
#include <Fonts/FreeSans9pt7b.h>
// *Extra font voor het display


Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */

//-------------------------------------------------------------------------
// Filter Classsetup
//-------------------------------------------------------------------------
template <class T>
class Filter 
{
public:
  int N = 0;                                                                          // Aantal te middelen waarde
  float *meetwaardes;                                                                 // Opslag individuele meetwaarden
  float accumulator = 0;                                                              // Optelsom van alle individuele meetwaarden
  int index = 0;                                                                      // Meetwaarden teller

  Filter(const int n)
  {
    meetwaardes = new float[n];
    N = n;
    for(int i = 0; i < n; i++)
    {  
      meetwaardes[i] = 0;
    }
  }

  ~Filter()
  {
    delete[] meetwaardes;
  }

  void AddSample(float NewSample)
  {  
    accumulator -= meetwaardes[index];        
    meetwaardes[index] = NewSample;                                                   // Bewaar nieuwe meetwaarde
    accumulator += meetwaardes[index];                                                // Accumuleer nieuwste meetwaarde
    index++; 
    index %= N;                                                                       // Teller loopt van 0 tot N-1
  }

  float Average()
  {  
    return accumulator/N;                                                             // Bereken de gemmiddelde waarde
  }
};


// // Variabelen voor corectiewaarden van temperatuur sensoren
// // int corr_pid_float = 0;
// // int corr_ref_float = 0;

// // Configuration averaging for the ADC inputs
Filter<float> Filter_TMP37_1(8);
Filter<float> Filter_TMP37_2(8); 



//=====================================================================
//=====================================================================
void setup(void)
{
  Serial.begin(9600);
  Serial.println("Hello!");

  Wire.begin();
  Wire.setClock(4000000);                                              // Set de i2c bus op 400KHz werkfrequentie

// Setup ads1115 ADC
ads.setGain(GAIN_FOUR);                                               // 4x gain   +/- 1.024V  1 bit = 0.5mV    0.03125mV
ads.setDataRate(4);                                                   // DATA RATE ADS1115


  if (!ads.begin()) {
    Serial.println("Failed to initialize ADS.");
    while (1);
  }

// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }


}





//=====================================================================
//=====================================================================
void loop(void)
{
   display.clearDisplay();
 
int16_t adc0, adc1;

  adc0 = ads.readADC_SingleEnded(0);                                     // Get value PID sensor input
  adc1 = ads.readADC_SingleEnded(1);                                     // Get value reference sensor input 



//Temperatuur van de TMP37_1
//	float sample_TMP37_1 = (float)analogRead(A0);
	float TMP37_1_Celcius = adc0 * (1.025/32768 / 0.02);	

//Temperatuur van de TMP37_2


//Samples toevoegen aan het filter.
	Filter_TMP37_1.AddSample(TMP37_1_Celcius);


	//Uitlezen resultaat filters.
 float avg_TMP37_1_Celcius = Filter_TMP37_1.Average();

   display.println();
 
 
 
 // text display tests
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(20,20);
 // display.println(TMP37_1_Celcius);
  
  display.setCursor(20,40);
 display.println(avg_TMP37_1_Celcius, 4);
  
  display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
  
  display.display();
  
  delay(1000);
}

Mooi nu eerst zo snurken en morgen verder :-)

Groet,
Bram

Ha, leuk dat je deze nog steeds toepast.

Er zijn wel een paar dingen die verbeterd moeten worden, met name in verband met embedded. Bijvoorbeeld de template heeft zo geen zin. Ik heb wat aangepast om de boel robuster te maken. Je kunt hem zo gebruiken!



template <size_t N>
class Filter
{
    static_assert(N > 0, "Filter size N must be greater than zero");

private:
    float measurements[N]{};
    float accumulator = 0.0f;
    size_t index = 0;

public:
    Filter() = default;

    // Prevent accidental expensive copies
    Filter(const Filter&) = delete;
    Filter& operator=(const Filter&) = delete;

    // Moves are fine (still effectively copies, but intentional)
    Filter(Filter&&) = default;
    Filter& operator=(Filter&&) = default;

    void AddSample(float sample)
    {
        accumulator -= measurements[index];
        measurements[index] = sample;
        accumulator += sample;

        index++;
        if (index >= N)
            index = 0;
    }

    float Average() const
    {
        return accumulator / static_cast<float>(N);
    }

    void Reset()
    {
        for (size_t i = 0; i < N; ++i)
            measurements[i] = 0.0f;

        accumulator = 0.0f;
        index = 0;
    }
};


void Example()
{

    Filter<5> filter_5;
    filter_5.AddSample(10.0f);
    filter_5.AddSample(20.0f);
    filter_5.AddSample(30.0f);
    float avg = filter_5.Average();
    printf("Average of last 5 samples: %.2f\n", avg);

    Filter<3> filter_3;
    filter_3.AddSample(5.0f);
    filter_3.AddSample(15.0f);
    float avg3 = filter_3.Average();
    printf("Average of last 3 samples: %.5f\n", avg3);
}

Met wat hulp van AI een lijstje van alle verbeterpunten.

  • Geen dynamische geheugenallocatie meer
    • Geen new / delete
    • Geen heap-fragmentatie
    • Betrouwbaar voor lang draaiende embedded software
  • Compile-time vaste filtergrootte
    • N is een templateparameter
    • Geheugengebruik is vooraf bekend
    • Compiler kan beter optimaliseren
  • Templateparameter wordt daadwerkelijk gebruikt
    • Filter<8> en Filter<16> zijn echt verschillende types
    • Geen misleidende of overbodige template-constructie
  • Veiligheidscontrole op filtergrootte
    • static_assert(N > 0)
    • Fouten worden tijdens compilatie ontdekt
    • Geen runtime checks nodig
  • Encapsulatie verbeterd
    • Interne variabelen zijn private
    • Externe code kan interne toestand niet beschadigen
    • Klasse-invariant blijft intact
  • Duidelijke en minimale publieke interface
    • AddSample() voor toevoegen van metingen
    • Average() voor uitlezen van het gemiddelde
    • Reset() voor herinitialisatie
  • Const-correctheid toegepast
    • Average() is const
    • Veilig aan te roepen op const Filter
    • Verbetert correctheid en leesbaarheid
  • Correct typegebruik voor indexering
    • size_t gebruikt voor index
    • Semantisch correct voor array-indexen
    • Voorkomt signed/unsigned waarschuwingen
  • Voorkomen van onbedoeld kopiëren
    • Copy constructor en copy assignment zijn delete
    • Voorkomt dure of verwarrende kopieën
    • Belangrijk in embedded context
  • Move-semantiek expliciet toegestaan
    • Verplaatsen is toegestaan
    • Ontwerpintentie blijft duidelijk
  • Deterministisch en voorspelbaar gedrag
    • Constante uitvoeringstijd (O(1) per sample)
    • Geen verborgen allocaties of zij-effecten
    • Geschikt voor real-time toepassingen
  • Reset-functionaliteit toegevoegd
    • Filter kan veilig opnieuw gebruikt worden
    • Geen herconstructie nodig
    • Interne toestand wordt volledig hersteld
  • Embedded-vriendelijk ontwerp
    • Geen exceptions
    • Geen RTTI
    • Geen dynamisch geheugen
    • Geschikt voor Arduino, ESP32, STM32, enz.

[Bericht gewijzigd door hardbass op (41%)]

Hi hardbass, :-)

Leuk dat je nog meedenkt, maar je begrijpt hopelijk wel dat mij dyslectische brein jouw voorbeeld niet echt grok...

Kan je een voorbeeld geven voor analoge ingang 0 en 1
En b.v. voor analoge ingang-1 een filtering van 32x
En b.v. voor analoge ingang-2 een filter waarde van 8x
Op die manier met een simpel voorbeeld kan ik de werking beter toepassen.

Kan je de onderstaande regel uitleggen.
Mijn aanname, filter nummer 5 sample toevoegen en dan wat is (10.0f)
Wat doet b.v. die f daar achter de nul?
Waarom drie regels voor filter nummer-5?

filter_5.AddSample(10.0f);

Verder natuurlijk... wat is het gedrag van het filter?
Ik neem aan niet direct een simpele middeling zeg 50 metingen optellen en door 50 delen.

Onderdrukt het b.v. een enkele uitschieter en gaat gewoon verder?
Als er b.v. snelle verandering optreed voor een reeks pulsen gaat de waarde dan snel naar het gemiddelde neiuwe waarde toe?

Oja, wat ik nu gisterenavond werkend kreeg, 0,00001C resolutie uit een TMP37 sensor,
zie je mooi rustig veranderen als de schakeling in een piepschuimen doosje is ingebouwd.
Die hoge resolutie is voor nu alleen om er aan te meten, dit om de trend en ruisonderdrukking te zien wat ik nog een beetje verder moet analyseren en aaapassen.

Code voor een aantal kleine oventjes met een referentie zener.
Dit projectje is waar ik een jaar of vier geleden mee gestopt ben en nu weer heb opgepakt.
Maar waar ik deze week tegenaan ben gelopen waarom van alles niet werkt is eigenelijk te gek voor woorden.
Je code uploaden en dat steeds commport error geven, staat achter de hoofd interface van de Arduino interface de serieele output open.
Maar je ziet niet onderaan in het venster waar je ziet of er errors zijn en de upload klaar is dat er een tab van de serial open staat!
Als je meerdere stukjes code open hebt staan wordt het nog leuker...

Mijn i2c display stopt met werken als er 1 foutje in een Println("") commando zit, dus een lege regel toevoegen.
De aanhalings tekens plaatsen en geen display init meer..
Aanhalings tekens weghalen, display werkt weer.
De Compiler zegt dus niets he, alles is TOPPY! Grrrrr.
Als ik dan de meldingen open zet wordt er verklaart dat hij het display niet kan opstarten, schiet mij maar lek.

En ik heb nog een hele lijst met dit soort zaken, zoveel dingen die niet werken waarbij je denkt dit zou de software moeten oplossen.
Ga je compilen en uploaden, sluit dan automatisch de commpoort voor de de code upload.

En natuurlijk mijn taal blindheid, vooral in de avond, blind paard ben ik dan. *grin*

Groet,
Bram

Hoi Bram,

Hier een simpel voorbeeld. Het leest 2 ADC ingangen (ADS1115 kanaal 0 en 1), rekent ze om naar TMP37 temperatuur en doet daarna een moving-average filtering.
- ingang 0 -> Filter<32> (veel demping, reageert langzaam)
- ingang 1 -> Filter<8> (minder demping, reageert sneller)


// 2 filters: kanaal 0 sterk (32), kanaal 1 minder sterk (8)
Filter<32> filter_ch0;
Filter<8>  filter_ch1;

float AdcValueToTemperature(float adcValue)
{
    return adcValue * (1.025/32768 / 0.02);	
}

float ReadTemperatureC(int input)
{
    int16_t rawAdc = ads.readADC_SingleEnded(input);    // Read the raw value from the ADC
    return AdcValueToTemperature(rawAdc);               // Convert it to temperature
}

void setup()
{
    // Hier jou setup code
}

void loop()
{
    // 1) Meten (ongefilterd)
    float temp_ch0_raw = ReadTemperatureC(0);
    float temp_ch1_raw = ReadTemperatureC(1);

    // 2) Meting aan filter toevoegen
    filter_ch0.AddSample(temp_ch0_raw);
    filter_ch1.AddSample(temp_ch1_raw);

    // 3) Gemiddelde (gefilterde waarde) ophalen
    float temp_ch0_avg = filter_ch0.Average();
    float temp_ch1_avg = filter_ch1.Average();

    // 4) Printen voor test (hier kun je ook je display update doen)
    Serial.print("CH0 raw=");
    Serial.print(temp_ch0_raw, 4);
    Serial.print("  avg(32)=");
    Serial.print(temp_ch0_avg, 4);

    Serial.print("    CH1 raw=");
    Serial.print(temp_ch1_raw, 4);
    Serial.print("  avg(8)=");
    Serial.println(temp_ch1_avg, 4);

    delay(1000);
}

Uitleg `filter_5.AddSample(10.0f);`

- AddSample(...) betekent: "voeg 1 nieuwe meting toe aan het filter"
- 10.0f is de samplewaarde (hier gewoon een voorbeeld-getal)

Waarom die 'f'?
- 10.0 is in C/C++ een double
- 10.0f is een float
Op Arduino is float meestal wat je wil (sneller/kleiner), dus daarom vaak met 'f'.

Waarom meerdere regels achter elkaar in een voorbeeld?
- Dat is gewoon om te laten zien dat je meerdere metingen na elkaar toevoegt
In de praktijk voeg je er per loop() meestal 1 toe.

Gedrag van dit filter (moving average):
- Het onthoudt de laatste N metingen (N = 32 of 8)
- Een enkele uitschieter wordt "uitgesmeerd" over N samples en verdwijnt weer
- Hoe groter N, hoe rustiger maar hoe trager bij snelle veranderingen

Let op: met deze versie van het filter start de buffer met nullen. Daardoor “loopt” de gemiddelde waarde in de eerste N loops rustig naar de echte waarde toe. Na N metingen is het een echt lopend gemiddelde over de laatste N samples.

Als je dit draait zie je in de serial output meteen: raw vs avg(32) en raw vs avg(8).
Dan kun je direct zien wat het filter doet. Mocht je er niet uitkomen kan ik een complete file maken die je in zijn geheel kan kopieren.

Ohja, ik zou je aanraden om de hele filter code in een andere file te stoppen. Dan zit dat niet heel de tijd op je scherm als je bezig bent.

Bram,
Als je snel wil reageren bij grote temperatuur sprongen dan zou je de filter-class van hardbass als volgt kunnen aanpassen. Bij temperatuurverschil groter dan 0.5 C springt tie direkt naar de nieuwe waarde, en gaat dan weer verder met middelen. Je kan die 0.5 natuurlijk naar wens aanpassen.
(PS:code is niet getest)

template <size_t N>
class Filter
{
    static_assert(N > 0, "Filter size N must be greater than zero");

private:
    float measurements[N]{};
    float accumulator = 0.0f;
    float bigJump = 0.5f;
    size_t index = 0;

public:
    Filter() = default;

    // Prevent accidental expensive copies
    Filter(const Filter&) = delete;
    Filter& operator=(const Filter&) = delete;

    // Moves are fine (still effectively copies, but intentional)
    Filter(Filter&&) = default;
    Filter& operator=(Filter&&) = default;

    void AddSample(float sample)
    {
		if(abs(sample - Average()) > bigJump)
		{
			Preset(sample);
		}	
		else
		{	
			accumulator -= measurements[index];
			measurements[index] = sample;
			accumulator += sample;

			index++;
			if (index >= N)
				index = 0;
		}
    }

    float Average() const
    {
        return accumulator / static_cast<float>(N);
    }

    void Reset()
    {
        for (size_t i = 0; i < N; ++i)
            measurements[i] = 0.0f;

        accumulator = 0.0f;
        index = 0;
    }

    void Preset(float sample)
    {
        for (size_t i = 0; i < N; ++i)
            measurements[i] = sample;

        accumulator = N * sample;
        index = 0;
    }	

};

[Bericht gewijzigd door Jeroen op (0%)]

Een hele simpele filter die heel weinig extra RAM nodig heeft is een FIR filter : hier is er maar een extra float nodig, onafhankelijk van het aantal samples dat je gebruikt voor een "moving average". Hier een voorbeeld om 10 waardes uit te middelen :
float Gemiddelde, Nieuw_sample;
Nieuw_sample = ADC_meting;
Gemiddelde = Nieuw_sample*0.1 + Gemiddelde*0.9;

Meer is het niet. Opgelet, je krijjgt geen perfect rekenkundig gemiddelde van de laatste 10 waardes, maar het is een prima benadering. Ook moet je met floats rekenen.

Waarom zou je een piek op die manier willen doorlaten? Het hele idee van een filter is toch juist om dat soort dingen te onderdrukken.

Ik krijg er wel weer een grappig idee van, als je een interface maakt kan je heel veel verschillende filters makkelijk uitwisselen in je code. Ik heb nog ergens een DPS bordje liggen. Wel grappig om eens mee te spelen.



struct Filter
{
    virtual float next(float value) = 0;
};

template<int N>
struct AverageFilter : public Filter
{
};

template<int ORDER> // nth order low pass filter
struct LowPassFilter : public Filter
{
    void Init(int cutoffFrequency, int sampleRate);
};

// Somehow inject the polynomial coefficients
template<int COOFICIENTS> // nth order
struct IIRFilter : public Filter
{
    void Init(float* aCoefficients, float* bCoefficients, int order);
};

struct DpsController
{
    Filter& filter;
    AnalogInput& input;
    AnalogOutput& output;

    DpsController(Filter& filt, AnalogInput& in, AnalogOutput& out)
        : filter(filt), input(in), output(out)
    {
    }

    void tick()
    {
        float sample = input.read();
        float filtered = filter.next(sample);
        output.write(filtered);
    }
};

// ----------------------
// Start of arduino code
// ----------------------
AnalogInput input;
AnalogOutput output;

LowPassFilter lowPass;
AverageFilter<8> avg;

// This now ties the input to the output through the low pass filter
DpsController controller(lowPass, input, output);

void loop()
{
    controller.tick();
}


Hi Heren, :-)

Voorlopig hou ik het even bij wat ik nu werkend heb, er zijn nog voldoende zaken die ik moet uitzoeken.
hardbass, misschien kan je een eigen topic maken met voorbeelden hoe je je filter kan gaan inzetten?

Waar ik tegenaan loop is het volgende vanavond...
Een aantal van mijn Pro mini's zijn niet wat ze lijken te zijn...
Ik heb gelukkig een 8MHz 3.3V model gevonden, misschien heb ik er nog meer, zoek daar later naar.
Mooi dan heb ik een 3.3V model 8MHz en dan blijkt de lineaire regelaar die dan 3.3V zou moeten maken vanaf 11V extra veel stroom te trekken...
Duidelijk geen echte MIC5205 van Microchip welke 16V aan kan.

Niet een heel groot probleem, ik had vanavond al een LF33CV op een breadboardje staan die zuinig is en goed werkt.
Kost alleen weer ruimte op het controller printje.
Om een indruk te krijgen van waar ik mee bezig ben hieronder twee foto's.

De eerste foto laad de oven te zien, onder de blauwe blop bevindt zich een TMP37, dit was eerst de oven-sensor maar krijgt nu een andere functie.
Deze functie is beveiliging als er iets mis gaat met de oven controller, de TPM37F komt aan de regelingang van een TLV431 dat is een 1,25V versie van de TL431 dus al comparator. :-)

Los liggen twee 5K NTC's die in een brug schakeling komen, hier liggen ze nog los, komende maandag komt mijn nieuw setje tubes thermische lijm binnen.
Het gene wat ik nog heb staan in twee potjes is keihard geworden, daar heb ik uiteindelijk voor die 70 Euro weinig aan gehad, nog geen 10% van gebruikt...
Maar goed niet jammeren, nieuwe lijm komt eraan in een kleinere verpakking en een betere thermische weerstand dan de blauwe WLK30 lijm

Zoals ik de NTC heb neergelegd, komen ze ongeveer in de oven, één meer aan de achterzijde en de andere aan de voorzijde en dan 180 graden uit elkaar.
Voor het plaatje ging dat nu even niet, maar later zal ik laten zien wat ik bedoel.

https://www.bramcam.nl/Buis-Oven/Buis-Oven-01.png
.

Er komt een dubbel printje dat precies zo gemaakt is dat hij in het midden van de oven vast blijf zitten.
Een kant voor de microcontroler en wat rand elektronica en de andere print voor de referentie elektronica.
https://www.bramcam.nl/Buis-Oven/Buis-Oven-03.png
.

Dit is het voedingsdeel van de elektronica en de aansturing van de twee NTC's die ik net heb laten zien.
Op de referentie print plak ik ook een NTC en die doet niets voor de regeling, maar meet wel de temperatuur vlak bij de referentie Zener.
Op het display kan ik dan zien als de oven zelf stabiel is, of het referentie deel ook al op tempratuur is, gewoon omdat het kan. :-)
De aansluiting voor deze NTC staat nog niet in dit schema.

https://www.bramcam.nl/Buis-Oven/Buis-Oven-02.png
.

Beetje uitleg...
12V is nodig voor de ovenwikkeling en deze wordt aan de ingang ontkoppeld door R8 R7 en de condensatoren C6 en C2.
De LF33CV wordt dus gebruikt omdat de regelaar op de Pro mini niet tegen 12V kan.
De NTC brug wordt gevoed uit een mooie AD7801 waar ik er nog een paar van heb liggen, deze is hier geconfigureerd voor 3V uitgang spanning, dit d.m.v. een jumper.
De onderdrukking van variaties op de ingang spanning is heel erg goed van 5 naar 13V ingang spanning blijft de laatste digit onveranderd op een 6,5 digit meter.
Dit geld natuurlijk wel voor een bepaalde bandbreedte, het DC signaal aan de ingang is voor hogere frequenties al reeds gefilterd met R7 en C2 en
ik denk C2 naar 47uF te brengen dan is het kantelpunt 34Hz en kan de Elco klein blijven.

Met de gekozen 3V voor de Brug en de NTC instel weerstanden heb ik een hoge brug uitgangspanning.
De instel weerstanden lijken een vreemde waarde te hebben van 2K54, maar daar heb ik er nog een aantal van liggen en zijn van zeer hoge kwaliteit.
En ze passen mooi bij de 5K NTC's als ik 42C oventemperatuur aan hou, de NTC-waarde is dan ook rond de 2,5K dus maximale uitgang spanning in dat gebied.
C1 van 1uF helpt stoorsignalen te verminderen.

De oven wikkeling van weerstanddraad is bifilair gewikkeld, dus dat geeft al weinig in de oven buis.
De MOSFet die de oven wikkeling gaat aansturen krijgt aan de Gate een netwerkje om de steile flanken weg te halen, want dat is het gene wat storing kan veroorzaken.
Dit staat ook nog niet op het schema hierboven wat trouwens de eerste opzet is.

Om even op de NTC brug terug te komen, hoe ga ik dat behandelen in de code, hieronder wat ik wel vaker gebruik, hoe pas is dit aan voor de symmetrische brug?
Deze code is voor een enkele NTC met een pull up weerstand, hoe doe je dat met het schema dat ik wil toepassen?

NTC Gegevens

// Thermistor Eigenschappen Vishay NTCLE300E3502SB
#define RT0 5000                                                     // NTC weerstand bij 25C
#define B   3977                                                     // K
#define VCC 3.000                                                    // Referentie Spanning van de brug
#define R   2540.00                                                  // Weerstand naar de referentie spanning voor de NTC in Ohm
#define T0  (25 + 273.15)                                            // Temperature T0 from datasheet, conversion from Celsius to kelvin fot the NTC Sensor

Berekening


  // Temperatuur van de NTC
  float sample_NTC_RAW = (float)analogRead(A8);
  float VRT = 2.4985 * sample_NTC_RAW / 65536.00; 
  float VR = VCC - VRT;
  float RT = VRT * R / VR; 
  float ln = log(RT / RT0);
  float TX = (1 / ((ln / B) + (1 / T0)));                                        
  float sample_NTC_Celcius = TX - 273.15;

Dank alvast weer voor de input, dit wordt gewaardeerd. ;)

Groet,
Bram