" base operand of '->' is not a pointer"

Hallo,

ich würde gerne einen Filter in den "normalen" Arduino Sketch implimentieren. Hier würde ich gerne folgenden nutzen:

struct butterworthFilter_t
{
  float v[2];
  float result;
};
void MAX30100::lowPassButterworthFilter( float x, butterworthFilter_t * filterResult )
{  
  filterResult->v[0] = filterResult->v[1];

  //Fs = 100Hz and Fc = 10Hz
  filterResult->v[1] = (2.452372752527856026e-1 * x) + (0.50952544949442879485 * filterResult->v[0]);

  //Fs = 100Hz and Fc = 4Hz
  //filterResult->v[1] = (1.367287359973195227e-1 * x) + (0.72654252800536101020 * filterResult->v[0]); //Very precise butterworth filter 

  filterResult->result = filterResult->v[0] + filterResult->v[1];
}

Meinen Sketch habe ich wie folgt aufgebaut:

/*!
 * @file basicRead.ino
 * @brief Output readings of red light and IR 
 * @n This library supports mainboards: ESP8266, FireBeetle-M0, UNO, ESP32, Leonardo, Mega2560
 * @copyright  Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
 * @licence     The MIT License (MIT)
 * @author [YeHangYu](hangyu.ye@dfrobot.com)
 * @version  V0.1
 * @date  2020-05-29
 * @url https://github.com/DFRobot/DFRobot_MAX30102
 */

#include <DFRobot_MAX30102.h>

 float x;
 float v[2];
 float result;
 float filterResult;
 float Filter_Wert;

DFRobot_MAX30102 particleSensor;

/*
Macro definition opions in sensor configuration 
sampleAverage: SAMPLEAVG_1 SAMPLEAVG_2 SAMPLEAVG_4 
               SAMPLEAVG_8 SAMPLEAVG_16 SAMPLEAVG_32
ledMode:       MODE_REDONLY  MODE_RED_IR  MODE_MULTILED
sampleRate:    PULSEWIDTH_69 PULSEWIDTH_118 PULSEWIDTH_215 PULSEWIDTH_411
pulseWidth:    SAMPLERATE_50 SAMPLERATE_100 SAMPLERATE_200 SAMPLERATE_400
               SAMPLERATE_800 SAMPLERATE_1000 SAMPLERATE_1600 SAMPLERATE_3200
adcRange:      ADCRANGE_2048 ADCRANGE_4096 ADCRANGE_8192 ADCRANGE_16384
*/
void setup()
{
  //Init serial 
  Serial.begin(115200);
  /*!
   *@brief Init sensor 
   *@param pWire IIC bus pointer object and construction device, can both pass or not pass parameters (Wire in default)
   *@param i2cAddr Chip IIC address (0x57 in default)
   *@return true or false
   */
  while (!particleSensor.begin()) {
    Serial.println("MAX30102 was not found");
    delay(1000);
  }

  /*!
   *@brief Use macro definition to configure sensor
   *@param ledBrightness LED brightness, default value: 0x1F(6.4mA), Range: 0~255(0=Off, 255=50mA)
   *@param sampleAverage Average multiple samples then draw once, reduce data throughput, default 4 samples average
   *@param ledMode LED mode, default to use red light and IR at the same time 
   *@param sampleRate Sampling rate, default 400 samples every second 
   *@param pulseWidth Pulse width: the longer the pulse width, the wider the detection range. Default to be Max range
   *@param adcRange Measurement Range, default 4096 (nA), 15.63(pA) per LSB
   */
  particleSensor.sensorConfiguration(/*ledBrightness=*/0x1F, /*sampleAverage=*/SAMPLEAVG_4, \
                                  /*ledMode=*/MODE_MULTILED, /*sampleRate=*/SAMPLERATE_400, \
                                  /*pulseWidth=*/PULSEWIDTH_411, /*adcRange=*/ADCRANGE_4096);
}

void loop()
{
  //Print result
  Serial.print("R=");
  /*!
   *@brief Get red value
   *@return Red light reading 
   */
  Serial.print(particleSensor.getRed());
  Serial.print(" IR=");
  /*!
   *@brief Get IR value 
   *@return IR reading 
   */
  Serial.print(particleSensor.getIR());
  Serial.println();
  delay(100);

  
  // Filter // 

  filterResult->v[0] = filterResult->v[1];

  //Fs = 100Hz and Fc = 10Hz
  filterResult->v[1] = (2.452372752527856026e-1 * x) + (0.50952544949442879485 * filterResult->v[0]);

  //Fs = 100Hz and Fc = 4Hz
  //filterResult->v[1] = (1.367287359973195227e-1 * x) + (0.72654252800536101020 * filterResult->v[0]); //Very precise butterworth filter 

  filterResult->result = filterResult->v[0] + filterResult->v[1];

  Filter_Wert = (v[2] + result)* filterResult;





}

Hier ist mir aber ein Fehler unterlaufen und ich bekomme folgende Fehlermeldung:

