crazylooser017
Posts: 32
Joined: Wed Dec 31, 2014 4:52 pm

Waves generator - Is there a faster way to calculate sines?

Mon Feb 09, 2015 4:48 am

Hi,


I'm trying to remake the wheel, just to learn about it. This is a wave generator that is going to speak Vowels, I need to calculate a very big function so I want to know a faster method to do that.
1) I put overclocking (1000MHz)
2) I use two methods in bash to do 1000 sines. The first one give me 7 seconds and the other 4 seconds.

Code: Select all

#! /bin/bash
# /home/pi/Zepfdr/just4test/math_test02.sh

#Constants
pi=`echo "4*a(1)" | bc -l`
pi2=`echo "$pi*2" | bc -l`

#Variables
fnumber=200
ftim=0.0001

echo -e "Using do loops with | bc -l:\n"
for i in `seq 1 100`
do
       fswave=`echo "$pi2*$fnumber*$ftim" | bc -l`
        #echo "s($fswave)" | bc -l
        ftim=`echo "$ftim+0.0001" | bc -l`
done


echo -e "\n\nUsing do loops with a faster nethod:\n"
for i in `seq 1 100`
do
        fswave=$(bc -l <<< "$pi2*$fnumber*$ftim")
        #echo "s($fswave)" | bc -l
        ftim=$(bc -l <<< "$ftim+0.0001")

done
I read that dash could improve the speed, but first I will try to write all my function to timing. I'll generated just the half of the wave and then is just the opposite.

Just for information of my function, a vowel has:

Fundamental Frequency = fo
Harmonics = fo*2, fo*3, etc.
variables of Natural decrement of the harmonics = Function FL
variables of Formant 1 = Function F1 (Sine)
variables of Fomant 2 = Function F2 (Sine)
variables of Form...
*Amplitude of each frequency = Arithmetic Function (FL:F1:F2:F...:F5)

**Wave form = sin(2pi*fo*time)*Amplitude of fo + sin(2pi*f1*time)*Amplitude of f1 +....

I have 80 frequencies so its going to be a long wait. (I made this with a microcontroller I got like 19 minutes)... Hoping the raspberry can do it faster (Excel made it in 1 sec xD)


Thanks!
Attachments
Wave.PNG
Wave.PNG (8.34 KiB) Viewed 5688 times

ame
Posts: 6040
Joined: Sat Aug 18, 2012 1:21 am
Location: New Zealand

Re: Waves generator - Is there a faster way to calculate sin

Mon Feb 09, 2015 5:38 am

Generally, the fastest way to generate a sine wave is to have a lookup table.

To save memory you only need to generate one quarter of the waveform.

Then your calculation becomes a simple index lookup into a table of values.
Hmm. What can I put here?

User avatar
KLL
Posts: 1453
Joined: Wed Jan 09, 2013 3:05 pm
Location: thailand

Re: Waves generator - Is there a faster way to calculate sin

Mon Feb 09, 2015 5:49 am

ame wrote:the fastest way to generate a sine wave is to have a lookup table.
To save memory you only need to generate one quarter of the waveform.
yes!
i use that in python pygame to generate sounds
http://kll.engineering-news.org/kllfusi ... icle_id=80
and instead to use inverse FFT by adding many sinus ( harmonics )
to generate the first (1/4) lookup table, i just modified a (1/4) square wave by a mouse click, download
http://kll.engineering-news.org/kllfusi ... load_id=44
but yes, its still slow.

crazylooser017
Posts: 32
Joined: Wed Dec 31, 2014 4:52 pm

Re: Waves generator - Is there a faster way to calculate sin

Mon Feb 09, 2015 12:35 pm

Thanks for the reply, you convinced me to use tables :), not sure how this work and if I could have flexibility I'm gonna read about it.


In the ucrontroller I can moved Fo and the position of the formants, this give me the idea of make tables for each sine that I could use. I need to learn that I'll reply soon.

I attached the amplitude wave (Purple line) this is only calculated at first. Then when the wave form starts I could use the tables to save time, I'm just worried about time and not space.


Do you know if python could be a little faster?
Attachments
Formants.PNG
Formants.PNG (10.14 KiB) Viewed 5588 times

