I'm trying to ouptput a the waveform contained in a wav file using the NI DAQMx ANSI C library. I'm using the libsnd library to read the wav file and I'm able to extract the data sucessfully, however the frequency of the output waveform is much higher than the actual wav file itself. Does anyone know how the frequency of the output waveform can be set. I'm using the PCIe 6351 Data Acquisition card.
Below is some code I wrote out to do this task:
#include<stdio.h>
#include<conio.h>
#include <math.h>
#include <stdlib.h>
#include <windows.h>
#include "NIDAQmx.h"
#include "Sync_AIAO.h"
#include "sndfile.h"
#include "RIB2.h"
int32 fnCreateTask(TaskHandle *AOTaskHandle)
{
int32 error=0;
DAQmxErrChk(DAQmxCreateTask("", AOTaskHandle));
Error:
return error;
}
int main(int argc, char** argv)
{
int i=0;
int32 error=0;
TaskHandle AOtaskHandle = 0;
float64* AIOSample;
float *fWavSample;
SNDFILE *SoundFile;
SF_INFO SoundFileInfo;
int iNoOfSamples=0;
FILE* fp;
//Error code
//Handle to the tasks created
char errBuff[2048]={'\0'};
//DAQmxErrChk(DAQmxCreateTask("",AOtaskHandle));
fnCreateTask(&AOtaskHandle);
//Create an analog out channel
DAQmxErrChk (DAQmxCreateAOVoltageChan(* (&AOtaskHandle),"Dev1/ao1","",-10.0000000,+10.00000,DAQmx_Val_Volts,NULL));
//Set for
//DAQmxErrChk (DAQmxCfgDigEdgeStartTrig(&AOtaskHandle,"ai/StartTrigger",DAQmx_Val_Rising));
SoundFile=sf_open("sine.wav", SFM_READ, &SoundFileInfo);
//Check if file is opened sucessfully
if (SoundFile == NULL)
{
printf("Failed to open the file.\n");
exit(-1);
}
//allocate memory for the buffer that is to hold the wav data:
fWavSample = new float[SoundFileInfo.channels * SoundFileInfo.frames];
iNoOfSamples = SoundFileInfo.channels * SoundFileInfo.frames;
//Read data into the float structure
sf_readf_float(SoundFile, fWavSample, SoundFileInfo.frames);
printf("Float:%d, Float64:%d\n",sizeof(float),sizeof(float64));
//printf("%f\n",fWavSample[0]);
//printf("%f\n",fWavSample[200000]);
AIOSample = new float64[iNoOfSamples];
// fopen_s(&fp,"output.dat","w");
for(i=0;i<SoundFileInfo.channels * SoundFileInfo.frames;i++)
{
// fprintf(fp,"Data[%d]:%f\n",i,fWavSample[i]);
AIOSample[i] = (float64)fWavSample[i];
}
// fclose(fp);
int32 written;
/*calling function that will output the trigger on PFI6*/
//fnSrPlayElectric(); //play electric stimulus
while(1)
{
/*
DAQmxErrChk(DAQmxWriteAnalogF64(AOtaskHandle,(SoundFileInfo.channels * SoundFileInfo.frames),
true, 10.0, DAQmx_Val_GroupByChannel,AIOSample,&written,NULL));
*/
DAQmxErrChk(DAQmxWriteAnalogF64(AOtaskHandle,1000,
true, 10.0, DAQmx_Val_GroupByChannel,AIOSample,&written,NULL));
//Sleep(3000);
}
//Display the error to the user here.
Error:
if( DAQmxFailed(error) )
{
DAQmxGetExtendedErrorInfo(errBuff,2048);
puts(errBuff);
}
getch();
}
I'd appreciate any help I can get. Thanks!
Atul
Right now, your program is writing samples to the DAQ card one at a time as fast as the process can and you're sending samples in groups of 1000. In DAQmx terms, this is a "software-timed" task, since the OS, scheduler, CPU, and other system dynamics affect how often a sample is written to the card.
Since audio files are sampled at a constant rate, you will also need to program the DAQ card to generate the samples at that same rate. In DAQmx terms, using a sample clock is called a "hardware-timed" task. DAQmx also comes with ANSI C examples for configuring a sample clock [1]. Take a look at "Continuously Generate Voltage - Internal Clock", which probably has an abbreviated name on disk, and how it uses the function DAQmxCfgSampClkTiming [2]. There is also more information on how timing works for DAQmx online [3].
For example, if your audio file is sampled at 44.1 kHz, you'll need to set the sample clock frequency to be the same. Beware however, that the 6351 has a 100 MHz timebase [4] and divides it down by integers to get lower sample clock rates. So for this 44.1 kHz example, the closest frequency you can get is 44.111 kHz (100 MHz / 2267) or 44.091 kHz (100 MHz / 2268). You can check the actual sample rate using DAQmxGetSampClkRate [5] after you configure it -- DAQmx will coerce it to a valid value.
[1] Text Based NI-DAQmx Data Acquisition Examples :: ANSI C
http://www.ni.com/white-paper/6999/en/#ANSIC
[2] NI-DAQmx C Reference Help :: DAQmxCfgSampClkTiming
http://zone.ni.com/reference/en-XX/help/370471W-01/daqmxcfunc/daqmxcfgsampclktiming
[3] Timing, Hardware Versus Software
http://zone.ni.com/reference/en-XX/help/370466V-01/TOC11.htm
[4] X Series User Manual :: Clock Routing (page 183)
http://digital.ni.com/manuals.nsf/websearch/82BB2FBF407E178586257D15006F596C
[5] NI-DAQmx C Reference Help :: DAQmxGetSampClkRate
http://zone.ni.com/reference/en-XX/help/370471W-01/mxcprop/func1344
Related
I'm working with .wav files and I need to get their duration in seconds.
So far I've been determining it with:
File size / byte_rate
Byte_rate being (Sample Rate * BitsPerSample * Channels) / 8.
And it works, with smaller files, when I try to parse bigger files, I get more seconds than the actual duration.
Example:
Size(bytes): 45207622 Byte_rate: 176400 Duration: 256
(45207622 / 176400)
but the actual duration is 250...
FYI: I've double checked the size and byte_rate, they are correct.
Without a sample RIFF header or your code, it would be difficult to answer the specifics in your question. (i.e. Why your math isn't coming to your expected result.)
However, since you've specified that you're working in C in the comments, might I suggest using the sox library instead of parsing the headers with newly written code? In addition to catching a fair number of edge cases, this allows you to support any format sox supports reading without having to write any of the reading code yourself. (Though anyone inclined to do so should probably take a look at Can someone explain .wav(WAVE) file headers? and RIFF WAVE format specifications. The process should be roughly the method described in the question, at least in most cases. [Edit: That is chunk data length divided by the header's byte rate.])
Example code:
#include <sox.h>
#include <stdio.h>
int main(int argc, char **argv) {
sox_format_t *fmt;
if(argc < 2) {
printf("Please provide audio file.\n");
return 1;
}
fmt = sox_open_read(argv[1], NULL, NULL, NULL);
__uint64_t ws = fmt->signal.length / fmt->signal.channels;
if(fmt->signal.length) {
printf("%0.2f seconds long\n", (double)ws / fmt->signal.rate);
} else {
printf("Cannot determine duration from header.\n");
}
}
For anyone curious, I largely derived this from the sox command line tool's source code.
Thank you EPR for giving me the fix to timing in my program. I'm not using libsox, I've set up a struct trying to match the original at http://www.lightlink.com/tjweber/StripWav/Canon.html This is NOT the correct way to do it but it works for simple files. Another useful reference is at http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
Anyway I assume the header is 44 bytes and read() it into memory at the location of the struct. Then I can access fields of the struct, malloc space for the pcm data and read() it into the pcm space from where the file pointer was left. I'm just writing an audiogram program so it needs to be close to correct for the WAV files I generate with arecord, sox, Audacity. Always 2 channels, 44100 sample rate. My struct:
struct wavhdr { // defined by Microsoft, needs to match
char riff[4]; // should be "RIFF"
uint32_t len8; // file length - 8
char wave[4]; // should be "WAVE"
char fmt[4]; // should be "fmt "
uint32_t fdatalen; // should be 16 (0x10)
uint16_t ftag; // format tag, 1 = pcm
uint16_t channels; // 2 for stereo
uint32_t sps; // samples/sec
uint32_t srate; // sample rate in bytes/sec (block align)
uint16_t chan8; // channels * bits/sample / 8
uint16_t bps; // bits/sample
char data[4]; // should be "data"
uint32_t datlen; // length of data block
// pcm data follows this
} hdr;
I was trying to use the measured file size - header length / samples/sec, that didn't work, I was off by a factor of 6.
I am using NodeMCU & Energy meter. Energy meter is Modbus RTU device which display parameter in 32 bit. With below piece of code I could able to read the data from slave but need method to type cast from into 32 bit floating & display
When I change the value to unsigned decimal in ModScan software the values showing properly. But I need to display value in 32 bit floating point.
#include <ModbusMaster232.h>
#include <SoftwareSerial.h>
float data[100];
ModbusMaster232 node(1);
// Define one address for reading
#define address 1
// Define the number of bits to read
#define bitQty 70
void setup()
{
Serial.begin(9600);
// Initialize Modbus communication baud rate
node.begin(9600);
}
void loop()
{
int result = node.readHoldingRegisters(address, bitQty);
data[0] = (float)node.getResponseBuffer(0);
data[1] = (float)node.getResponseBuffer(1);
data[2] = (float)node.getResponseBuffer(2);
data[3] = (float)node.getResponseBuffer(3);
data[4] = (float)node.getResponseBuffer(4);
data[5] = (float)node.getResponseBuffer(5);
for (int i = 0; i < 100; i++)
{
//data[i] = node.getResponseBuffer(i);
Serial.println(data[i]);
}
Serial.println("............");
}
I would like to display the reading as shown in Modbus with type casting.
Actual Modbus device output from salve:
Arduino output while read data from energy meter:
You are casting a 16-bit word into a float. Check the slave documentation to find how they map a 32-bit floating point into two Modbus registers. Basically you need to know where the least significant word is (first or second register), load them into memory (shift if necessary) and cast to float.
I am looking and trying to solve exact same problem (with same results). This may help:
function read() {
client.readHoldingRegisters(0000, 12)
.then(function(d) {
var floatA = d.buffer.readFloatBE(0);
console.log("Total kWh: ", floatA); })
.catch(function(e) {
console.log(e.message); })
.then(close);
}
This is NodeJS and javascript version, which works and Arduino does not. Complete example can be found here and it works on Raspberry Pi https://github.com/yaacov/node-modbus-serial/blob/master/examples/buffer.js
I have followed the ZCL report to implement the function which is able to receive the data sent from the sensor.
In the SDk, it is defined as the following:
void ZbZclReportFunc{
struct ZbZclClusterT * clusterPtr,
zbApsdeDataInt * dataIndPtr,
uint16_t attributeId,
const uint8_t * data
}
By implementing the callback function as shown above, I am able to receive all information except data.
In ZCL spec, the Temperature Measurement Cluster defines its "MeasuredValue" Signed 16-bit Integer.
I print out the data using the following format:
printf("Degree: 0x%04x", *data);
As I expect, the data shown is "0x002b" as an example.
By casting it to Signed 16-bit integer, it does not help.
printf("Degree: 0x%04x", (int16_t)*data);
Any idea?
Thanks
Zigbee packet data is little Endian. Also, the units for MeasuredValue are "hundredths of degrees Celsius". So if your measured temperature value was 26 degrees celsius, your data buffer would look like: 28 0A. To convert to celsius you would use:
double temperature = (double)((int16_t)(data[1] << 8) | (int16_t)data[0]) / 100.0;
I am trying to program a MSP430 with a simple "FIR filter" program, that looks like the following:
#include "msp430x22x4.h"
#include "legacymsp430.h"
#define FILTER_LENGTH 4
#define TimerA_counter_value 12000 // 12000 counts/s -> 12000 counts ~ 1 Hz
int i;
double x[FILTER_LENGTH+1] = {0,0,0,0,0};
double y = 0;
double b[FILTER_LENGTH+1] = {0.0338, 0.2401, 0.4521, 0.2401, 0.0338};
signed char floor_and_convert(double y);
void setup(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 = CALBC1_8MHZ; // Set DCO
DCOCTL = CALDCO_8MHZ;
/* Setup Port 3 */
P3SEL |= BIT4 + BIT5; // P3.4,5 = USART0 TXD/RXD
P3DIR |= BIT4; // P3.4 output direction
/* UART */
UCA0CTL1 = UCSSEL_2; // SMCLK
UCA0BR0 = 0x41; // 9600 baud from 8Mhz
UCA0BR1 = 0x3;
UCA0MCTL = UCBRS_2;
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt
/* Setup TimerA */
BCSCTL3 |= LFXT1S_2; // LFXT1S_2: Mode 2 for LFXT1 = VLO
// VLO provides a typical frequency of 12kHz
TACCTL0 = CCIE; // TACCR0 Capture/compare interrupt enable
TACCR0 = TimerA_counter_value; // Timer A Capture/Compare 0: -> 25 Hz
TACTL = TASSEL_1; // TASSEL_1: Timer A clock source select: 1 - ACLK
TACTL |= MC_1; // Start Timer_A in up mode
__enable_interrupt();
}
void main(void) // Beginning of program
{
setup(); // Call Function setup (see above)
_BIS_SR(LPM3_bits); // Enter LPM0
}
/* USCIA interrupt service routine */
/*#pragma vector=USCIAB0RX_VECTOR;*/
/*__interrupt void USCI0RX_ISR(void)*/
interrupt (USCIAB0RX_VECTOR) USCI0RX_ISR(void)
{
TACTL |= MC_1; // Start Timer_A in up mode
x[0] = (double)((signed char)UCA0RXBUF); // Read received sample and perform type casts
y = 0;
for(i = 0;i <= FILTER_LENGTH;i++) // Run FIR filter for each received sample
{
y += b[i]*x[i];
}
for(i = FILTER_LENGTH-1;i >= 0;i--) // Roll x array in order to hold old sample inputs
{
x[i+1] = x[i];
}
while (!(IFG2&UCA0TXIFG)); // Wait until USART0 TX buffer is ready?
UCA0TXBUF = (signed char) y;
TACTL |= TACLR; // Clear TimerA (prevent interrupt during receive)
}
/* Timer A interrupt service routine */
/*#pragma vector=TIMERA0_VECTOR;*/
/*__interrupt void TimerA_ISR (void)*/
interrupt (TIMERA0_VECTOR) TimerA_ISR(void)
{
for(i = 0;i <= FILTER_LENGTH;i++) // Clear x array if no data has arrived after 1 sec
{
x[i] = 0;
}
TACTL &= ~MC_1; // Stops TimerA
}
The program interacts with a MatLab code, that sends 200 doubles to the MSP, for processing in the FIR filter. My problem is, that the MSP is not able to deal with the doubles.
I am using the MSPGCC to compile the code. When I send a int to the MSP it will respond be sending a int back again.
Your problem looks like it is in the way that the data is being sent to the MSP.
The communications from MATLAB is, according to your code, a sequence of 4 binary byte values that you then take from the serial port and cast it straight to a double. The value coming in will have a range -128 to +127.
If your source data is any other data size then your program will be broken. If your data source is providing binary "double" data then each value may be 4 or 8 bytes long depending upon its internal data representation. Sending one of these values over the serial port will be interpreted by the MSP as a full set of 4 input samples, resulting in absolute garbage for a set of answers.
The really big question is WHY ON EARTH ARE YOU DOING THIS IN FLOATING POINT - on a 16 bit integer processor that (many versions) have integer multiplier hardware.
As Ian said, You're taking an 8bit value (UCA0RXBUF is only 8 bits wide anyway) and expecting to get a 32bit or 64 bit value out of it.
In order to get a proper sample you would need to read UCA0RXBUF multiple times and then concatenate each 8 bit value into 32/64 bits which you then would cast to a double.
Like Ian I would also question the wisdom of doing floating point math in a Low power embedded microcontroller. This type of task is much better suited to a DSP.
At least you should use fixed point math, seewikipedia (even in a DSP you would use fixed point arithmetic).
Hmm. Actually the code is made of my teacher, I'm just trying to make it work on my Mac, and not in AIR :-)
MATLAB code is like this:
function FilterTest(comport)
Fs = 100; % Sampling Frequency
Ts = 1/Fs; % Sampling Periode
L = 200; % Number of samples
N = 4; % Filter order
Fcut = 5; % Cut-off frequency
B = fir1(N,Fcut/(Fs/2)) % Filter coefficients in length N+1 vector B
t = [0:L-1]*Ts; % time array
A_m = 80; % Amplitude of main component
F_m = 5; % Frequency of main component
P_m = 80; % Phase of main component
y_m = A_m*sin(2*pi*F_m*t - P_m*(pi/180));
A_s = 40; % Amplitude of secondary component
F_s = 40; % Frequency of secondary component
P_s = 20; % Phase of secondary component
y_s = A_s*sin(2*pi*F_s*t - P_s*(pi/180));
y = round(y_m + y_s); % sum of main and secondary components (rounded to integers)
y_filt = round(filter(B,1,y)); % filtered data (rounded to integers)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Serial_port_object = serial(comport); % create Serial port object
set(Serial_port_object,'InputBufferSize',L) % set InputBufferSize to length of data
set(Serial_port_object,'OutputBufferSize',L) % set OutputBufferSize to length of data
fopen(Serial_port_object) % open Com Port
fwrite(Serial_port_object,y,'int8'); % send out data
data = fread(Serial_port_object,L,'int8'); % read back data
fclose(Serial_port_object) % close Com Port
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subplot(2,1,1)
hold off
plot(t,y)
hold on
plot(t,y_filt,'r')
plot(t,y_filt,'ro')
plot(t,data,'k.')
ylabel('Amplitude')
legend('y','y filt (PC)','y filt (PC)','y filt (muP)')
subplot(2,1,2)
hold off
plot(t,data'-y_filt)
hold on
xlabel('time')
ylabel('muP - PC')
figure(1)
It is also not advised to keep interrupt routines doing long processing routines, because you will impact on interrupt latency. Bytes comming from the PC can get easily lost, because of buffer overrun on the serial port.
The best is to build a FIFO buffer holding a resonable number of input values. The USCI routine fills the FIFO while the main program keeps looking for data inside it and process them as they are available.
This way, while the data is being processed, the USCI can interrupt to handle new incomming bytes.
When the FIFO is empty, you can put the main process in a suitable LPM mode to conserve power (and this is the best MSP430 feature). The USCI routine will wake the CPU up when a data is ready (just put the WAKEUP attribute in the USCI handler if you are using MSPGCC).
In such a scenario be sure to declare volatile every variable that are shared between interrupt routines and the main process.
have C sources that must compile in 32bit and 64bit for multiple platforms.
structure that takes the address of a buffer - need to fit address in a 32bit value.
obviously where possible these structures will use natural sized void * or char * pointers.
however for some parts an api specifies the size of these pointers as 32bit.
on x86_64 linux with -m64 -mcmodel=small tboth static data and malloc()'d data fit within the 2Gb range. data on the stack, however, still starts in high memory.
so given a small utility _to_32() such as:
int _to_32( long l ) {
int i = l & 0xffffffff;
assert( i == l );
return i;
}
then:
char *cp = malloc( 100 );
int a = _to_32( cp );
will work reliably, as would:
static char buff[ 100 ];
int a = _to_32( buff );
but:
char buff[ 100 ];
int a = _to_32( buff );
will fail the assert().
anyone have a solution for this without writing custom linker scripts?
or any ideas how to arrange the linker section for stack data, would appear it is being put in this section in the linker script:
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
thanks!
The stack location is most likely specified by the operating system and has nothing to do with the linker.
I can't imagine why you are trying to force a pointer on a 64 bit machine into 32 bits. The memory layout of structures is mainly important when you are sharing the data with something which may run on another architecture and saving to a file or sending across a network, but there are almost no valid reasons that you would send a pointer from one computer to another. Debugging is the only valid reason that comes to mind.
Even storing a pointer to be used later by another run of your program on the same machine would almost certainly be wrong since where your program is loaded can differ. Making any use of such a pointer would be undefined abd unpredictable.
the short answer appears to be there is no easy answer. at least no easy way to reassign range/location of the stack pointer.
the loader 'ld-linux.so' at a very early stage in process activation gets the address in the hurd loader - in the glibc sources, elf/ and sysdeps/x86_64/ search out elf_machine_load_address() and elf_machine_runtime_setup().
this happens in the preamble of calling your _start() entry and related setup to call your main(), is not for the faint hearted, even i couldn't convince myself this was a safe route.
as it happens - the resolution presents itself in some other old school tricks... pointer deflations/inflation...
with -mcmodel=small then automatic variables, alloca() addresses, and things like argv[], and envp are assigned from high memory from where the stack will grow down. those addresses are verified in this example code:
#include <stdlib.h>
#include <stdio.h>
#include <alloca.h>
extern char etext, edata, end;
char global_buffer[128];
int main( int argc, const char *argv[], const char *envp )
{
char stack_buffer[128];
static char static_buffer[128];
char *cp = malloc( 128 );
char *ap = alloca( 128 );
char *xp = "STRING CONSTANT";
printf("argv[0] %p\n",argv[0]);
printf("envp %p\n",envp);
printf("stack %p\n",stack_buffer);
printf("global %p\n",global_buffer);
printf("static %p\n",static_buffer);
printf("malloc %p\n",cp);
printf("alloca %p\n",ap);
printf("const %p\n",xp);
printf("printf %p\n",printf);
printf("First address past:\n");
printf(" program text (etext) %p\n", &etext);
printf(" initialized data (edata) %p\n", &edata);
printf(" uninitialized data (end) %p\n", &end);
}
produces this output:
argv[0] 0x7fff1e5e7d99
envp 0x7fff1e5e6c18
stack 0x7fff1e5e6a80
global 0x6010e0
static 0x601060
malloc 0x602010
alloca 0x7fff1e5e69d0
const 0x400850
printf 0x4004b0
First address past:
program text (etext) 0x400846
initialized data (edata) 0x601030
uninitialized data (end) 0x601160
all access to/from the 32bit parts of structures must be wrapped with inflate() and deflate() routines, e.g.:
void *inflate( unsigned long );
unsigned int deflate( void *);
deflate() tests for bits set in the range 0x7fff00000000 and marks the pointer so that inflate() will recognize how to reconstitute the actual pointer.
hope that helps if anyone similarly must support structures with 32bit storage for 64bit pointers.