:\Users\emanu\AppData\Local\Temp.arduinoIDE-unsaved202333-19788-15329bg.c41kl\basicRead\basicRead.ino:83:36: error: base operand of '->' is not a pointer
filterResult->v[0] = filterResult->v[1];

Wenn ich das korrekt verstehe muss ich innerhalb einer structur (oder Funktion?) einen "pointer" verwenden wie bspw " .prev". Der Befehl -> weißt dann eine Funktion oder einen Wert einer anderen Variable zu, korrekt? Der ganze Code aus dem ich den Filter habe findet sich hier: xcoder123/MAX30100: Driver for MAX30100 using arduino (github.com)

Warum fängst Du für jedes Krümel einen neuen Thread an? Meinst Du, da bekommst Du mehr und bessere Antworten? Das gleiche Problem hast Du doch schon dort gepostet.

Gruß Tommy

Dachte es wäre übersichtlicher, aber ich kann auch alles in einem Thread "belassen".

Nein!

Ist Dein Google defekt?

Gruß Tommy

Auch wenn heutzutage Zeiger (pointer) auch in C++ gern vermieden werden, liefert new einen zurück und der -> operator braucht einen (das sagt die Fehlermeldung)

Fang erstmal mit c++ Grundlagen an, bevor du Feinheiten eines Butterworth- oder anderen Filters erforschst.

Das ist der Unterschied

Danke für deine Hilfe. Also ich hab schon eine Weile auf Google und YT geschaut und wenn ich das korrekt verstanden habe, dann müsste man Pfeile grundsätzlich so definieren:

int result = (int) malloc(sizeof(int));
int filterResult = (int) malloc(sizeof(int));

Ich bin da noch dabei das zu verstehen, hoffe es macht bald "Klick". ^^ Warum verwendet man denn Pfeile heute idR nicht mehr im C++?

Wenn ich einen Pfeil statt einer Variable definiert habe, dann bekomme ich (falls definiert wie oben) mittels:
filterResult = eine Speicheradresse
&filterResult = Speicheradresse von filterResult
*filterResult = den Wert von filterResult >> dieser muss aber zuvor gesetzt werden, korrekt?

Wenn ich nun in den Code schaue, dann wird filterResult hier gesetzt:

filterResult->v[1]

In meinen Fall ist das aber nun falsch, korrekt? Da ich auf "MAX30100::MAX30100" in der .h verweisen muss? Ich vermute es handelt sich hier um eine Funktion?

Suche ich nun in der Libary nach v[1]

finde ich:

MAX30100::MAX30100(
        Mode mode, 
        SamplingRate samplingRate, 
        LEDPulseWidth pulseWidth, 
        LEDCurrent IrLedCurrent,
        bool highResMode,
        bool debug)
{
  this->debug = debug;
  currentPulseDetectorState = PULSE_IDLE;

  setMode(  mode );

  //Check table 8 in datasheet on page 19. You can't just throw in sample rate and pulse width randomly. 100hz + 1600us is max for that resolution
  setSamplingRate( samplingRate );
  setLEDPulseWidth( pulseWidth );

  redLEDCurrent = (uint8_t)STARTING_RED_LED_CURRENT;
  lastREDLedCurrentCheck = 0;

  this->IrLedCurrent = IrLedCurrent;
  setLEDCurrents(redLEDCurrent, IrLedCurrent );
  setHighresModeEnabled(highResMode);


  dcFilterIR.w = 0;
  dcFilterIR.result = 0;

  dcFilterRed.w = 0;
  dcFilterRed.result = 0;


  lpbFilterIR.v[0] = 0;
  lpbFilterIR.v[1] = 0;
  lpbFilterIR.result = 0;

  meanDiffIR.index = 0;
  meanDiffIR.sum = 0;
  meanDiffIR.count = 0;


  valuesBPM[0] = 0;
  valuesBPMSum = 0;
  valuesBPMCount = 0;
  bpmIndex = 0;
  

  irACValueSqSum = 0;
  redACValueSqSum = 0;
  samplesRecorded = 0;
  pulsesDetected = 0;
  currentSaO2Value = 0;

  lastBeatThreshold = 0;

}

Fang erstmal mit c++ Grundlagen an, bevor du Feinheiten eines Butterworth- oder anderen Filters erforschst.

Das versuche ich ja gerade, vielleicht stelle ich mich auch ungeschickt an. Mein Programm (ohne Pfeile) funktioniert ja bereits, bis auf die Filter, leider fand ich gerade nur Filter mit den Pfeilen und muss das nun erstmal verstehen. :slight_smile:

Ich rate zu einem der schönen dicken C++ Bücher.

Was sind "Pfeile"?

Meinst du den -> Operator?
Einen solchen kannst du bauen wie und wann du willst.

Wo ist da eine Funktion?
Ich sehe da 2 Bezeichner, den Dereferenzierungsoperator, den ArrayAccessoperator und ein numerisches Literal.
Eine Funktion kann ich da auf Anhieb nicht erkennen.

filterResult->v[1]
// oder
(*filterResult).v[1]

