How to calibrate internal temperature sensor value in STM32 L496ZGT4 - stm32

I'm creating simple project using STM32 L946ZGT4. I'd like to use the internal temperature sensor. I configured ADC and i can get value from this. My problem is with calibrate this sensor. Using Reference Manual and Datasheet instructions my final value in celsius degrees equals -17. The ADC value is about 800. Here is my code for sensor calibrating.
#include "Myfun.h"
#include "HD44780.h"
extern uint16_t tab[100];
char buf[16];
float sum, avg;
#define TS_CAL1((uint16_t*)((uint32_t) 0x1FFF75A8))
#define TS_CAL2((uint16_t*)((uint32_t) 0x1FFF75CA))
#define TS_CAL1_TEMP 30.0 f
#define TS_CAL2_TEMP 130.0 f
int32_t temperature;
int main(void)
{
SysTick_Config(4000000 / 1000);
LCD_Init();
Led_Conf();
ADC_Conf_DMA_TempSensor();
while (1)
{
sum = 0;
for (int i = 0; i < 100;)
{
sum = sum + tab[i];
++i;
}
avg = sum / 100; // here is my value from ADC
temperature = (int32_t)(((TS_CAL2_TEMP - TS_CAL1_TEMP) / ((float)(*TS_CAL2) - (float)(*TS_CAL1))) *
(avg - (float)(*TS_CAL1)) + 30.0);
sprintf(buf, "%d C", temperature);
LCD_Clear();
LCD_WriteText(buf);
delay_ms(60);
}
}

you have to convert your ADC reading to volt by:
ADC_value / ADC_maxvalue * ADC_refvoltage
with
ADC_value: the value you get back from the ADC
ADC_maxvalue: 2^12 = 4096, when you are sampling in the 12-bit mode
ADC_revoltage: 3.3 Volt, typically - except you are using a different reference voltage
Then apply the formula from the datasheet, chapter "Electrical Characteristics" --> "Operating Conditions" --> "Temperature Sensor", where you find the offset and the scale (plus the formula) to convert the voltage to temperature ...

Related

MPU-9250 sample rate lower than the one selected in register map

