some work with headers ... etc

dev
Oona Räisänen 2015-08-28 17:30:35 +03:00
rodzic c34a49f5db
commit 122a0add97
9 zmienionych plików z 397 dodań i 237 usunięć

Wyświetl plik

@ -1,4 +1,4 @@
bin_PROGRAMS = slowrx
slowrx_CPPFLAGS = -g $(GTKMM_CFLAGS) @SNDFILE_CFLAGS@ $(PORTAUDIO_CFLAGS)
slowrx_LDADD = $(GTKMM_LIBS) @SNDFILE_LIBS@ -lfftw3 $(PORTAUDIO_LIBS)
slowrx_SOURCES = slowrx.cc common.cc modespec.cc gui.cc dsp.cc vis.cc video.cc sync.cc tests.cc
slowrx_SOURCES = slowrx.cc common.cc modespec.cc gui.cc dsp.cc header.cc video.cc sync.cc tests.cc

Wyświetl plik

@ -19,7 +19,6 @@ Glib::KeyFile config;
std::vector<std::thread> threads(2);
PicMeta CurrentPic;
PcmData pcm;
std::vector<std::vector<double> > DSPworker::window_ (16);
@ -102,7 +101,6 @@ void evt_changeDevices() {
int status;
pcm.BufferDrop = false;
Abort = true;
static int init;

Wyświetl plik

@ -1,18 +1,14 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#define MINSLANT 30
#define MAXSLANT 150
#define SYNCPIXLEN 1.5e-3
// moment length only affects length of delay, read interval,
// moment length only affects length of global delay, I/O interval,
// and maximum window size.
#define READ_CHUNK_LEN 1024
#define MOMENT_LEN 2047
#define FFT_LEN_SMALL 1024
#define FFT_LEN_BIG 2048
#define CIRBUF_LEN_FACTOR 4
#define CIRBUF_LEN ((MOMENT_LEN+1)*CIRBUF_LEN_FACTOR)
#define READ_CHUNK_LEN ((MOMENT_LEN+1)/2)
#include <iostream>
#include "portaudio.h"
@ -20,6 +16,21 @@
#include "fftw3.h"
#include "gtkmm.h"
struct Point {
int x;
int y;
explicit Point(int x = 0.0, int y=0.0) : x(x), y(y) {}
};
struct Tone {
double dur;
double freq;
explicit Tone(double dur = 0.0, double freq=0.0) : dur(dur), freq(freq) {}
};
using Wave = std::vector<double>;
using Melody = std::vector<Tone>;
enum WindowType {
WINDOW_CHEB47 = 0,
WINDOW_HANN95,
@ -64,26 +75,6 @@ enum eVISParity {
extern std::map<int, SSTVMode> vis2mode;
typedef struct _FFTStuff FFTStuff;
struct _FFTStuff {
double *in;
fftw_complex *out;
fftw_plan Plan1024;
fftw_plan Plan2048;
};
extern FFTStuff fft;
typedef struct _PcmData PcmData;
struct _PcmData {
// snd_pcm_t *handle;
void *handle;
gint16 *Buffer;
int WindowPtr;
bool BufferDrop;
};
//extern PcmData pcm;
class DSPworker {
public:
@ -219,7 +210,7 @@ void createGUI ();
double deg2rad (double Deg);
std::string GetFSK ();
bool GetVideo (SSTVMode Mode, DSPworker *dsp);
SSTVMode GetVIS (DSPworker*);
SSTVMode modeFromNextHeader (DSPworker*);
int initPcmDevice (std::string);
void *Listen ();
void populateDeviceList ();
@ -229,17 +220,25 @@ void setVU (double *Power, int FFTLen, int WinIdx, bool ShowWin);
int startGui (int, char**);
void findSyncRansac (SSTVMode, std::vector<bool>);
void findSyncHough (SSTVMode, std::vector<bool>);
std::vector<double> upsampleLanczos (std::vector<double>, int);
std::vector<double> Hann (std::size_t);
std::vector<double> Blackmann (std::size_t);
std::vector<double> Rect (std::size_t);
std::vector<double> Gauss (std::size_t);
double findSyncAutocorr (SSTVMode, std::vector<bool>);
double gaussianPeak (double y1, double y2, double y3);
Wave upsampleLanczos (Wave orig, int factor, double middle=1500, int a=3);
Wave Hann (std::size_t);
Wave Blackmann (std::size_t);
Wave Rect (std::size_t);
Wave Gauss (std::size_t);
Wave deriv (Wave);
Wave peaks (Wave, int);
Wave derivPeaks (Wave, int);
Wave rms (Wave, int);
void runTest(const char*);
double complexMag (fftw_complex coeff);
guint8 freq2lum(double);
void printWave(Wave, double);
void evt_AbortRx ();
void evt_changeDevices ();
void evt_chooseDir ();

Wyświetl plik

@ -3,7 +3,7 @@
DSPworker::DSPworker() : Mutex(), please_stop_(false) {
std::vector<double> cheb47 = {
Wave cheb47 = {
0.0004272315,0.0013212953,0.0032312239,0.0067664313,0.0127521667,0.0222058684,
0.0363037629,0.0563165400,0.0835138389,0.1190416120,0.1637810511,0.2182020094,
0.2822270091,0.3551233730,0.4354402894,0.5210045495,0.6089834347,0.6960162864,
@ -13,7 +13,7 @@ DSPworker::DSPworker() : Mutex(), please_stop_(false) {
0.1637810511,0.1190416120,0.0835138389,0.0563165400,0.0363037629,0.0222058684,
0.0127521667,0.0067664313,0.0032312239,0.0013212953,0.0004272315
};
std::vector<double> sq47 = {
Wave sq47 = {
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
@ -138,16 +138,23 @@ double DSPworker::get_t() {
}
void DSPworker::readMore () {
short read_buffer[READ_CHUNK_LEN];
int numchans = file_.channels();
short read_buffer[READ_CHUNK_LEN * numchans];
sf_count_t samplesread = 0;
if (is_open_) {
if (stream_type_ == STREAM_TYPE_FILE) {
samplesread = file_.read(read_buffer, READ_CHUNK_LEN);
samplesread = file_.readf(read_buffer, READ_CHUNK_LEN);
if (samplesread < READ_CHUNK_LEN)
is_open_ = false;
if (numchans > 1) {
for (int i=0; i<READ_CHUNK_LEN; i++) {
read_buffer[i] = read_buffer[i*numchans];
}
}
} else if (stream_type_ == STREAM_TYPE_PA) {
samplesread = READ_CHUNK_LEN;
@ -222,12 +229,8 @@ void DSPworker::windowedMoment (WindowType win_type, fftw_complex *result) {
if_phi += 2 * M_PI * 10000 / samplerate_;*/
result[win_i][0] = result[win_i][1] = a;
//printf("%f\n",a);
//std::cout<<result[win_i]<<",";
}
}
// exit(0);
//std::cout<<"\n";
}
@ -253,25 +256,22 @@ double DSPworker::peakFreq (double minf, double maxf, WindowType wintype) {
peakBin = i;
}
// Find the peak frequency by Gaussian interpolation
//double result = MaxBin + (log( Power[MaxBin + 1] / Power[MaxBin - 1] )) /
// (2 * log( pow(Power[MaxBin], 2) / (Power[MaxBin + 1] * Power[MaxBin - 1])));
double y1 = Mag[peakBin-1], y2 = Mag[peakBin], y3 = Mag[peakBin+1];
double result = peakBin + (y3 - y1) / (2 * (2*y2 - y3 - y1));
double result = peakBin + gaussianPeak(Mag[peakBin-1], Mag[peakBin], Mag[peakBin+1]);
/*double y1 = Mag[peakBin-1], y2 = Mag[peakBin], y3 = Mag[peakBin+1];
double result = peakBin + (y3 - y1) / (2 * (2*y2 - y3 - y1));*/
// In Hertz
result = result / fft_len * samplerate_;
// cheb47 @ 44100 can't resolve <1800 Hz
if (wintype == WINDOW_CHEB47 && result < 1800)
if (result < 1800 && wintype == WINDOW_CHEB47)
result = peakFreq (minf, maxf, WINDOW_HANN95);
return result;
}
std::vector<double> DSPworker::bandPowerPerHz(std::vector<std::vector<double> > bands) {
Wave DSPworker::bandPowerPerHz(std::vector<std::vector<double> > bands) {
int fft_len = FFT_LEN_BIG;
WindowType wintype = WINDOW_HANN2047;
@ -282,8 +282,8 @@ std::vector<double> DSPworker::bandPowerPerHz(std::vector<std::vector<double> >
memcpy(fft_inbuf_, windowed, window_[wintype].size() * sizeof(windowed[0]));
fftw_execute(fft_len == FFT_LEN_BIG ? fft_plan_big_ : fft_plan_small_);
std::vector<double> result;
for (std::vector<double> band : bands) {
Wave result;
for (Wave band : bands) {
double P = 0;
double binwidth = 1.0 * samplerate_ / fft_len;
int nbins = 0;
@ -312,6 +312,12 @@ WindowType DSPworker::bestWindowFor(SSTVMode Mode, double SNR) {
return WinType;
}
// param: y values around peak
// return: peak x position (-1 .. 1)
double gaussianPeak (double y1, double y2, double y3) {
return ((y3 - y1) / (2 * (2*y2 - y3 - y1)));
}
/*WindowType DSPworker::bestWindowFor(SSTVMode Mode) {
return bestWindowFor(Mode, 20);
}*/
@ -347,33 +353,33 @@ WindowType DSPworker::bestWindowFor(SSTVMode Mode, double SNR) {
}*/
std::vector<double> Hann (std::size_t winlen) {
std::vector<double> result(winlen);
for (std::size_t i=0; i < winlen; i++)
Wave Hann (size_t winlen) {
Wave result(winlen);
for (size_t i=0; i < winlen; i++)
result[i] = 0.5 * (1 - cos( (2 * M_PI * i) / (winlen)) );
return result;
}
std::vector<double> Blackmann (std::size_t winlen) {
std::vector<double> result(winlen);
for (std::size_t i=0; i < winlen; i++)
Wave Blackmann (size_t winlen) {
Wave result(winlen);
for (size_t i=0; i < winlen; i++)
result[i] = 0.42 - 0.5*cos(2*M_PI*i/winlen) - 0.08*cos(4*M_PI*i/winlen);
return result;
}
std::vector<double> Rect (std::size_t winlen) {
std::vector<double> result(winlen);
Wave Rect (size_t winlen) {
Wave result(winlen);
double sigma = 0.4;
for (std::size_t i=0; i < winlen; i++)
for (size_t i=0; i < winlen; i++)
result[i] = exp(-0.5*((i-(winlen-1)/2)/(sigma*(winlen-1)/2)));
return result;
}
std::vector<double> Gauss (std::size_t winlen) {
std::vector<double> result(winlen);
for (std::size_t i=0; i < winlen; i++)
Wave Gauss (size_t winlen) {
Wave result(winlen);
for (size_t i=0; i < winlen; i++)
result[i] = 1;
return result;
@ -387,32 +393,98 @@ guint8 freq2lum (double freq) {
return clip((freq - 1500.0) / (2300.0-1500.0) * 255 + .5);
}
std::vector<double> upsampleLanczos(std::vector<double> orig, int factor) {
std::vector<double> result(orig.size()*factor);
int alpha = 4;
int sinclen = (factor*alpha % 2 == 0 ? factor*alpha+1 : factor*alpha);
double middle = 1500;
double sinc (double x) {
return (x == 0 ? 1 : sin(M_PI*x) / (M_PI*x));
}
std::vector<double> sinc(sinclen);
for (int i=0; i<sinclen; i++) {
double x1 = 1.0*i/factor - alpha/2;
double x2 = 2.0*i/sinclen - 1;
sinc[i] = (x1 == 0 ? 1 : sin(M_PI*x1) / (M_PI*x1)) *
(x2 == 0 ? 1 : sin(M_PI*x2) / (M_PI*x2));
Wave upsampleLanczos(Wave orig, int factor, double middle_freq, int a) {
Wave result(orig.size()*factor);
int kernel_len = factor*a*2 + 1;
// make kernel
Wave lanczos(kernel_len);
for (int i=0; i<kernel_len; i++) {
double x_kern = (1.0*i/(kernel_len-1) - .5)*2*a;
double x_wind = 2.0*i/(kernel_len-1) - 1;
lanczos[i] = sinc(x_kern) * sinc(x_wind);
}
for (int i=0; i<orig.size(); i++) {
if (orig[i] != 0) {
for (int j=0; j<sinclen; j++) {
int i_new = i*factor + (j-sinclen/2);
if (i_new > 0 && i_new < result.size())
result[i_new] += (orig[i] - middle) * sinc[j];
// convolution
for (int i=-a; i<int(orig.size()+a); i++) {
double orig_sample;
if (i < 0)
orig_sample = orig[0];
else if (i > orig.size()-1)
orig_sample = orig[orig.size()-1];
else
orig_sample = orig[i];
if (orig_sample != 0) {
for (int kernel_idx=0; kernel_idx<kernel_len; kernel_idx++) {
int i_new = i*factor + (kernel_idx-kernel_len/2);
if (i_new >= 0 && i_new <= result.size()-1)
result[i_new] += (orig_sample - middle_freq) * lanczos[kernel_idx];
}
}
}
for (int i=0; i<result.size(); i++)
result[i] += middle;
result[i] += middle_freq;
return result;
}
Wave deriv (Wave wave) {
Wave result;
for (int i=1; i<wave.size(); i++)
result.push_back(wave[i] - wave[i-1]);
return result;
}
std::vector<double> peaks (Wave wave, int n) {
std::vector<std::pair<double,double> > peaks;
for (int i=0; i<wave.size(); i++) {
double y1 = (i==0 ? wave[0] : wave[i-1]);
double y2 = wave[i];
double y3 = (i==wave.size()-1 ? wave[wave.size()-1] : wave[i+1]);
if ( fabs(y2) >= fabs(y1) && fabs(y2) >= fabs(y3) )
peaks.push_back({ i + gaussianPeak(y1, y2, y3), wave[i]});
}
std::sort(peaks.begin(), peaks.end(),
[](std::pair<double,double> a, std::pair<double,double> b) {
return fabs(b.second) < fabs(a.second);
});
Wave result;
for (int i=0;i<n && i<peaks.size(); i++)
result.push_back(peaks[i].first);
std::sort(result.begin(), result.end());
return result;
}
std::vector<double> derivPeaks (Wave wave, int n) {
std::vector<double> result = peaks(deriv(wave), n);
for (int i=0; i<result.size(); i++) {
result[i] += .5;
}
return result;
}
Wave rms(Wave orig, int window_width) {
Wave result(orig.size());
Wave pool(window_width);
int pool_ptr = 0;
double total = 0;
for (int i=0; i<orig.size(); i++) {
total -= pool[pool_ptr];
pool[pool_ptr] = pow(orig[i], 2);
total += pool[pool_ptr];
result[i] = sqrt(total / window_width);
pool_ptr = (pool_ptr+1) % window_width;
}
return result;
}

181
src/header.cc 100644
Wyświetl plik

@ -0,0 +1,181 @@
#include "common.hh"
#include <cmath>
/* pass: wave FM demodulated signal
* melody array of Tones
* (zero frequency to accept any)
* dt sample delta
*
* returns: (bool) did we find it
* (double) at which frequency shift
* (int) starting at how many dt from beginning of buffer
*/
std::tuple<bool,double,int> findMelody (Wave wave, Melody melody, double dt) {
bool was_found = true;
int start = 0;
double avg_fdiff = 0;
double freq_margin = 25;
double t = melody[melody.size()-1].dur;
std::vector<double> fdiffs;
for (int i=melody.size()-2; i>=0; i--) {
if (melody[i].freq != 0) {
double delta_f_ref = melody[i].freq - melody[melody.size()-1].freq;
double delta_f = wave[wave.size()-1 - (t/dt)] - wave[wave.size()-1];
double fshift = delta_f - delta_f_ref;
was_found &= fabs(fshift) < freq_margin;
}
start = wave.size() - (t / dt);
t += melody[i].dur;
}
if (was_found) {
int melody_i = 0;
double next_tone_t = melody[melody_i].dur;
for (int i=start; i<wave.size(); i++) {
double fref = melody[melody_i].freq;
double fdiff = (wave[i] - fref);
fdiffs.push_back(fdiff);
if ( (i-start)*dt >= next_tone_t ) {
melody_i ++;
next_tone_t += melody[melody_i].dur;
}
}
std::sort(fdiffs.begin(), fdiffs.end());
avg_fdiff = fdiffs[fdiffs.size()/2];
}
return { was_found, avg_fdiff, start };
}
SSTVMode modeFromNextHeader (DSPworker *dsp) {
double dt = 5e-3;
int bitlen = 30e-3 / dt;
int upsample_factor = 10;
int selmode, ptr=0;
int vis = 0, Parity = 0, ReadPtr = 0;
Wave HedrCirBuf(1100e-3 / dt);
Wave delta_f(1100e-3 / dt);
Wave freq(1100e-3 / dt);
Wave tone(1100e-3 / dt);
bool gotvis = false;
unsigned Bit[8] = {0}, ParityBit = 0;
Melody mmsstv_melody = {
Tone(100e-3, 1900), Tone(100e-3, 1500), Tone(100e-3, 1900), Tone(100e-3, 1500),
Tone(100e-3, 2300), Tone(100e-3, 1500), Tone(100e-3, 2300), Tone(100e-3, 1500),
Tone(300e-3, 1900)
};
Melody robot_melody = {
Tone(150e-3, 1900), Tone(150e-3, 1900), Tone(160e-3, 1900), Tone(150e-3, 1900),
Tone(30e-3, 1200), Tone(8*30e-3,0), Tone(30e-3, 1200)
};
fprintf(stderr,"Waiting for header\n");
while ( dsp->is_open() ) {
HedrCirBuf[ReadPtr] = dsp->peakFreq(500, 3300, WINDOW_HANN1023);
for (int i = 0; i < HedrCirBuf.size(); i++) {
freq[i] = HedrCirBuf[(ReadPtr + 1 + i) % HedrCirBuf.size()];
}
double fshift;
std::tuple<bool,double,int> has = findMelody(freq, mmsstv_melody, dt);
if (std::get<0>(has)) {
fshift = std::get<1>(has);
int start = std::get<2>(has);
fprintf(stderr," got MMSSTV header (t=%f s, fshift=%f Hz, start at %d)\n",dsp->get_t(), fshift, start);
Wave powers = rms(deriv(freq), 6);
for (int i=0; i<powers.size(); i++) {
}
Wave header_interp = upsampleLanczos(freq, upsample_factor, 1900);
std::vector<double> peaks_pos = derivPeaks(header_interp, 8);
printWave(freq, dt);
exit(0);
}
if (false) {
double fshift = ((delta_f[0] - 1900) + delta_f[4*bitlen] + delta_f[6*bitlen] + delta_f[8*bitlen] +
delta_f[10*bitlen]) / 5.0;
printf(" got robot header: t=%f, fshift=%+.1f Hz\n",dsp->get_t(),fshift);
// hi-res zero-crossing search
Wave abs_f(delta_f.size());
abs_f[0] = delta_f[0];
for (int i=1; i<abs_f.size(); i++)
abs_f[i] += delta_f[0] + delta_f[i];
Wave header_interp = upsampleLanczos(abs_f, upsample_factor);
int n_zc = 0;
double t_zc1=0, t_zc2=0;
double s=0,s0=0;
for (int i=0; i<header_interp.size(); i++) {
s = header_interp[i] - fshift - (1200.0+(1900.0-1200.0)/2.0);
double t = dsp->get_t() - (header_interp.size()-1-i)*dt/upsample_factor;
//printf("%f,%f\n",t,s);
if (i*dt/upsample_factor>15e-3 && s * s0 < 0) {
if (n_zc == 1) {
t_zc1 = t - dt + ((-s0)/(s-s0))*dt/upsample_factor;
}
if (n_zc > 1 && t > t_zc1+270e-3 ) {
t_zc2 = t - dt + ((-s0)/(s-s0))*dt/upsample_factor;
break;
}
n_zc++;
}
s0 = s;
}
printf (" n_zc=%d, t_zc1=%f, t_zc2=%fi (dur = %.05f ms, speed = %.5f)\n",n_zc,t_zc1,t_zc2,
(t_zc2-t_zc1)*1e3,
300e-3 / (t_zc2 - t_zc1)
);
int parity_rx=0;
for (int k=0; k<8; k++) {
if (abs_f[(13+k)*bitlen]+fshift < 1200) {
vis |= (1 << k);
parity_rx ++;
}
}
vis &= 0x7f;
printf(" got VIS: %dd (%02Xh) @ %+f Hz\n", vis, vis, fshift);
if (vis2mode.find(vis) == vis2mode.end()) {
printf(" Unknown VIS\n");
gotvis = false;
} else {
if ((parity_rx % 2) != ModeSpec[vis2mode[vis]].VISParity) {
printf(" Parity fail\n");
gotvis = false;
} else {
printf(" %s\n",ModeSpec[vis2mode[vis]].Name.c_str());
double start_of_video = t_zc2 + 10 * 30e-3;
dsp->forward_to_time(start_of_video);
break;
}
}
}
ReadPtr = (ReadPtr+1) % HedrCirBuf.size();
dsp->forward_time(dt);
}
return vis2mode[vis];
}

Wyświetl plik

@ -27,7 +27,7 @@ int main(int argc, char *argv[]) {
if (!dsp.is_open())
dsp.openPortAudio();
GetVideo(GetVIS(&dsp), &dsp);
GetVideo(modeFromNextHeader(&dsp), &dsp);
//SlowGUI gui = SlowGUI();
return 0;

Wyświetl plik

@ -1,39 +1,80 @@
#include "common.hh"
double findSyncHough (SSTVMode Mode, std::vector<bool> has_sync) {
void findSyncHough (SSTVMode Mode, std::vector<bool> has_sync) {
}
double findSyncAutocorr (SSTVMode Mode, std::vector<bool> has_sync) {
int line_width = ModeSpec[Mode].NumLines;
std::vector<int> jakauma;
int peak_speed = 0;
int peak_speed_val = 0;
int peak_pos = 0;
double min_spd = 0.998;
double max_spd = 1.002;
double spd_step = 0.0002;
for (double speed = min_spd; speed <= max_spd; speed += spd_step) {
std::vector<int> acc(line_width);
int peak_x = 0;
for (int i=0; i<has_sync.size(); i++) {
int x = int(i / speed + .5) % line_width;
acc[x] += has_sync[i];
if (acc[x] > acc[peak_x]) {
peak_x = x;
}
}
jakauma.push_back(acc[peak_x]);
if (acc[peak_x] > peak_speed_val) {
peak_speed = jakauma.size()-1;
peak_speed_val = acc[peak_x];
peak_pos = peak_x;
}
printf("(%.5f=%.0f) %d\n",1.0/speed,44100.0/speed,acc[peak_x]);
/*for (int x=0; x<acc.size(); x++) {
printf("%4d ",acc[x]);
}
printf("\n");*/
}
double peak_refined = peak_speed + gaussianPeak(jakauma[peak_speed-1], jakauma[peak_speed], jakauma[peak_speed+1]);
double spd = 1.0/(min_spd + peak_refined*spd_step);
printf("%.5f\n",spd);
printf("--> %.1f\n",44100*spd);
printf("pos = %d (%.1f ms)\n",peak_pos,1.0*peak_pos/line_width*ModeSpec[Mode].tLine*1000);
return spd;
}
void findSyncRansac(SSTVMode Mode, std::vector<bool> has_sync) {
int line_width = ModeSpec[Mode].NumLines;//ModeSpec[Mode].tLine / ModeSpec[Mode].tSync * 4;
std::vector<std::pair<int,int> > sync_pixels;
std::vector<Point> sync_pixels;
for (int y=0; y<ModeSpec[Mode].NumLines; y++) {
for (int x=0; x<line_width; x++) {
if (y+x>0 && has_sync[y*line_width + x] && !has_sync[y*line_width + x - 1]) {
sync_pixels.push_back({x,y});
sync_pixels.push_back(Point(x,y));
printf("%d,%d\n",x,y);
}
}
}
std::pair<std::pair<int,int>, std::pair<int,int> > best_line;
std::pair<Point, Point > best_line;
double best_dist = -1;
int it_num = 0;
while (++it_num < 300) {
std::random_shuffle(sync_pixels.begin(), sync_pixels.end());
std::pair<std::pair<int,int>, std::pair<int,int> > test_line = {sync_pixels[0], sync_pixels[1]};
int x0 = test_line.first.first;
int y0 = test_line.first.second;
int x1 = test_line.second.first;
int y1 = test_line.second.second;
std::pair<Point, Point > test_line = {sync_pixels[0], sync_pixels[1]};
int x0 = test_line.first.x;
int y0 = test_line.first.y;
int x1 = test_line.second.x;
int y1 = test_line.second.y;
double total_sq_dist = 0;
int total_good = 0;
for(std::pair<int,int> pixel : sync_pixels) {
int x = pixel.first;
int y = pixel.second;
for(Point pixel : sync_pixels) {
int x = pixel.x;
int y = pixel.y;
// Point distance to line
double d = 1.0 * ((y0-y1)*x + (x1-x0)*y + (x0*y1 - x1*y0)) / sqrt(pow(x1-x0,2) + pow(y1-y0,2));

Wyświetl plik

@ -1,13 +1,11 @@
#include "common.hh"
typedef struct {
int X;
int Y;
Point pt;
int Channel;
double Time;
} PixelSample;
bool sortPixelSamples(PixelSample a, PixelSample b) { return a.Time < b.Time; }
// Map to RGB & store in pixbuf
void toPixbufRGB(guint8 Image[800][800][3], Glib::RefPtr<Gdk::Pixbuf> pixbuf, SSTVMode Mode) {
@ -58,8 +56,7 @@ std::vector<PixelSample> getPixelSamplingPoints(SSTVMode Mode) {
for (int x=0; x<s.ScanPixels; x++) {
for (int Chan=0; Chan < (s.ColorEnc == COLOR_MONO ? 1 : 3); Chan++) {
PixelSample px;
px.X = x;
px.Y = y;
px.pt = Point(x,y);
px.Channel = Chan;
switch(s.SubSampling) {
@ -150,7 +147,9 @@ std::vector<PixelSample> getPixelSamplingPoints(SSTVMode Mode) {
}
}
std::sort(PixelGrid.begin(), PixelGrid.end(), sortPixelSamples);
std::sort(PixelGrid.begin(), PixelGrid.end(), [](PixelSample a, PixelSample b) {
return a.Time < b.Time;
});
return PixelGrid;
}
@ -199,22 +198,10 @@ bool GetVideo(SSTVMode Mode, DSPworker* dsp) {
double t = 0;
for (int PixelIdx = 0; PixelIdx < PixelGrid.size(); PixelIdx++) {
/*printf("expecting %d (%d,%d,%d)\n",PixelIdx,
PixelGrid[PixelIdx].X,
PixelGrid[PixelIdx].Y,
PixelGrid[PixelIdx].Channel
);*/
while (t < PixelGrid[PixelIdx].Time && dsp->is_open()) {
t += dsp->forward();
}
/*if (dsp->is_open()) {
printf("got it\n");
} else {
printf("didn't get it\n");
}*/
/*** Store the sync band for later adjustments ***/
if (dsp->get_t() >= next_sync_sample_time) {
@ -225,7 +212,7 @@ bool GetVideo(SSTVMode Mode, DSPworker* dsp) {
// If there is more than twice the amount of power per Hz in the
// sync band than in the video band, we have a sync signal here
has_sync.push_back(bands[0] > bands[1]);
has_sync.push_back(bands[0] > 2 * bands[1]);
next_sync_sample_time += ModeSpec[Mode].tLine / line_width;
@ -237,7 +224,7 @@ bool GetVideo(SSTVMode Mode, DSPworker* dsp) {
double SNR;
bool Adaptive = true;
if (PixelIdx == 0 || (Adaptive && PixelGrid[PixelIdx].X == s.ScanPixels/2)) {
if (PixelIdx == 0 || (Adaptive && PixelGrid[PixelIdx].pt.x == s.ScanPixels/2)) {
std::vector<double> bands = dsp->bandPowerPerHz({{300,1100}, {1500,2300}, {2500, 2700}});
double Pvideo_plus_noise = bands[1];
double Pnoise_only = (bands[0] + bands[2]) / 2;
@ -268,8 +255,8 @@ bool GetVideo(SSTVMode Mode, DSPworker* dsp) {
//measured.push_back({t, Lum});
//StoredLum[SampleNum] = clip((Freq - (1500 + CurrentPic.HedrShift)) / 3.1372549);
int x = PixelGrid[PixelIdx].X;
int y = PixelGrid[PixelIdx].Y;
int x = PixelGrid[PixelIdx].pt.x;
int y = PixelGrid[PixelIdx].pt.y;
int Channel = PixelGrid[PixelIdx].Channel;
// Store pixel
@ -279,7 +266,7 @@ bool GetVideo(SSTVMode Mode, DSPworker* dsp) {
}
/* sync */
findSyncRansac(Mode, has_sync);
findSyncAutocorr(Mode, has_sync);
toPixbufRGB(Image, pixbuf_rx, Mode);
toPixbufRGB(Imagesnr, pixbuf_snr, Mode);

Wyświetl plik

@ -1,118 +0,0 @@
#include "common.hh"
#include <cmath>
/*
*
* Detect Robot header & VIS
*
*/
SSTVMode GetVIS (DSPworker *dsp) {
double dt = 5e-3;
int bitlen = 30e-3 / dt;
int upsample_factor = 10;
int selmode, ptr=0;
int vis = 0, Parity = 0, ReadPtr = 0;
std::vector<double> HedrCirBuf(bitlen*22);
std::vector<double> delta_f(bitlen*22);
std::vector<double> tone(bitlen*22);
bool gotvis = false;
unsigned Bit[8] = {0}, ParityBit = 0;
printf("bitlen=%d\n",bitlen);
printf("Waiting for header\n");
while ( dsp->is_open() ) {
HedrCirBuf[ReadPtr] = dsp->peakFreq(500, 3300, WINDOW_HANN1023);
//printf("%f,%f\n",dsp->get_t(),HedrCirBuf[ReadPtr]);
delta_f[0] = HedrCirBuf[(ReadPtr+1) % HedrCirBuf.size()];
for (int i = 1; i < HedrCirBuf.size(); i++) {
delta_f[i] = HedrCirBuf[(ReadPtr + 1 + i) % HedrCirBuf.size()] - delta_f[0];
}
// Is there a pattern that looks like (the end of) a calibration header + VIS?
CurrentPic.HedrShift = 0;
gotvis = false;
double freq_margin = 25;
if ( fabs(delta_f[4*bitlen]) < freq_margin && fabs(delta_f[6*bitlen]) < freq_margin &&
fabs(delta_f[8*bitlen]) < freq_margin && fabs(delta_f[10*bitlen]) < freq_margin &&
fabs(delta_f[12*bitlen]+(1900-1200)) < freq_margin &&
fabs(delta_f[21*bitlen]+(1900-1200)) < freq_margin ) {
double fshift = ((delta_f[0] - 1900) + delta_f[4*bitlen] + delta_f[6*bitlen] + delta_f[8*bitlen] +
delta_f[10*bitlen]) / 5.0;
printf("header! t=%f, fshift=%+.1f Hz\n",dsp->get_t(),fshift);
// hi-res zero-crossing search
std::vector<double> abs_f(delta_f.size());
for (int i=1; i<abs_f.size(); i++)
abs_f[i] += delta_f[0] + delta_f[i];
std::vector<double> header_interp = upsampleLanczos(abs_f, upsample_factor);
int n_zc = 0;
double t_zc1=0, t_zc2=0;
double s=0,s0=0;
for (int i=0; i<header_interp.size(); i++) {
s = header_interp[i] - fshift - (1200.0+(1900.0-1200.0)/2.0);
double t = dsp->get_t() - (header_interp.size()-1-i)*dt/upsample_factor;
//printf("%f,%f\n",t,s);
if (i*dt/upsample_factor>15e-3 && s * s0 < 0) {
if (n_zc == 1) {
t_zc1 = t - dt + ((-s0)/(s-s0))*dt/upsample_factor;
}
if (n_zc == 2) {
t_zc2 = t - dt + ((-s0)/(s-s0))*dt/upsample_factor;
break;
}
n_zc++;
}
s0 = s;
}
/*printf ("n_zc=%d, t_zc1=%f, t_zc2=%fi (dur = %.05f ms, error = %.03f%%)\n",n_zc,t_zc1,t_zc2,
(t_zc2-t_zc1)*1e3,
(t_zc2 - t_zc1) / 300e-3 * 100 - 100
);*/
int parity_rx=0;
for (int k=0; k<8; k++) {
if (abs_f[(13+k)*bitlen]+fshift < 1200) {
vis |= (1 << k);
parity_rx ++;
}
}
vis &= 0x7f;
printf("VIS: %dd (%02Xh) @ %+f Hz\n", vis, vis, fshift);
if (vis2mode.find(vis) == vis2mode.end()) {
printf("Unknown VIS\n");
gotvis = false;
} else {
if ((parity_rx % 2) != ModeSpec[vis2mode[vis]].VISParity) {
printf("Parity fail\n");
gotvis = false;
} else {
printf("%s\n",ModeSpec[vis2mode[vis]].Name.c_str());
double start_of_video = t_zc2 + 10 * 30e-3;
dsp->forward_to_time(start_of_video);
break;
}
}
}
ReadPtr = (ReadPtr+1) % HedrCirBuf.size();
dsp->forward_time(dt);
}
return vis2mode[vis];
}