How to detect Frequency Sweep Direction when Channel is unknown So I would like to try to modulate data using the direction of frequency sweep (a data bit of 1 would be an up sweep, and 0 a down sweep). Encoding my transmit signal is fairly easy, but i'm not sure how I would actually go about decoding the received signal. To help make things clear, please see the figure below where I have and 8 bit data stream, and the spectrogram of the transmitted and received signal. For this example my sampling frequency is $4000\textrm{ Hz}$, and my frequency sweeps are going from $0$ to $2000\textrm{ Hz}$



I've also added in a channel aspect the the figure above. My channel will be unkown, and will change from time to time (but will be constant during any single transmission). The figure below shows the channel response, which is just 2 stop bands.



In the first figure, I and can clearly see the patern of an up sweep and down sweep, but I'm not sure how I would go about actually decoding in an algorithm. I've done work with differential encoding (DPSK) and know how a method to sync and decode that kind of data, but i'm not quite sure where I would start here. The only think I could think of is to take over lapping FFT's and see which bins have the highest magnitude and try to track the direction from there.

Thanks for any input! Please let me know if I can clarify anything!

EDIT:

I tried using two matched filters as MBaz suggested such that my matched filter for my up sweep is $h$ = up sweep signal, in MATLAB it's chirp(time,startFreq,1,stopFreq). I'm then creating my matched filter output as seen below, where $y[n]$ is my output, and $x[n]$ is my received signal

$$y[n] = \sum_{i=0}^{\textrm{length}[h]} h[i]\star x[n+i]$$

I get the output as seen below, with thin spikes corresponding to the appropriate up and down sweeps. (note, it's hard to see, but there is a spike at the very beginning of the up sweep plot)



I'm hoping to get something similar to the bottom plot on the figure below, where the plot peaks at the end of the symbol, which could be used for syncing of the signal I believe.
See below for a python matched filter implementation. I generate an up-chirp and down-chirp. Then, subsequently I filter this signal by two matched filters, each filter is matched to one signal shape. As you see, there are two very strong peaks in the matched filtering. The reason why there are two peaks instead of (what you expect) slowly growing and falling triangles is that the chirps create an orthogonal basis, i.e. two time-shifted chirps are orthogonal, i.e. the MF output is zero. (The chirps are only orthogonal for infinite-time, which we dont have here, so there is still some small non-zero MF output). 

import scipy

Fs = 10000
t = np.arange(0, 2, 1/Fs)

f = 500*(2-t)

signal = np.sin(2*np.pi*f*t)  # generate an down- and upchirp

f_ax, t_ax, Sxx = scipy.signal.spectrogram(signal, Fs)
plt.figure(figsize=(8,8))

plt.subplot(211)
plt.pcolormesh(t_ax, f_ax, Sxx)

plt.subplot(212)
plt.plot(t, np.real(signal))

chirpDown = signal[:int(Fs)]  # extract both signal shapes from the signal
chirpUp = signal[int(Fs):]

rx = signal + 0*np.random.randn(*signal.shape)

# perform the matched filtering (this means convolving with the time-reversed sequence)
t_c = np.arange(0, 3, 1/Fs)[:-1]
plt.plot(t_c, np.convolve(chirpDown[::-1], rx))
plt.plot(t_c, np.convolve(chirpUp[::-1], rx));




So, in order to detect those peaks, you can select the maximum of the MF output for each symbol duration (in case you are not perfectly synchronized) and compare which MF had higher output. Then, you reset the maximum value and search the next symbol period. Alternatively, you can convolve the filter output with some triangle or Gaussian, to get wider peaks.  For example, you can do the following to get an output similar to your posted figure:

triang = 1-abs(np.arange(-1,1,1/Fs))
# perform the matched filtering
t_c = np.arange(0, 3, 1/Fs)[:-1]
mf1 = np.convolve(chirpDown[::-1], rx)
mf2 = np.convolve(chirpUp[::-1], rx)
plt.plot(t_c, mf1)
plt.plot(t_c, mf2)

plt.figure()
plt.plot(np.convolve(mf1-mf2, triang))