I'm using Arduino UNO and I2C protocol to read data from MPU 9250 in arduino IDE. But the sampling rate is lower than the one I selected, indeed, I try to use 1KHz but the maximum speed I can reach is by reading only one of the sensors and is 25 Hz. Do you know I can improve the speed of sampling?
This is my code:
float ax, ay, az, gx, gy, gz;//Some original data of accelerometer, gyroscope and magenetometer
float mx, my, mz;
float magCalibration[3]={0, 0 ,0};
int16_t accelCount[3]; // Stores the 16-bit signed accelerometer sensor output
int16_t gyroCount[3]; // Stores the 16-bit signed gyro sensor output
int16_t magCount[3]; // Stores the 16-bit signed magnetometer sensor output
// Specify sensor full scale
uint8_t Gscale = 0; //GFS_250DPS;
uint8_t Ascale = 0; //AFS_2G;
uint8_t Mscale = 1; // Choose either 14-bit or 16-bit magnetometer resolution
uint8_t Mmode = 0x02; // 2 for 8 Hz, 6 for 100 Hz continuous magnetometer data read
// scale resolutions per LSB for the sensors
float gRes = 250./32768.0; // *(PI/180.0); degrees/s
float mRes = 1000.*4219./32760.0; // nT
float aRes = 2./32768.0; //g
float lastUpdate=0;
float Now, deltat;
void setup() {
Wire.begin();//Initialize
Serial.begin(115200);//Initialize the serial
//MyBlue.begin(9600);
initMPU9250(); //Inititalize the accelerometer
initAK8963(magCalibration);//Initialize the magnetometer
//int tickEvent1=t.every(timeChange, get_motion);
//int tickEvent2=t.every(500, printout) ;//print out the serial 50 after this line
}
void loop() {
get_motion();
printout();
Now = micros();
deltat = ((Now - lastUpdate)/1000000.0f); // set integration time by time elapsed since last filter update
lastUpdate = Now;
Serial.println(deltat);
}
void printout()
{
Serial.print(ax);
Serial.print(',');
Serial.print(ay);
Serial.print(',');
Serial.println(az);
Serial.print(',');
Serial.print(gx);
Serial.print(',');
Serial.print(gy);
Serial.print(',');
Serial.println(gz);
Serial.print(',');
Serial.print(mx);
Serial.print(',');
Serial.print(my);
Serial.print(',');
Serial.println(mz);
}
void get_motion()
{
if (readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01) { // On interrupt, check if data ready interrupt
readAccelData(accelCount); // Read the x/y/z adc values
// Now we'll calculate the accleration value into actual g's
ax = (float)accelCount[0] * aRes;// * 9.81;
ay = (float)accelCount[1] * aRes; //* 9.81;
az = (float)accelCount[2] * aRes; //* 9.81;
readGyroData(gyroCount); // Read the x/y/z adc values
// Calculate the gyro value into actual degrees per second
gx = (float)gyroCount[0] * gRes;
gy = (float)gyroCount[1] * gRes;
gz = (float)gyroCount[2] * gRes;
readMagData(magCount); // Read the x/y/z adc values
// Calculate the magnetometer values in milliGauss
// Include factory calibration per data sheet and user environmental corrections
mx = (float)magCount[0] * mRes * magCalibration[0];
my = (float)magCount[1] * mRes * magCalibration[1];
mz = (float)magCount[2] * mRes * magCalibration[2];
}
}
void readAccelData(int16_t * destination)
{
uint8_t rawData[6]; // x/y/z accel register data stored here
readBytes(MPU9250_ADDRESS, ACCEL_XOUT_H, 6, &rawData[0]); // Read the six raw data registers into data array
destination[0] = ((int16_t)rawData[0] << 8) | rawData[1] ; // Turn the MSB and LSB into a signed 16-bit value
destination[1] = ((int16_t)rawData[2] << 8) | rawData[3] ;
destination[2] = ((int16_t)rawData[4] << 8) | rawData[5] ;
}
void readGyroData(int16_t * destination)
{
uint8_t rawData[6]; // x/y/z gyro register data stored here
readBytes(MPU9250_ADDRESS, GYRO_XOUT_H, 6, &rawData[0]); // Read the six raw data registers sequentially into data array
destination[0] = ((int16_t)rawData[0] << 8) | rawData[1] ; // Turn the MSB and LSB into a signed 16-bit value
destination[1] = ((int16_t)rawData[2] << 8) | rawData[3] ;
destination[2] = ((int16_t)rawData[4] << 8) | rawData[5] ;
}
void readMagData(int16_t * destination)
{
uint8_t rawData[7]; // x/y/z gyro register data, ST2 register stored here, must read ST2 at end of data acquisition
//read mag
writeByte(MPU9250_ADDRESS, INT_PIN_CFG, 0x02); //set i2c bypass enable pin to true to access magnetometer
delay(10);
writeByte(AK8963_ADDRESS, 0x0A, 0x01); //enable the magnetometer
delay(100);
if(readByte(AK8963_ADDRESS, AK8963_ST1) & 0x01) { // wait for magnetometer data ready bit to be set
readBytes(AK8963_ADDRESS, AK8963_XOUT_L, 6, &rawData[0]); // Read the six raw data and ST2 registers sequentially into data array
uint8_t c = rawData[6]; // End data read by reading ST2 register
//if(!(c & 0x08)) { // Check if magnetic sensor overflow set, if not then report data
destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ; // Turn the MSB and LSB into a signed 16-bit value
destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ; // Data stored as little Endian
destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
//}
}
}
void initAK8963(float * destination)
{
// First extract the factory calibration for each magnetometer axis
uint8_t rawData[3]; // x/y/z gyro calibration data stored here
writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer
delay(10);
writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x0F); // Enter Fuse ROM access mode
delay(10);
readBytes(AK8963_ADDRESS, AK8963_ASAX, 3, &rawData[0]); // Read the x-, y-, and z-axis calibration values
destination[0] = (float)(rawData[0] - 128)/256. + 1.; // Return x-axis sensitivity adjustment values, etc.
destination[1] = (float)(rawData[1] - 128)/256. + 1.;
destination[2] = (float)(rawData[2] - 128)/256. + 1.;
writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer
delay(10);
// Configure the magnetometer for continuous read and highest resolution
// set Mscale bit 4 to 1 (0) to enable 16 (14) bit resolution in CNTL register,
// and enable continuous mode data acquisition Mmode (bits [3:0]), 0010 for 8 Hz and 0110 for 100 Hz sample rates
writeByte(AK8963_ADDRESS, AK8963_CNTL, Mscale << 4 | Mmode); // Set magnetometer data resolution and sample ODR
delay(10);
}
void initMPU9250()
{
// wake up device
//writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x80);
delay(100);
writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x00); // Clear sleep mode bit (6), enable all sensors
delay(100); // Wait for all registers to reset
// get stable time source
writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x01); // Auto select clock source to be PLL gyroscope reference if ready else
delay(200);
// Configure Gyro and Thermometer
// Disable FSYNC and set thermometer and gyro bandwidth to 41 and 42 Hz, respectively;
// minimum delay time for this setting is 5.9 ms, which means sensor fusion update rates cannot
// be higher than 1 / 0.0059 = 170 Hz
// DLPF_CFG = bits 2:0 = 011; this limits the sample rate to 1000 Hz for both
// With the MPU9250, it is possible to get gyro sample rates of 32 kHz (!), 8 kHz, or 1 kHz
writeByte(MPU9250_ADDRESS, CONFIG, 0x01);
// Set sample rate = gyroscope output rate/(1 + SMPLRT_DIV)
writeByte(MPU9250_ADDRESS, SMPLRT_DIV, 0x00); // Use a 200 Hz rate; a rate consistent with the filter update rate
// determined inset in CONFIG above
// Set gyroscope full scale range
// Range selects FS_SEL and GFS_SEL are 0 - 3, so 2-bit values are left-shifted into positions 4:3
uint8_t c = readByte(MPU9250_ADDRESS, GYRO_CONFIG); // get current GYRO_CONFIG register value
// c = c & ~0xE0; // Clear self-test bits [7:5]
c = c & ~0x03; // Clear Fchoice bits [1:0]
c = c & ~0x18; // Clear GFS bits [4:3]
c = c | Gscale << 3; // Set full scale range for the gyro
// c =| 0x00; // Set Fchoice for the gyro to 11 by writing its inverse to bits 1:0 of GYRO_CONFIG
writeByte(MPU9250_ADDRESS, GYRO_CONFIG, c ); // Write new GYRO_CONFIG value to register
// Set accelerometer full-scale range configuration
c = readByte(MPU9250_ADDRESS, ACCEL_CONFIG); // get current ACCEL_CONFIG register value
// c = c & ~0xE0; // Clear self-test bits [7:5]
c = c & ~0x18; // Clear AFS bits [4:3]
c = c | Ascale << 3; // Set full scale range for the accelerometer
writeByte(MPU9250_ADDRESS, ACCEL_CONFIG, c); // Write new ACCEL_CONFIG register value
// Set accelerometer sample rate configuration
// It is possible to get a 4 kHz sample rate from the accelerometer by choosing 1 for
// accel_fchoice_b bit [3]; in this case the bandwidth is 1.13 kHz
c = readByte(MPU9250_ADDRESS, ACCEL_CONFIG2); // get current ACCEL_CONFIG2 register value
c = c & ~0x0F; // Clear accel_fchoice_b (bit 3) and A_DLPFG (bits [2:0])
c = c | 0x02; // Set accelerometer rate to 1 kHz and bandwidth to 41 Hz
writeByte(MPU9250_ADDRESS, ACCEL_CONFIG2, c); // Write new ACCEL_CONFIG2 register value
// The accelerometer, gyro, and thermometer are set to 1 kHz sample rates,
// but all these rates are further reduced by a factor of 5 to 200 Hz because of the SMPLRT_DIV setting
// Configure Interrupts and Bypass Enable
// Set interrupt pin active high, push-pull, hold interrupt pin level HIGH until interrupt cleared,
// clear on read of INT_STATUS, and enable I2C_BYPASS_EN so additional chips
// can join the I2C bus and all can be controlled by the Arduino as master
writeByte(MPU9250_ADDRESS, INT_PIN_CFG, 0x22);
writeByte(MPU9250_ADDRESS, INT_ENABLE, 0x01); // Enable data ready (bit 0) interrupt
delay(100);
}
// Wire.h read and write protocols
void writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
{
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.write(data); // Put data in Tx buffer
Wire.endTransmission(); // Send the Tx buffer
}
uint8_t readByte(uint8_t address, uint8_t subAddress)
{
uint8_t data; // `data` will store the register data
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
Wire.requestFrom(address, (uint8_t) 1); // Read one byte from slave register address
data = Wire.read(); // Fill Rx buffer with result
return data; // Return data read from slave register
}
void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
{
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
uint8_t i = 0;
Wire.requestFrom(address, count); // Read bytes from slave register address
while (Wire.available()) {
dest[i++] = Wire.read(); } // Put read results in the Rx buffer
}
With the settings you have in initMPU9250, I don't see any reason not to get 1kHz sampling rate. However, Serial.print may be slowing you down. I suggest reducing the rate of your Serial dumps to 0.5s intervals to see if the situation improves.
EDIT:
I just noticed a few things that are wrong in your readMagData function.
Move these statements to the appropriate place in initAK8963:
//read mag
writeByte(MPU9250_ADDRESS, INT_PIN_CFG, 0x02); //set i2c bypass enable pin to true to access magnetometer
delay(10);
writeByte(AK8963_ADDRESS, 0x0A, 0x01); //enable the magnetometer
delay(100);
because performing those actions on every data read will slow you down to below 10 Hz. They are configuration commands that are meant to be done once upon init of the sensor.
Reading the AK8963 data requires actually reading an extra register in order for the read to trigger. Change the 6 to a 7 in this line like so:
readBytes(AK8963_ADDRESS, AK8963_XOUT_L, 7, &rawData[0]);