User avatar
KLL
Posts: 1453
Joined: Wed Jan 09, 2013 3:05 pm
Location: thailand

Re: Waves generator - Is there a faster way to calculate sin

Mon Feb 09, 2015 2:13 pm

i can not say that python is fast, but not need 10sec for 100 sinus!!
back to your code:
-a- you installed a add tool: bc
-b- you disabled the lines #echo "s($fswave)" | bc -l
what is the sinus calculation and the output to terminal.
i think the math is slow, but more the output!

when you get that number on the screen, how you get the graphs?
because for that again example in python should install add matplotlib
is that really the job? to print graphs?


i test python2:
install add library
sudo apt-get install python-matplotlib
edit a python example
nano python_invfft.py

Code: Select all

import matplotlib.pyplot as plt
import numpy as np

t = np.arange(80)
n = np.zeros((80,), dtype=complex)
#n[40:60] = np.exp(1j*np.random.uniform(0, 2*np.pi, (20,)))
# instead the above good random example i test some manual values:
n[1] = 0.5
n[3] = 0.3
n[5] = 0.1

s = np.fft.ifft(n)
plt.plot(t, s.real, 'b-', t, s.imag, 'r--')

plt.legend(('real', 'imaginary'))

plt.show()
start with
python python_invfft.py
7 sec for math and graphic

User avatar
PeterO
Posts: 6095
Joined: Sun Jul 22, 2012 4:14 pm

Re: Waves generator - Is there a faster way to calculate sin

Mon Feb 09, 2015 2:54 pm

Why are you using "bc" to do maths ?

https://docs.python.org/2/library/math.html

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

crazylooser017
Posts: 32
Joined: Wed Dec 31, 2014 4:52 pm

Re: Waves generator - Is there a faster way to calculate sin

Tue Feb 10, 2015 2:44 am

Good afternoon,

The code is just a simple test due I'm a beginner in the bian, but the goal is send all the data to an external device using a binary format (255) to generated the vowels sound in a speaker in less than 10 seconds.

bc is the first tool that I learn I'm opened to more ways :).

I'm old but I want to learn. I put as example the speed of excell in a standard computer. The graphs are just to show what I want from the calculus.

oh and I'm trying right now with tables...


This is my function the output must be stay from 0 to 255 and Afn is the "Purple line" in the previous graph.

Output at 0.001s = (Af0*sin((2*pi)*f0*t) + Af1*sin((2*pi)*f1*t) + Af2*sin((2*pi)*f2*t) + ... + Afn*sin((2*pi)*fn*t))
Output at 0.002s = (Af0*sin((2*pi)*f0*t) + Af1*sin((2*pi)*f1*t) + Af2*sin((2*pi)*f2*t) + ... + Afn*sin((2*pi)*fn*t))
Output at wherever f0 period at the middle...

It's funny try with different input values... I know that there are voice generators in the market, but as hobby this is fine.

Hoping I can end this project to share it :)...

Thanks to all!
Attachments
Calculations.PNG
Calculations.PNG (59.48 KiB) Viewed 5496 times

User avatar
KLL
Posts: 1453
Joined: Wed Jan 09, 2013 3:05 pm
Location: thailand

Re: Waves generator - Is there a faster way to calculate sin

Tue Feb 10, 2015 3:50 am

i like your thinking

again, if you have the final array of data you can declare it as a sound and play it as audio
using python pygame

Code: Select all

import pygame
from pygame.locals import *
import numpy as np 
...
sound = pygame.sndarray.make_sound(mytmp) 
sound.play(loops=myloops) 
i know that my /python_audio/kll_keyboard.py
is unreadable because of the 95% GUI code and the 88 piano keys code
and i am just a python beginner too.

i read your post about the adding of sinus ( harmonics?) with different amplitudes,
did you check on that example i made about inverse FFT?
i think this is doing exactly the job you need,
you use your Afx and store it in the array n[x] of my example ( that's why i made that manual input example.
i not know where you get the Afx from, but python could read it from a file
and that could be written by a other python (service) program catching it from USB if it comes from a ucontroller like arduino...

crazylooser017
Posts: 32
Joined: Wed Dec 31, 2014 4:52 pm

Re: Waves generator - Is there a faster way to calculate sin

Wed Feb 11, 2015 12:29 pm

Hi KLL, yes but I gave a step back to learn some python basics it's easy I must say... Just to understand better your code.

Af0, Af1... Afn is the amplitude for each harmonic and fundamental frequency, for me, is the variable that I must find; each person and each vowel have their own formants (Fn), I must play with the variables of my first functions to match with the following spectogram attached... ;)

