Please help a bone-headed newbie.

I’m trying to follow along with what bochovj has on his site here:

Using this code:

#include "LowPassFilter.c"

//The number of samples to buffer before analyzing them
int samplesN = 200;

int micPin = 0;

LowPassFilter* filter;

void setup(){
  Serial.begin(115200);
  filter = new LowPassFilter();
  LowPassFilter_init(filter);
}

int index = 0;
int maxpeak = 0 ;
int minPeak = 1023;

void loop(){
  int peak = 0;

  for(int k=0; k<samplesN; k++){
    int val = analogRead(micPin);
    LowPassFilter_put(filter, val);

    int filtered = LowPassFilter_get(filter);
    peak = max(peak, filtered);
  }  
  maxpeak = max(maxpeak, peak);
  minPeak = min(minPeak, peak);

  index++;
  if(index == 1000){
    maxpeak = 0;
    minPeak = 1023;
  }
  int lvl = map(peak, minPeak, maxpeak, 0, 1023);
  Serial.println(lvl);
}

When I run Verify I get an error which I expected:
“bass_detector.ino:1:27: fatal error: LowPassFilter.c: No such file or directory”

So I add a tab named LowPassFilter.c and paste in the contents as he directs from here http://t-filter.appspot.com/fir/index.html:

#include "SampleFilter.h"

static double filter_taps[SAMPLEFILTER_TAP_NUM] = {
  -0.02010411882885732,
  -0.05842798004352509,
  -0.061178403647821976,
  -0.010939393385338943,
  0.05125096443534972,
  0.033220867678947885,
  -0.05655276971833928,
  -0.08565500737264514,
  0.0633795996605449,
  0.310854403656636,
  0.4344309124179415,
  0.310854403656636,
  0.0633795996605449,
  -0.08565500737264514,
  -0.05655276971833928,
  0.033220867678947885,
  0.05125096443534972,
  -0.010939393385338943,
  -0.061178403647821976,
  -0.05842798004352509,
  -0.02010411882885734
};

void SampleFilter_init(SampleFilter* f) {
  int i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i)
    f->history[i] = 0;
  f->last_index = 0;
}

void SampleFilter_put(SampleFilter* f, double input) {
  f->history[f->last_index++] = input;
  if(f->last_index == SAMPLEFILTER_TAP_NUM)
    f->last_index = 0;
}

double SampleFilter_get(SampleFilter* f) {
  double acc = 0;
  int index = f->last_index, i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i) {
    index = index != 0 ? index-1 : SAMPLEFILTER_TAP_NUM-1;
    acc += f->history[index] * filter_taps[i];
  };
  return acc;
}

Then, when I re-run Verify, I get another error which I also expected:
“LowPassFilter.c:1:26: fatal error: SampleFilter.h: No such file or directory”

So I add another tab named SampleFilter.h and paste in the contents:

#ifndef SAMPLEFILTER_H_
#define SAMPLEFILTER_H_

/*

FIR filter designed with
 http://t-filter.appspot.com

sampling frequency: 2000 Hz

* 0 Hz - 400 Hz
  gain = 1
  desired ripple = 5 dB
  actual ripple = 4.1393894966071585 dB

* 500 Hz - 1000 Hz
  gain = 0
  desired attenuation = -40 dB
  actual attenuation = -40.07355419274887 dB

*/

#define SAMPLEFILTER_TAP_NUM 21

typedef struct {
  double history[SAMPLEFILTER_TAP_NUM];
  unsigned int last_index;
} SampleFilter;

void SampleFilter_init(SampleFilter* f);
void SampleFilter_put(SampleFilter* f, double input);
double SampleFilter_get(SampleFilter* f);

#endif

But when I run Verify again, I end up back where I started:
“bass_detector.ino:1:27: fatal error: LowPassFilter.c: No such file or directory”

I feel like I’m chasing my tail. But I must be doing something fundamentally wrong.