Preisfrage:
Warum wirken die beiden (meistens) gleich?
Wann unterscheiden sie sich?

Sorry, das war wohl missverständlich.
In C++ gibt es Referenz, was man oft anstelle von Zeiger verwenden kann.

Aber eigentlich ist
objptr->elem
nur etwas bequemer zu schreiben als
(*objptr).elem

Mit dem struct-Objekt direkt (oder einer Referenz darauf) verwendest du
obj.elem

Um den -> Operator zu verwenden einen Zeiger erfinden, ist natürlich Unsinn bzw. höchstens eine Übungsaufgabe.

"->" lässt sich überladen. Der "." Operator nicht.

Ja...
Der * allerdings auch.
Sowohl der Multiplikations* als auch der Dereferenzierungs*

Ich hätte das nun einmal so getestet:

struct Mein_Filter

{

float filterResult;
float x;
float result;

};

  Mein_Filter.filterResult.v[1] = (2.452372752527856026e-1 * Mein_Filter.x) + (0.50952544949442879485 * Mein_Filter.filterResult.v[0]);
  Mein_Filter.filterResult.result = Mein_Filter.filterResult.v[0] + Mein_Filter.filterResult.v[1];

}

Aber da muss ich jetzt noch die v[0], v[1],v[2] definieren, oder?

Error bekomme ich:

C:\Users\emanu\AppData\Local\Temp\.arduinoIDE-unsaved202333-19788-18dwbej.o118\SPO2\SPO2.ino:89:14: error: expected unqualified-id before '.' token Mein_Filter.filterResult.result = Mein_Filter.filterResult.v[0] + Mein_Filter.filterResult.v[1];

v[0],v[1],v[2] steht für meinen Vektor, das "Lineal"?

Da Du es anscheinend strikt ablehnst, Dich mit den Grundlagen von C++ zu befassen, wirst Du noch lange im Nebel stochern.

Gruß Tommy

v[0] und v[1] sind in dem Beispiel, das du nachbauen willst, zwei Elemente von filterResult, und filterResult ist kein float sondern eine struct, die du übernehmen kannst, aber nicht musst. Die du aber zumindest verstehen solltest.

1 Like

Ah okay danke, dann wird das schon klarer. Aber wo ist den v[1] und v[2] dem struct filterResult zugeordnet? Bei butterworthFilter_t finde ich v[2] in der Header Datei.

.h


struct butterworthFilter_t
{
  float v[2];
  float result;
};

void lowPassButterworthFilter( float x, butterworthFilter_t * filterResult );

 float meanDiff(float M, meanDiffFilter_t* filterValues);

Müsste V[0] und V[1] nicht wie v[2] dem struct in der header zugeordnet werden?

Wenn ich dich richtig verstehe, kann ich das struct löschen und einfach für v[0] und v[1] Variablen mit float definieren ?

Also


float FilterResult0;
float FilterResult1;
float FilterResult_result;
float X;

X = ....;



FilterResult0 = FilterResult1;

  //Fs = 100Hz and Fc = 10Hz
  FilterResult1 = (2.452372752527856026e-1 * x) + (0.50952544949442879485 * FilterResult0);


  FilterResult_result = FilterResult0 + FilterResult1;

In der "original" Headeratei wurde eine Struktur vom Typ butterworthFilter_t deklariert. Dieser Datentyp ist aus einem Array (v) von Typ float und einer Variablen (result) von Typ float zusammengesetzt. Irgendwo im Programm wird eine Variable vom Typ butterworthFilter_t angelegt worden sein, die als Pointer an die Funktion void lowPassButterworthFilter( float x, butterworthFilter_t * filterResult ); übergeben wurde.

Damit in der Funktion auf den Inhalt der Member der Struktur zugegriffen werden kann, wird der "->" Operator verwendet.

Was Du da gebaut hast, hat mit dem "Original" so rein gar nichts mehr zu tun. In deinem zusammengesetzten Datentyp Mein_Filter aus#14 gibt es kein Member-Array "v". Trotzdem willst Du mit Mein_Filter.filterResult.v[1] darauf zugreifen.

Des geht net...

1 Like
struct butterworthFilter_t
{
  const float a =  0.24523728;
  const float b =  0.50952545;
  float v1;
  float result(float x) {
       float valt = v1;  
       v1 = x * a + valt * b; 
       return valt + v1;
  }
};
butterworthFilter_t b;
void setup() {
  Serial.begin(115200);
}

void loop() {
  float x = random(500,1000) *0.1;
  Serial.print(x,1); Serial.print(" "); Serial.println(b.result(x),3);  // in SerialPlotter ansehen
  delay (100); // 10 Hz
}

... so etwa ...

Nachtrag 1:
jetzt wissen wir immer noch nicht, was es mit dem -> auf sich hat :slight_smile:
Nachtrag 2:
Ein Filter erster Ordnung braucht sich nur 1 Zustandsvariable zu merken

Nachtrag 3:
und erinnern uns:

any low pass filter is fine

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.