Frequency Adjusting with STM32 DAC

I used STM32F407VG to create a 30 khz sine wave. Timer settings are; Prescaler = 2-1, ARR = 1, also the clock is 84 Mhz(the clock which runs DAC).
I wrote a function called generate_sin();
#define SINE_ARY_SIZE (360)
const int MAX_SINE_DEGERI = 4095; // max_sine_value
const double BASLANGIC_NOKTASI = 2047.5; //starting point
uint32_t sine_ary[SINE_ARY_SIZE];
void generate_sine(){
for (int i = 0; i < SINE_ARY_SIZE; i++){
double deger = (sin(i*M_PI*360/180/SINE_ARY_SIZE) * BASLANGIC_NOKTASI) + BASLANGIC_NOKTASI; //double value
sine_ary[i] = (uint32_t)deger; // value
}
This is the function which creates sine wave. I used HAL DMA to send DAC output variables.
HAL_TIM_Base_Start(&htim2);
generate_sine();
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, sine_ary, SINE_ARY_SIZE, DAC_ALIGN_12B_R);
These are the codes i used to do what i want. But im having a trouble to change frequency without changing prescaler or ARR.
So here is my question. Can i change frequency without changing timer settings ? For example i want to use buttons and whenever i push button i want my frequency to change.
The generate_sine function will give you one period of a sine wave which has SINE_ARY_SIZE of samples.
To increase the frequency you need to make the period shorter (for 2x frequency, you would have half the number of samples per period). So you should calculate the array for smaller SINE_ARY_SIZE (which will fill just part of the original buffer with a shorter sine wave) and also put this smaller value in the HAL_DAC_Start_DMA function.
Decreasing the frequency will require making the array longer.
You should declare the sine_ary with a maximum length that you will need (for lowest frequency). Make sure it fits in RAM.
#define MAXIMUM_ARRAY_LENGTH 360
uint32_t usedArrayLength = 180;
const double amplitude = 2047.5;
uint32_t sine_ary[MAXIMUM_ARRAY_LENGTH];
void generate_sine(){
for (int i = 0; i < usedArrayLength; i++){
double value = (sin(i*M_PI*2/usedArrayLength) * amplitude) + amplitude;
sine_ary[i] = (uint32_t)value; // value
}
This will have two times higher frequency than the original code, because it only has 180 samples per period, compared to 360.
Start it using
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, sine_ary, usedArrayLength, DAC_ALIGN_12B_R);
To change the frequency, stop DAC, change the value of usedArrayLength (smaller value means higher frequency, must be less or equal to MAXIMUM_ARRAY_LENGTH). Then call the generate_sine function and start the DAC again by the same function (that now uses new usedArrayLength).
Frequency will be: Clock/prescaler/ARR/usedArrayLength
Also, you should use uint16_t for the array (values are from 0 to 4095, the DAC is 12bit I suppose) and DMA should be set to Half-word (2 bytes per value).

