本文主要是介绍File transfer over sound card II: Phase Shift Keying,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
墙外的文章,转载贴过来慢慢看,慢慢翻译。
I've played around further with the file transfer over sound card idea, and developed a more advanced method that uses a technique called Phase Shift Keying. Similar techniques are used in wireless network connections.
I've played around further with the file transfer over sound card idea, and developed a more advanced method that uses a technique called Phase Shift Keying .Similar techniques are used in wireless network connections.
Instead of coding data in the amplitude or frequency of the carrier signal, phase shift keying (as the name indicates) encodes it in the phase. It is significantly faster, partially because it doesn't waste as much time with silences, but also because it's more reliant.
How it works
The mathematics of the method is as following, if the signal is expressed as
S(t) = A 0 sin(ωt + φ)
Then the Fourier transform of S would give you
F ω (S) = A 0 e iφ
Normally, one would simply discard the phase factor by taking the norm of the frequency coefficient, but for this we're going to make use of it . You can't just yank the phase out of the expression as it is though (phase is always relative to something) . But! You can compare this phase with the phase of the last sample you got (this is called differential phase-shift keying, by the way) .
So, I propose the following scheme:
Δφ | Meaning |
---|---|
0 | Still the same sample as last time |
π / 2 | Next bit is 1 |
π | Next bit is 0 |
3 &pi / 2 | New byte |
Modifying the fourier code from the last blog post on sonic file transfers, the following function will allow you to make use of the phase:
double fourier1p(double x_in[], double n, int length, double* phase_r, double* phase_i) {
double x_complex[2] = { 0, 0 };
int i;
for(i = 0; i < length; i++) {
x_complex[0] += x_in[i] * cos(M_PI * 2 * i * n / (double) length);
x_complex[1] += x_in[i] * sin(M_PI * 2 * i * n / (double) length);
}
double norm = sqrt(x_complex[0]*x_complex[0] + x_complex[1]*x_complex[1]);
*phase_i = x_complex[1] / norm;
*phase_r = x_complex[0] / norm;
return norm / length;
}
So how do we figure out the phase difference ? Let φ be the phase of the current sample, and ψ be the phase of the previous sample .
e iφ e -iψ = e i(φ - ψ) = cos(φ - ψ) + i sin(φ - ψ)
The real term will dominate if φ - ψ ~ nπ , and the imaginary term will dominate if φ - ψ ~ (n+1)π/2 and their sign will further tell you if n is odd or even .
The demodulation algorithm is fairly short:
double carrier_phase[2];
double carrier_strength = fourier1p(dbuffer, (float) length * carrier / (float)rate, length, &carrier_phase[0], &carrier_phase[1]);
if(carrier_strength < threshold) continue;
double delta_re = carrier_phase[0] * old_carrier_phase[0] + carrier_phase[1]*old_carrier_phase[1];
double delta_im = -carrier_phase[1]*old_carrier_phase[0] + carrier_phase[0] * old_carrier_phase[1];
if(delta_re * delta_re > delta_im * delta_im) { /* Phase difference is a multiple of pi */
if(delta_re > 0); /* No change */
else {
bit_data = bit_data * 2;
}
} else {
if(delta_im > 0) {
bit_data = bit_data * 2 + 1;
} else {
if(isprint(bit_data)) printf("%c", bit_data);
else printf("<%.2x>", bit_data);
bit_data = 0;
}
}
old_carrier_phase[0] = carrier_phase[0];
old_carrier_phase[1] = carrier_phase[1];
For several reasons, it's a good idea to use a pretty high carrier frequency for this method . At some point, your speaker or microphone will not be able to process the information, so you'll want to stay under that, but a high frequency will result in less perturbation of the signal since fairly few objects have eigenfrequencies in the 5 kHz range or higher, and even oscillation at harmonic frequencies drops off pretty significantly at such frequencies .
Sources
The complete source code for the program:
generate_psk.c
analyze_psk.c
You may have grabbed these the last time, but they are slightly altered now, so get them again:
fourier.h
fourier.c
You also need the playback and record programs I posted in the previous post . They haven't changed though.
playback.c
record.c
Using
Same old warning: Never try these programs with your headphones on . THEY MAKE LOUD NOISES! It is possible to configure these programs to make noises way louder than you ever imagined your headphones could make . You can damage your hearing when playing with audio programming . Tinnitus isn't fun .
To transfer a file (let's transfer /etc/fstab again), put the microphone next to the speaker, pre-type the following on the transmitting computer (without running it):
>./generate_psk -r 48000 -c 8000 -b 100 /etc/fstab | ./playback -r 48000
Type the following on the receiving computer:
>./record -r 48000 > mydata
Press enter on the transmitting computer . Be quiet (this should be fairly quick. Maybe 30 seconds ? ) When the high pitched noise stops, press Ctrl+C on the receiving computer's terminal .
Running
./analyze_psk -r 48000 -c 8000 -b 100 mydata
on the receiving computer should retreive the message .
The parameters are
-r : Sample rate -- carrier frequency and signal quality
-c : Carrier frequency -- limits baud rate and signal quality
-b : Baud rate -- determines how fast the transfer is
What works and doesn't with the sampling rates and frequencies is a bit tricky . It all boils down to Nyquist-Shannon . That theorem is all innocent looking, until you make it mad . Then it turns green and grows three times it's size and goes on a furious rampage through your hopes and dreams.
Anyways, have fun experimenting with this technique .
2011 update: Moved the sources to a github repo.
This has several nice features. You can jump into the signal almost anywhere and at most one byte will be garbled. Furthermore, everything has an uniform length, so bit rate doesn't depend on how many ones and zeros is in the byte.
Modifying the fourier code from the last blog post on sonic file transfers, the following function will allow you to make use of the phase:
这篇关于File transfer over sound card II: Phase Shift Keying的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!