I think that including this line is a MAJOR part of your problem. I think it calculates the magnitude AND SAVES IT IN 'vReal'.
If I remove that line then I get a phase value that is low by about 20° for every phase value from -179 to +179.
I found the other problem: That "(samples - 1)" caused the 20° phase error. Change it to "samples".
Here is the code I was using to test:
#include <arduinoFFT.h>
arduinoFFT FFT;
const uint16_t samples = 128; //This value MUST ALWAYS be a power of 2
const double signalFrequency = 1.0917;
const double samplingFrequency = 10;
double phase_shift = 0;
double vReal[samples];
double vImag[samples];
void setup()
{
Serial.begin(115200);
delay(200);
Serial.println("Ready");
}
void loop()
{
Serial.println("Phase,Real,Imaginary,Phase");
for (int phaseDegrees = -179; phaseDegrees < 180; phaseDegrees += 5)
{
phase_shift = phaseDegrees * PI / 180.0;
DoTheFFT();
Serial.print(phaseDegrees);
Serial.print(",\t");
if (samples == 64)
ShowSample(7); // 64 samples
if (samples == 128)
ShowSample(14); // 128 samples
}
while (1) {}
}
void DoTheFFT()
{
/* Build raw data */
double cycles = ((samples * signalFrequency) / samplingFrequency); //Number of signal cycles that the sampling will read
for (uint16_t i = 0; i < samples; i++)
{
/* Build data with positive and negative values*/
vReal[i] = cos((i * (twoPi * cycles)) / samples + phase_shift);
vImag[i] = 0.0; //Imaginary part must be zeroed in case of looping to avoid wrong calculations and overflows
}
FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD); /* Weigh data */
FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */
// FFT.ComplexToMagnitude(vReal, vImag, samples); /* Compute magnitudes */
// PrintVector();
}
void PrintVector()
{
Serial.println("Amplitude,Real,Imaginary,Phase");
for (uint16_t i = 0; i < (samples / 2) - 1; i++)
{
for (int j = 0; j < 1; j++)
{
ShowSample(i);
}
}
}
void ShowSample(int i)
{
// Serial.print(((i * samplingFrequency) / samples));
// Serial.print(",\t");
float amplitude = sqrt(vReal[i] * vReal[i] + vImag[i] * vImag[i]);
// Serial.print(amplitude);
Serial.print(",\t");
Serial.print(vReal[i]);
Serial.print(",\t");
Serial.print(vImag[i]);
Serial.print(",\t");
if (amplitude > 1.0)
Serial.println(atan2(vImag[i], vReal[i]) * 180 / PI);
else
Serial.println('0');
}