This line in the .INO:

#include "LowPassFilter.c"

should be this:

#include "LowPassFilter.h"

It's very rare to include a .C file. It's almost always #include "xxx.[u]h[/u]".

It's a .h file because it's a "header" file. Header files declare variables and routines that will be defined elsewhere. It's like a promise: the SampleFilterInit is implemented with a bunch of lines somewhere else, but here's what it looks like so the compiler will know it's ok to use it in the .INO file. There's a linking step that connects the .INO reference to the routine with the actual lines of code for the routine in the separate .C file.

Cheers, /dev

/dev: It's a .h file because it's a "header" file. Header files declare variables and routines that will be defined elsewhere. It's like a promise: the SampleFilterInit is implemented with a bunch of lines somewhere else, but here's what it looks like so the compiler will know it's ok to use it in the .INO file. There's a linking step that connects the .INO reference to the routine with the actual lines of code for the routine in the separate .C file.

Cheers, /dev

I thought linking was done with precompiled or separately compiled modules and a make file... from what I've seen so far, the .H files just reference the .C source files (as you stated). But isn't that step just an #include of the .C file?

I don’t think you should include the .c file, as /dev points out. Make a new tab in the IDE, call it “LowPassFilter.c” and paste the contents of LowPassFilter.c into it. Then remove the #include “LowPassFilter.c” part.

aarg: I thought linking was done with precompiled or separately compiled modules and a make file...

Linking is the process of combining compiled objects together. A make file is simply an automated/scripted way of compiling and linking programs. So, you have multiple source files, which are compiled, and linked (libraries are already compiled source files, so you only have the object files, not the source).

from what I've seen so far, the .H files just reference the .C source files (as you stated).

It's the other way around. .C files include (reference) .H files. .H files should never include .C files.

But isn't that step just an #include of the .C file?