Transmitting data from Arduino UNO into MATLAB but getting a lot of NaNs and numbers with missing digits

I'm collecting degree data from an encoder using an Arduino Uno, and then sending that data into MATLAB using USB. In order to get velocity of rotation as well, I'm generating and sending a timestamp after every degree data point from the Arduino into MATLAB. The data is generated flawlessly on the Arduino side--there's nothing wrong on the Serial Monitor.
In MATLAB, however, my data matrices fill up with quite a few NaNs, as well as the occasional integer with a missing first digit. For example, instead of 216 degree, I get 16 degrees coming through, or instead of 7265900 microseconds, I get 265900 microseconds coming through.
I've been able to solve the issue of losing time data by using Arduino's millis() clock instead of its micros() clock and by adding a 50 millisecond delay after the encoder reading. The problem of degree data loss goes away if I increase the delay after the millis() clock, but then degree data acquisition becomes too slow to be useful.
Any help would be much appreciated!
Code pasted below. First the Arduino code, then the MATLAB code.
Thank you!
David
#include <Adafruit_LEDBackpack.h>
#include <Adafruit_GFX.h>
#include <gfxfont.h>
#include <SPI.h> //Include the SPI library in this sketch.
#include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc.
//#include <TinyWireM.h> // Enable this line if using Adafruit Trinket, Gemma, etc.
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
Adafruit_7segment matrix = Adafruit_7segment();
//Variables for SPI rotary encoder
boolean knob_detected = false;
byte slave_select = 10; //Slave select pin.
byte mosi = 11; //MOSI pin.
byte miso = 12; //MISO pin.
byte spi_clock = 13; //Clock pin.
byte read_counter = 96;
byte write_mode0 = 137;
byte write_mode1 = 144;
byte count1;
byte count2;
int count;
int val;
int button = 7;
int b = 0;
int degree;
int absolute;
unsigned long time;
// SETUP //
void setup() {
//Connect the 4 communication pins between the Arduino and the quadrature counter.
#ifndef __AVR_ATtiny85__
Serial.begin(9600);
//Serial.println("7 Segment Backpack Test");
#endif
matrix.begin(0x70);
pinMode(slave_select, OUTPUT);
pinMode(mosi, OUTPUT);
pinMode(miso, INPUT);
pinMode(spi_clock, OUTPUT);
// pinMode(button,INPUT);
SPI.begin(); //Begin SPI communication.
SPI.setBitOrder(MSBFIRST); //Bytes read into SPI will be read in MSB style.
SPI.setDataMode(SPI_MODE0); //Set the data to shift on the low clock phase with normal (non-inverted) clock polarity.
digitalWrite(slave_select, HIGH); //Close the SPI communication port.
SPI.setClockDivider(SPI_CLOCK_DIV128); //Set the SPI clock to 125 kHz (This can be changed).
digitalWrite(slave_select, LOW); //Set slave select low to enable communication.
SPI.transfer(write_mode0); //Select mode 0 for modifying.
SPI.transfer(0b01000011); //Write to mode 0: Synchronous Index, disable index, range-limit count mode, x4 quadrature.
digitalWrite(slave_select, HIGH); //Set slave select high to disable communication
digitalWrite(slave_select, LOW); //Set slave select low to enable communication
SPI.transfer(write_mode1); //Select mode 1 for modifying.
SPI.transfer(2); //Write across a 0b01 to mode1 to enable 2 byte data transfers
digitalWrite(slave_select, HIGH); //Set slave select high to disable communication
Serial.begin(9600); //Set the baud rate for serial data transmission.
//Serial.println("READY"); //Print "READY" to the serial line to indicate that initialization is complete.
}
// MAIN LOOP //
void loop() {
digitalWrite(slave_select, LOW); //Set slave_select pin low to begin tranmission .
SPI.transfer(read_counter); //Read from the read_counter register.
count1 = SPI.transfer(0); //Send a null transfer to read byte1 values.
count2 = SPI.transfer(0); //Send a null transfer to read byte2 values.
digitalWrite(slave_select, HIGH); //Set slave_select high to end transmission.
count = word(count1, count2); //Type cast the 2 bytes as a word.
degree = count / 4;
absolute = abs(degree);
//Send back the value of the register over the serial line.
b = digitalRead(button);
if (b == HIGH) {
digitalWrite(absolute,LOW);
}
else {}
if (absolute == LOW)
{
absolute = 0;
}
else {}
Serial.println(absolute); //Send back the value of the register over the serial line.
matrix.print(absolute,DEC);
matrix.writeDisplay();
delay(50); //Pause for 50 milliseconds before re-looping.
time = millis();
Serial.println(time);
delay(10);
}
clear all;
close all;
clc;
delete(instrfind); %delete connected ports
p=getserialport;
[m,n] = listdlg('PromptString','Select Your Bluetooth device:','SelectionMode','single','ListString',p);
com=cell2mat(p(m));
s=serial(com);
fopen(s);
csd = figure;
set(csd,'Name','Plotting Arduino Data on MATLAB','NumberTitle','off'); % open Figure
t=1:100;% total Figure
hAx(1) = subplot(211);
hLine(1) = line('XData',t, 'YData',nan(size(t)), 'Color','b', 'Parent',hAx(1));
xlabel('Samples'), ylabel('Degrees');
hAx(2) = subplot(212);
hLine(2) = line('XData',t, 'YData',nan(size(t)), 'Color','b', 'Parent',hAx(2));
xlabel('Samples'), ylabel('Velocity');
set(hAx, 'Box','on', 'YGrid','on');
axis(hAx(1),[0,100,0,100]);
axis(hAx(2),[0,100,0,100000]);
d=zeros(1,100); %buffer of 100 elements
sm=zeros(1,10); %buffer of 10 elements
t10=zeros(1,10); %buffer of 10 elements
t100=zeros(1,100); %buffer of 100 elements
while(1)
j=1;
while(j<=10)
flushinput(s);
sc=(fscanf(s));
if(length(sc)<6) %1000 degree units = 6 char (was <7 for micros() clock)
sm(j)=str2double(sc);
else %i.e. else, if a timestamp (more than 7 chars)
t10(j)=str2double(sc);
j=j+1;
end
end
t100 = [t100,t10];
t100 = t100(11:end);
d=[d,sm]; %Add new Samples
d=d(11:end); %Remove old Samples
%d(end)
set(hLine(1), 'YData',d); %draw Degrees
set(hLine(2), 'YData',t100); %draw Velocity (currently just timestamps)
drawnow %# force MATLAB to flush any queued displays
end
(getserialport function defined by the following m-file)
function x=getserialport
serialInfo = instrhwinfo('serial');
x=serialInfo.SerialPorts;
end