I was checking your recommendation not sure if I can get this kind of harmonicsamplitude control. Is it possible?
Attachments
image.jpg
image.jpg (59.61 KiB) Viewed 5383 times
Last edited by crazylooser017 on Wed Feb 11, 2015 12:54 pm, edited 2 times in total.

crazylooser017
Posts: 32
Joined: Wed Dec 31, 2014 4:52 pm

Re: Waves generator - Is there a faster way to calculate sin

Wed Feb 11, 2015 12:41 pm

So Afn is the adding of a linear function that is the natural decrement of the harmonics (just theory) plus a sin of the formant 1 or A plus the sin of the formant 2... Plus all the rest of the formants.

And it's maked only the first time... I could save the result and then when I need start the script to generate the wave (that is the sum of all the frequencies I could call my previous amplitudes to make easier the process.

So I must say that is ok spend time in the learning/generating routine but not minutes! :)

In this graph I was showing my function to calculate the harmonics amplitude I have only two formants so I need to put four more. If you see I try to replicated the concept of the spectogram.

I got a program and a microphone so I'm starting with my own voice.

Regards!
Attachments
image.jpg
image.jpg (28.06 KiB) Viewed 5378 times

User avatar
KLL
Posts: 1453
Joined: Wed Jan 09, 2013 3:05 pm
Location: thailand

Re: Waves generator - Is there a faster way to calculate sin

Wed Feb 11, 2015 3:15 pm

i am sorry, i can be completely OFF,