No. A .C file includes a .H file, never the other way (well, technically you can do it, but it's a very, very bad idea).

arduinodlb:
Linking is the process of combining compiled objects together. A make file is simply an automated/scripted way of compiling and linking programs. So, you have multiple source files, which are compiled, and linked (libraries are already compiled source files, so you only have the object files, not the source).

It’s the other way around. .C files include (reference) .H files. .H files should never include .C files.

No. A .C file includes a .H file, never the other way (well, technically you can do it, but it’s a very, very bad idea).

I am referring to the library file, not the application file or “main program”. So yes, “helloworld.c” has #include <stdio.h> at the top. Somewhere there is a file, like “stdio.c” that has the functional code. “stdio.h” at least contains the function prototypes for the functions in “stdio.c”. I have yet to see any object files in the device libraries that I have downloaded for the Arduino. They are all *.c or *.cpp files. So it is a fair question, how the compiler knows which file to use. For example, I look at time.h from the time library. It contains function prototypes and definitions. There is a time.cpp with the actual code. In my primary C source file, I #include time.h. So where is the reference to time.cpp? Surely, it’s not just looking for the identical filename, without the prefix?

Thanks very much for everyone's replies. Much appreciated.

Some progress (?) but no success.

Still taking it one step at a time, should I add a tab SampleFilter.h and paste in the contents there? Or add it to the libraries folder and link to it that way?

Either way looks to me like much the same cryptic error...

Linked to it in the libraries folder returns:

Arduino: 1.6.1 (Windows 7), Board: "Arduino Nano, ATmega328"

Using library SampleFilter in folder: C:\Users\Steve\Documents\Arduino\libraries\SampleFilter (legacy)



C:\Program Files (x86)\Arduino/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10601 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs -IC:\Users\Steve\Documents\Arduino\libraries\SampleFilter C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build3555318545410608056.tmp\LowPassFilter.c -o C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build3555318545410608056.tmp\LowPassFilter.c.o 

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build3555318545410608056.tmp\LowPassFilter.c:3:27: error: 'SAMPLEFILTER_TAP_NUM' undeclared here (not in a function)

 static double filter_taps[SAMPLEFILTER_TAP_NUM] = {

                           ^

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build3555318545410608056.tmp\LowPassFilter.c:27:24: error: unknown type name 'SampleFilter'

 void SampleFilter_init(SampleFilter* f) {

                        ^

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build3555318545410608056.tmp\LowPassFilter.c:34:23: error: unknown type name 'SampleFilter'

 void SampleFilter_put(SampleFilter* f, double input) {

                       ^

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build3555318545410608056.tmp\LowPassFilter.c:40:25: error: unknown type name 'SampleFilter'

 double SampleFilter_get(SampleFilter* f) {

                         ^

Error compiling.

Added as a tab:

Arduino: 1.6.1 (Windows 7), Board: "Arduino Nano, ATmega328"

C:\Program Files (x86)\Arduino/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10601 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build2056147504189273834.tmp\LowPassFilter.c -o C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build2056147504189273834.tmp\LowPassFilter.c.o 

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build2056147504189273834.tmp\LowPassFilter.c:3:27: error: 'SAMPLEFILTER_TAP_NUM' undeclared here (not in a function)

 static double filter_taps[SAMPLEFILTER_TAP_NUM] = {

                           ^

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build2056147504189273834.tmp\LowPassFilter.c:27:24: error: unknown type name 'SampleFilter'

 void SampleFilter_init(SampleFilter* f) {

                        ^

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build2056147504189273834.tmp\LowPassFilter.c:34:23: error: unknown type name 'SampleFilter'

 void SampleFilter_put(SampleFilter* f, double input) {

                       ^

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build2056147504189273834.tmp\LowPassFilter.c:40:25: error: unknown type name 'SampleFilter'

 double SampleFilter_get(SampleFilter* f) {

                         ^

Error compiling.

Since you are quite likely to use this library in more than one sketch, put it in your Arduino libraries folder. Make the folder name exactly match the library name, so that Arduino knows where to find the .h and .c files.

Then use #include <LowPassFilter.h>
The angle brackets instead of quotes (") tell the compiler to look in the standard location for libraries.

Thanks, MorganS.

My sketch is now as below, with a tab LowPassFilter.c:

#include <LowPassFilter.h>

// #include "LowPassFilter.c"

//The number of samples to buffer before analyzing them
int samplesN = 200;

int micPin = 0;

LowPassFilter* filter;

void setup(){
  Serial.begin(115200);
  filter = new LowPassFilter();
  LowPassFilter_init(filter);
}

int index = 0;
int maxpeak = 0 ;
int minPeak = 1023;

void loop(){
  int peak = 0;

  for(int k=0; k<samplesN; k++){
    int val = analogRead(micPin);
    LowPassFilter_put(filter, val);

    int filtered = LowPassFilter_get(filter);
    peak = max(peak, filtered);
  }  
  maxpeak = max(maxpeak, peak);
  minPeak = min(minPeak, peak);

  index++;
  if(index == 1000){
    maxpeak = 0;
    minPeak = 1023;
  }
  int lvl = map(peak, minPeak, maxpeak, 0, 1023);
  Serial.println(lvl);
}

And I have LowPassFilter.h in this folder: C:\Users\Steve\Documents\Arduino\libraries\LowPassFilter
but I still get compiler errors:

Arduino: 1.6.1 (Windows 7), Board: "Arduino Nano, ATmega328"

Using library SampleFilter in folder: C:\Users\Steve\Documents\Arduino\libraries\SampleFilter (legacy)



C:\Program Files (x86)\Arduino/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10601 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs -IC:\Users\Steve\Documents\Arduino\libraries\SampleFilter C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build5101369154882342258.tmp\LowPassFilter.c -o C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build5101369154882342258.tmp\LowPassFilter.c.o 

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build5101369154882342258.tmp\LowPassFilter.c:3:27: error: 'SAMPLEFILTER_TAP_NUM' undeclared here (not in a function)

 static double filter_taps[SAMPLEFILTER_TAP_NUM] = {

                           ^

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build5101369154882342258.tmp\LowPassFilter.c:27:24: error: unknown type name 'SampleFilter'

 void SampleFilter_init(SampleFilter* f) {

                        ^

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build5101369154882342258.tmp\LowPassFilter.c:34:23: error: unknown type name 'SampleFilter'

 void SampleFilter_put(SampleFilter* f, double input) {

                       ^

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build5101369154882342258.tmp\LowPassFilter.c:40:25: error: unknown type name 'SampleFilter'

 double SampleFilter_get(SampleFilter* f) {

                         ^

Error compiling.

It looks like LowPassFilter.c is not finding SampleFilter.h.

Try changing the first line in LowPassFilter.c to

#include <SampleFilter.h>

arduinodlb:
It looks like LowPassFilter.c is not finding SampleFilter.h.

Try changing the first line in LowPassFilter.c to

#include <SampleFilter.h>

Thanks, arduinodlb. Tried that. Another error:

Arduino: 1.6.1 (Windows 7), Board: "Arduino Nano, ATmega328"

Using library LowPassFilter in folder: C:\Users\Steve\Documents\Arduino\libraries\LowPassFilter (legacy)



C:\Program Files (x86)\Arduino/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10601 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs -IC:\Users\Steve\Documents\Arduino\libraries\LowPassFilter C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build4575839827301304542.tmp\LowPassFilter.c -o C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build4575839827301304542.tmp\LowPassFilter.c.o 

C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build4575839827301304542.tmp\LowPassFilter.c:1:26: fatal error: SampleFilter.h: No such file or directory

 #include <SampleFilter.h>

                          ^

compilation terminated.

Error compiling.

Then I tried it with LowPassFilter.h:

Arduino: 1.6.1 (Windows 7), Board: "Arduino Nano, ATmega328"

Using library LowPassFilter in folder: C:\Users\Steve\Documents\Arduino\libraries\LowPassFilter (legacy)



C:\Program Files (x86)\Arduino/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10601 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs -IC:\Users\Steve\Documents\Arduino\libraries\LowPassFilter C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build7419285227465268876.tmp\LowPassFilter.c -o C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build7419285227465268876.tmp\LowPassFilter.c.o 

C:\Program Files (x86)\Arduino/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10601 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs -IC:\Users\Steve\Documents\Arduino\libraries\LowPassFilter C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build7419285227465268876.tmp\bass_detector.cpp -o C:\USERS\STEVE\APPDATA\LOCAL\TEMP\build7419285227465268876.tmp\bass_detector.cpp.o 

bass_detector.ino:10:1: error: 'LowPassFilter' does not name a type

bass_detector.ino: In function 'void setup()':

bass_detector.ino:14:3: error: 'filter' was not declared in this scope

bass_detector.ino:14:16: error: expected type-specifier before 'LowPassFilter'

bass_detector.ino:14:16: error: expected ';' before 'LowPassFilter'

bass_detector.ino:15:28: error: 'LowPassFilter_init' was not declared in this scope

bass_detector.ino: In function 'void loop()':

bass_detector.ino:27:23: error: 'filter' was not declared in this scope

bass_detector.ino:27:34: error: 'LowPassFilter_put' was not declared in this scope

bass_detector.ino:29:44: error: 'LowPassFilter_get' was not declared in this scope

Error compiling.

I really feel like it’s something staring back at me. :stuck_out_tongue:

I finally found it. The code I was using referred to LowPassFilter.c, and LowPassFilter.h while the filter software was naming the output files SamplFilterc. and SampleFilter.h. I kept trying to fix it in the #include statements all the while ignoring what was in the body of the sketch.

I said it was bone-headed. :-[