Perform autocorrelation with vDSP_conv from Apple Accelerate Framework

I need to perform the autocorrelation of an array (vector) but I am having trouble finding the correct way to do so. I believe that I need the method "vDSP_conv" from the Accelerate Framework, but I can't follow how to successfully set it up. The thing throwing me off the most is the need for 2 inputs. Perhaps I have the wrong function, but I couldn't find one that operated on a single vector.
The documentation can be found here
Copied from the site
vDSP_conv
Performs either correlation or convolution on two vectors; single
precision.
void vDSP_conv ( const float __vDSP_signal[], vDSP_Stride
__vDSP_signalStride, const float __vDSP_filter[], vDSP_Stride __vDSP_strideFilter, float __vDSP_result[], vDSP_Stride __vDSP_strideResult, vDSP_Length __vDSP_lenResult, vDSP_Length __vDSP_lenFilter );
Parameters
__vDSP_signal
Input vector A. The length of this vector must be at least __vDSP_lenResult + __vDSP_lenFilter - 1.
__vDSP_signalStride
The stride through __vDSP_signal.
__vDSP_filter
Input vector B.
__vDSP_strideFilter
The stride through __vDSP_filter.
__vDSP_result
Output vector C.
__vDSP_strideResult
The stride through __vDSP_result.
__vDSP_lenResult
The length of __vDSP_result.
__vDSP_lenFilter
The length of __vDSP_filter.
For an example, just assume you have an array of float x = [1.0, 2.0, 3.0, 4.0, 5.0]. How would I take the autocorrelation of that?
The output should be something similar to float y = [5.0, 14.0, 26.0, 40.0, 55.0, 40.0, 26.0, 14.0, 5.0] //generated using Matlab's xcorr(x) function
performing autocorrelation simply means you take the cross-correlation of one vector with itself. There is nothing fancy about it.
so in your case, do:
vDSP_conv(x, 1, x, 1, result, 1, 2*len_X-1, len_X);
check a sample code for more details: (which does a convolution)
http://disanji.net/iOS_Doc/#documentation/Performance/Conceptual/vDSP_Programming_Guide/SampleCode/SampleCode.html
EDIT: This borders on ridiculous, but you need to offset the x value by a specific number of zeros, which is just crazy.
the following is a working code, just set filter to the value of x you desire, and it will put the rest in the correct position:
float *signal, *filter, *result;
int32_t signalStride, filterStride, resultStride;
uint32_t lenSignal, filterLength, resultLength;
uint32_t i;
filterLength = 5;
resultLength = filterLength*2 -1;
lenSignal = ((filterLength + 3) & 0xFFFFFFFC) + resultLength;
signalStride = filterStride = resultStride = 1;
printf("\nConvolution ( resultLength = %d, "
"filterLength = %d )\n\n", resultLength, filterLength);
/* Allocate memory for the input operands and check its availability. */
signal = (float *) malloc(lenSignal * sizeof(float));
filter = (float *) malloc(filterLength * sizeof(float));
result = (float *) malloc(resultLength * sizeof(float));
for (i = 0; i < filterLength; i++)
filter[i] = (float)(i+1);
for (i = 0; i < resultLength; i++)
if (i >=resultLength- filterLength)
signal[i] = filter[i - filterLength+1];
/* Correlation. */
vDSP_conv(signal, signalStride, filter, filterStride,
result, resultStride, resultLength, filterLength);
printf("signal: ");
for (i = 0; i < lenSignal; i++)
printf("%2.1f ", signal[i]);
printf("\n filter: ");
for (i = 0; i < filterLength; i++)
printf("%2.1f ", filter[i]);
printf("\n result: ");
for (i = 0; i < resultLength; i++)
printf("%2.1f ", result[i]);
/* Free allocated memory. */
free(signal);
free(filter);
free(result);