but for me it still looks like the sinus amplitude list "spectrum" is same as what i know as result of FFT,
so using the amplitudes list in a INV FFT to create the signal back still looks logical.
( and same as use the sum( Ax*sin(fx) / just faster )

-a- could you run my python example "python_invfft.py"
-b- do you understand what the n(f) means in there, the n[0] is a offset, n[1] groundwave amplitude..
i tested the values manually to show you this, its your Ax list?

-c- pls answer my questions, how you do the graphs now?
and is it the job to do graphs only?
or is it the job to create a sound ( what can be done by my first python pygame way. )?

-d- do you need to take the sound sample by microphone also with RPI?
( i (not) know how to record sound as there is no analog input)
only see this http://www.adafruit.com/product/1475
http://www.correderajorge.es/audio-conf ... pberry-pi/
search for "2) Microphone" , update / got it running
http://kll.engineering-news.org/kllfusi ... 8#example9

-e- the "program" you use, does it do a FFT ? ( i used to do it with laptop in EXCEL, frequency analysis of a recorded sound signal of a walky talky, where the "partners" walky talky is pressed on a gearbox to catch mechanic vibes, now i also do it in arduino of electric grid current signals.

-f- the best audio tool for RPI might be
sudo apt-get install audacity

crazylooser017
Posts: 32
Joined: Wed Dec 31, 2014 4:52 pm

Re: Waves generator - Is there a faster way to calculate sin

Sat Feb 14, 2015 1:00 pm

My apologizes, after my last replied the SD card became damaged :( I tried to use tables and save it in a USB driver,

This code was working to play a stereo 440Hz tone in my tv:

Code: Select all

import pygame, numpy, math
import matplotlib.pyplot as plt

SOUND_DURATION = 1.0
SAMPLE_RATE = 44100
BIT_DEPTH = 16
CHANNELS = 2
FREQUENCY = 440

try:
    pygame.mixer.init(SAMPLE_RATE, -BIT_DEPTH, CHANNELS)

    n_samples = int(round(SOUND_DURATION*SAMPLE_RATE))
    Freq_form = numpy.zeros((n_samples, 2), dtype = numpy.int16)
    max_sample = 2**(BIT_DEPTH - 1) - 1
    
    for s in range(n_samples):
        t = float(s)/SAMPLE_RATE
        Freq_form[s][0] = int(round(max_sample*1*math.sin(2*math.pi*FREQUENCY*t)))	 # left
        Freq_form[s][1] = int(round(max_sample*0.5*math.sin(2*math.pi*FREQUENCY*t))) # right

    sound = pygame.sndarray.make_sound(Freq_form)
    sound.play()
    pygame.time.wait(int(round(1000*SOUND_DURATION)))

finally:
    pygame.mixer.quit()
And I made modifications trying to save time with an array to avoid 18 seconds of math.

Code: Select all

import numpy, math

# Generate some test data
SOUND_DURATION = 1.0
SAMPLE_RATE = 44100
BIT_DEPTH = 16
CHANNELS = 2
FREQUENCY = 440

sample_size = numpy.arange(int(round(SOUND_DURATION*SAMPLE_RATE))).reshape((int(round(SOUND_DURATION*SAMPLE_RATE)),1,1))

data_samples = numpy.zeros((int(round(SOUND_DURATION*SAMPLE_RATE)), 2), dtype = numpy.int16)
max_sample = 2**(BIT_DEPTH - 1) - 1

for s in range(int(round(SOUND_DURATION*SAMPLE_RATE))):
	t = float(s)/SAMPLE_RATE
	data_samples[s][0] = int(round(max_sample*1*math.sin(2*math.pi*FREQUENCY*t)))   #Left 
	data_samples[s][1] = int(round(max_sample*0.5*math.sin(2*math.pi*FREQUENCY*t))) #Right

# Write the array to disk
with file('datasaved03.txt', 'w') as outfile:

    outfile.write('Array shape: {0}\n'.format(sample_size.shape))

    #c for data_slice in sample_size:
    for data_slice in data_samples:

        numpy.savetxt(outfile, data_slice, fmt='%-7.2f', delimiter=';')
        outfile.write('New slice\n')
I got this table:

Code: Select all

Array shape: (44100, 1, 1)
0.00   
0.00   
New slice
2053.00
1026.00
New slice
4098.00
2049.00
New slice
6126.00
3063.00
N
Unfortunately I couldn't get yet the array to play it (with loadtxt or getfromtxt). I'll need help here.

a. I tested your code, run perfect with harmonics and make a graph!. I didn't have success to play a sound with it. I saw all your full code in KLLwebpage. Working to figure out about it.

c. the main goal for this specific topic is generate sound. I'm not worried to make or not graphs (could be cool show something in the screen) but see answer d; to generated my first waves I was using mathlab (in windows 7) with the function, but the ones that I put here were made in microsoft Excell, using the same concept as a mathlab.

d. I'll play weeks with this code, after vowels comes the consonants, after understand it very well and understand more of the python, bash codes, maybe how c works in linux, press external buttons to make sounds, a second task it'll needed, listen and answer!. but that its something far to reach right now. I'm using wavepad (audio editing) with a shure microphone.

crazylooser017
Posts: 32
Joined: Wed Dec 31, 2014 4:52 pm

Re: Waves generator - Is there a faster way to calculate sin

Mon Feb 23, 2015 3:19 pm

In the other hand, I'm using savetxt to see the results of the functions.

This is stereo... how can I give the following format

Code: Select all

Array shape: (44100, 1, 2)
Left           Right
0.00           0.00   
2053.00        1026.00
4098.00        2049.00
6126.00        3063.00
etc
I'm trying to change the shape but not sure if the reason of always get my current order is the 'for' functions.

Anyway I can't get yet my values back.

Regards!

crazylooser017
Posts: 32
Joined: Wed Dec 31, 2014 4:52 pm

Re: Waves generator - Is there a faster way to calculate sin

Sat Mar 07, 2015 6:19 pm

well, after days with these codes. This is my solution:

Savingwave.py
This script uses the formula to calculate for now only one sin wave in one second (I'm still working to use fft...). Then save the array in datasaved.txt. Next updated: generated only one wave.

Soundwave.py
This one extract the array and play the sound. Next updated: play in a bucle the lonely wave.

Right now the timing got some improves. I decided send the array through SPI to an external FLASH memory and play it with a microcontroller (of course the RPi has full control on what is going to play the uC). I want to save resources from the RPi to do other tasks.

These are the codes on the first round:

Code: Select all

import numpy, math

# Generate some test data
SOUND_DURATION = 1.0
SAMPLE_RATE = 44100
BIT_DEPTH = 16
CHANNELS = 2
FREQUENCY = 440

sample_size = numpy.arange(int(round(SOUND_DURATION*SAMPLE_RATE))).reshape((int(round(SOUND_DURATION*SAMPLE_RATE)) ,1 ,1))

data_samples = numpy.zeros((int(round(SOUND_DURATION*SAMPLE_RATE)), 1), dtype = numpy.int16)
max_sample = 2**(BIT_DEPTH - 1) - 1

for s in range(int(round(SOUND_DURATION*SAMPLE_RATE))):
	t = float(s)/SAMPLE_RATE
	data_samples[s] = int(round(max_sample*1*math.sin(2*math.pi*FREQUENCY*t)))   #Left 
	#data_samples[s][1] = int(round(max_sample*0.5*math.sin(2*math.pi*FREQUENCY*t))) #Right

# Write the array to disk
with file('datasaved05.txt', 'w') as outfile:

    outfile.write('Array shape: {0}\n'.format(sample_size.shape))

    #c for data_slice in sample_size:
    for data_slice in data_samples:

        #numpy.savetxt(outfile, data_slice, fmt='%-7.2f', delimiter=';')
	numpy.savetxt(outfile, data_slice, fmt='%-7.0f')
        #outfile.write('New slice\n')

print data_samples.shape
print data_samples

Code: Select all

import pygame, numpy, math


print("Getting data")
datain = numpy.loadtxt('datasaved05.txt', dtype = int, skiprows=1).reshape(44100, 1)
#print datain

SOUND_DURATION = 1.0
SAMPLE_RATE = 44100
BIT_DEPTH = 16
CHANNELS = 2
FREQUENCY = 440

try:
    pygame.mixer.init(SAMPLE_RATE, -BIT_DEPTH, CHANNELS)

    n_samples = int(round(SOUND_DURATION*SAMPLE_RATE))
    Freq_form = numpy.zeros((n_samples, 2), dtype = numpy.int16)
    max_sample = 2**(BIT_DEPTH - 1) - 1
    
    for s in range(n_samples):
        t = float(s)/SAMPLE_RATE
        Freq_form[s][0] = datain[s]    # left
        Freq_form[s][1] = datain[s]    # right

    sound = pygame.sndarray.make_sound(Freq_form)
    print("loading")
    sound.play()    
    pygame.time.wait(int(round(1000*SOUND_DURATION)))
    print("Stop")

    sound = pygame.sndarray.make_sound(Freq_form)
    print("loading")
    sound.play()
    pygame.time.wait(int(round(1000*SOUND_DURATION)))
    print("Stop")

    sound = pygame.sndarray.make_sound(Freq_form)
    print("loading")
    sound.play()
    pygame.time.wait(int(round(1000*SOUND_DURATION)))
    print("Stop")


finally:
    pygame.mixer.quit()
1) Both codes have common variables, I'll change this to a master script that ask me for the values of these ones. Then play savingwave part and later soundwave part... The challenge here is save each test with a new number. That later will become in a, e, i, o & u.

2) I don't know yet how works

Code: Select all

    sound = pygame.sndarray.make_sound(Freq_form)
    sound.play()
    pygame.time.wait(int(round(1000*SOUND_DURATION)))
If you see I put three times this one to play 3 seconds of sound.


Regards!

crazylooser017
Posts: 32
Joined: Wed Dec 31, 2014 4:52 pm

Re: Waves generator - Is there a faster way to calculate sin

Wed Mar 11, 2015 5:02 am

I'm here...

a) Master Script
b) Save configuration settings
c) Save 2channel array
d) Using Sine long function...
e) Everything works fine