Help with IIR Comb Filter

Reverb.m
#define D 1000
OSStatus MusicPlayerCallback(
void* inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames
AudioBufferList * ioData){
MusicPlaybackState *musicPlaybackState = (MusicPlaybackState*) inRefCon;
//Sample Rate 44.1
float a0,a1;
double y0, sampleinp;
//Delay Gain
a0 = 1;
a1 = 0.5;
for (int i = 0; i< ioData->mNumberBuffers; i++){
AudioBuffer buffer = ioData->mBuffers[i];
SIn16 *outSampleBuffer = buffer.mData;
for (int j = 0; j < inNumberFrames*2; j++) {
//Delay Left Channel
sampleinp = *musicPlaybackState->samplePtr++;
/* IIR equation of Comb Filter
y[n] = (a*x[n])+ (b*x[n-D])
*/
y0 = (a0*sampleinp) + (a1*sampleinp-D);
outSample[j] = fmax(fmin(y0, 32767.0), -32768.0);
j++;
//Delay Right Channel
sampleinp = *musicPlaybackState->samplePtr++;
y0 = (a0*sampleinp) + (a1*sampleinp-D);
outSample[j] = fmax(fmin(y0, 32767.0), -32768.0);
}
}
}
Ok, I got a lot of info but I'm having trouble implementing it. Can someone help, it's probably something really easy i'm forgeting. It's just playing back as normal with a little boost but no delays.
Your treatment of the x0[] variables doesn't look right -- the way you have it, the left and right channels will be intermingled. You assign to x0[j] for the left channel, then
overwrite x0[j] with the right channel data. So the delayed signal x0[j-D] will
always correspond to the right channel, with the delayed left channel data being lost.
You didn't say what your sample rate is, but for a typical audio application, a
three-sample delay might not have much of an audible effect. At 44.1 ksamp/sec,
with a 3-sample delay the peaks and troughs of the filter response will be at
multiples of 14,700 Hz. All you'll get is a single peak in the audio frequency
range, in a part of the spectrum where there's hardly any power (assuming the
signal is speech or music).