Code: Select all

import pygame, numpy, math

print 'Speech Development Platform...\n'
question = 'Select an action\n	a) Design  wave shape\n	b) Plot wave shape\n	c) Play sound'
print (question)

while True:
	
	answer = raw_input()
	
	if answer == 'a':
		SAMPLE_RATE = 44100
		BIT_DEPTH = 16
		CHANNELS = 2
		FREQUENCY = 440
		SOUND_DURATION = 1
		
		config_data = numpy.arange(5).reshape((5,1,1))
		
		config_data[0] = SAMPLE_RATE
		config_data[1] = BIT_DEPTH
		config_data[2] = CHANNELS
		config_data[3] = FREQUENCY
		config_data[4] = SOUND_DURATION

		# Write configuration array to disk
                with file('Config01.txt', 'w') as outfile:

                        outfile.write('Array shape: {0}\n'.format(config_data.shape))

                        for cd_slice in config_data:

                                numpy.savetxt(outfile, cd_slice, fmt='%-7.0f')

		sample_size = numpy.arange(int(round(SOUND_DURATION*SAMPLE_RATE))).reshape((int(round(SOUND_DURATION*SAMPLE_RATE)) ,1 ,1))
		data_samples = numpy.zeros((int(round(SOUND_DURATION*SAMPLE_RATE)), 2), dtype = numpy.int16)
		max_sample = 2**(BIT_DEPTH - 1) - 1

		for s in range(int(round(SOUND_DURATION*SAMPLE_RATE))):
			t = float(s)/SAMPLE_RATE
			data_samples[s][0] = int(round(max_sample*1*math.sin(2*math.pi*FREQUENCY*t)))   #Left 
			data_samples[s][1] = int(round(max_sample*0.5*math.sin(2*math.pi*FREQUENCY*t))) #Right	

		# Write the array to disk
		with file('Speech_data01.txt', 'w') as outfile:

	    		outfile.write('Array shape: {0}\n'.format(sample_size.shape))
    			for data_slice in data_samples:

				numpy.savetxt(outfile, data_slice, fmt='%-7.0f')

		print data_samples.shape
		print data_samples

		break

	elif answer == 'b':
		y = numpy.zeros((4, 1), dtype = float)
		x = numpy.zeros((4,), dtype=float)
		x[1] = 1.0
		y = numpy.fft.fft(x)*32767
		print y.real
		break

	elif answer == 'c':
		print 'Getting data'
		
		config_data = numpy.loadtxt('Config01.txt', dtype = int, skiprows=1).reshape(5, 1)
		
		SAMPLE_RATE = config_data[0]
                BIT_DEPTH = config_data[1]
                CHANNELS = config_data[2]
                FREQUENCY = config_data[3]
                SOUND_DURATION = config_data[4]*1.0
		
		#print (SOUND_DURATION)
		datain = numpy.loadtxt('Speech_data01.txt', dtype = int, skiprows=1).reshape(44100, 2)
		print datain

		#SAMPLE_RATE = 44100
		#BIT_DEPTH = 16
		#CHANNELS = 2
		#FREQUENCY = 440
		#SOUND_DURATION = 1.0

		try:
    			pygame.mixer.init(SAMPLE_RATE, -BIT_DEPTH, CHANNELS)
			sound = pygame.sndarray.make_sound(datain)
    			print("loading")
    			sound.play()
			sound.play()
    			sound.play()
			sound.play()    
    			pygame.time.wait(int(round(4000*SOUND_DURATION)))
    			print("Stop")

		finally:
    			pygame.mixer.quit()

		break

	else:
		print 'Wrong'


but! I want to use numpy.fft.fft so I have a problem developing the code for that.

Code: Select all

	elif answer == 'b':
		y = numpy.zeros((4, 1), dtype = float)
		x = numpy.zeros((4,), dtype=float)
		x[1] = 1.0
		y = numpy.fft.fft(x)*32767
		print y.real
		break
This little code is saving an 1D array, but I need to use two channel so "y" must work as 2D array... any ideas?

crazylooser017
Posts: 32
Joined: Wed Dec 31, 2014 4:52 pm

Re: Waves generator - Is there a faster way to calculate sin

Wed Mar 11, 2015 5:24 am

Updated:

Ok that was dumb...

Code: Select all

	elif answer == 'b':
		z = numpy.zeros((4, 2)).reshape((4, 2))
		x = numpy.zeros((4,), dtype=float)
		x[1] = 1.0
		y = numpy.fft.fft(x)*32767
		
		for s in range(4):
			z[s][0] = y[s].real
			z[s][1] = y[s].real
		print y.real
		print z
		break
Ok! I finished with this board... Thanks to all.

The last step is going to be replace the long sine funtion with fft... and I'll use it to generate vowels!

Return to “Beginners”