Oi Habr.
Provavelmente, muitas pessoas que compram um relógio ou estação meteorológica viram o logotipo do Rádio Controlado ou até o Relógio Atômico na embalagem. Isso é muito conveniente, porque basta colocar o relógio na mesa e, depois de um tempo, eles se ajustam automaticamente à hora exata.

Vamos ver como funciona e escrever um decodificador em Python.
Existem diferentes sistemas de sincronização de tempo. O mais popular na Europa é o sistema alemão
DCF-77 , o Japão possui seu próprio sistema
JJY , os EUA
possuem o sistema
WWVB e assim por diante. Além disso, a história será sobre o DCF77, como o mais relevante e disponível para recepção em alguns lugares da parte européia da Rússia e dos países vizinhos (os residentes do Extremo Oriente podem ter uma opinião oposta, no entanto, por sua vez, podem receber e analisar o sinal japonês;).
Tudo escrito abaixo será sobre DCF77.
Recepção de sinal
O DCF77 é uma estação de ondas longas operando a uma frequência de 77,5 KHz e transmitindo sinais em modulação de amplitude. A estação com capacidade de 50 kW está localizada a 25 km de Frankfurt, iniciou suas atividades em 1959, em 1973, quando as informações da data foram adicionadas à hora exata. O comprimento de onda a uma frequência de 77KHz é muito grande, portanto as dimensões do campo da antena também são muito decentes (foto da Wikipedia):

Com essa antena e entrada de energia, a área de recepção cobre quase toda a Europa, Bielorrússia, Ucrânia e parte da Rússia.

Todos podem gravar um sinal. Para fazer isso, basta ir ao receptor on-line
http://websdr.ewi.utwente.nl:8901/ , selecionar a frequência de 76,5 KHz e modulação USB. Uma imagem de algo assim deve abrir:

Lá, pressionamos o botão de download e gravamos um fragmento por vários minutos. Obviamente, se você tiver um receptor "real" capaz de gravar uma frequência de 77,5 KHz, poderá usá-lo.
Obviamente, quando recebermos sinais de rádio da hora exata pela Internet, não teremos uma hora realmente precisa - o sinal é transmitido com um atraso. Mas nosso objetivo é apenas entender a estrutura do sinal; para isso, a gravação na Internet é mais que suficiente. Na vida real, é claro, são usados dispositivos especializados para receber e decodificar, eles serão discutidos abaixo.
Então, nós temos o registro, vamos começar a processá-lo.
Decodificação de sinal
Faça o download do arquivo usando Python e veja sua estrutura:
from scipy.io import wavfile from scipy import signal import matplotlib.pyplot as plt import numpy as np sample_rate, data = wavfile.read("dcf_websdr_2019-03-26T20_25_34Z_76.6kHz.wav") plt.plot(data[:100000]) plt.show()
Vemos uma modulação de amplitude típica:

Para simplificar a decodificação, pegamos o envelope do sinal usando a transformação Hilbert:
analytic_signal = signal.hilbert(data) A = np.abs(analytic_signal) plt.plot(A[:100000])
Resultar em uma visão ampliada:

Suavizamos as emissões de interferência usando um filtro passa-baixo; ao mesmo tempo que calculamos o valor médio, será útil mais tarde para análise.
b, a = signal.butter(2, 20.0/sample_rate) zi = signal.lfilter_zi(b, a) A, _ = signal.lfilter(b, a, A, zi=zi*A[0]) avg = (np.amax(A) + np.amin(A))/2
Resultado (linha amarela): um sinal quase retangular que é bastante fácil de analisar.

Análise
Primeiro você precisa obter a sequência de bits. A estrutura do sinal em si é muito simples.

Os pulsos são divididos em segundos intervalos. Se a distância entre os pulsos for de 0,1 s (ou seja, o comprimento do próprio pulso é de 0,9 s), adicione "0" à sequência de bits, se a distância for de 0,2 s (ou seja, o comprimento é de 0,8 s), adicione "1". O final de cada minuto é indicado por um pulso “longo”, 2s de comprimento, a sequência de bits é redefinida para zero e o preenchimento é iniciado novamente.
O acima é fácil de escrever em Python.
sig_start, sig_stop = 0, 0 pos = 0 bits_str = "" while pos < cnt - 4: if A[pos] < avg and A[pos+1] > avg:
Como resultado, obtemos uma sequência de bits; em nosso exemplo, por dois minutos, fica assim:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
A propósito, é interessante que o sinal tenha uma "segunda camada" de dados. A sequência de bits também é codificada usando
modulação de fase . Teoricamente, isso deve fornecer uma decodificação mais estável, mesmo no caso de um sinal enfraquecido.
Nosso último passo: obtenha os dados reais. Os bits são transmitidos uma vez por segundo, portanto, temos apenas 59 bits, nos quais muitas informações são codificadas:

Os bits são descritos na
Wikipedia e são bastante curiosos. Os primeiros 15 bits não são utilizados, embora houvesse planos de uso para sistemas de alerta
e defesa civil . O bit A1 indica que na próxima hora o relógio será ajustado para o horário de verão. O bit A2 indica que um
segundo extra será adicionado na próxima hora, que às vezes é usada para corrigir o tempo de acordo com a rotação da Terra. Os bits restantes codificam horas, minutos e data.

Para aqueles que querem experimentar por conta própria, o código para decodificação é fornecido sob o spoiler.
Código fonte def decode(bits): if bits[0] != '0' or bits[20] != '1': return minutes, hours, day_of_month, weekday, month, year = map(convert_block, (bits[21:28], bits[29:35], bits[36:42], bits[42:45], bits[45:50], bits[50:58])) days = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday') print('{dow}, {dom:02}.{mon:02}.{y}, {h:02}:{m:02}'.format(h=hours, m=minutes, dow=days[weekday], dom=day_of_month, mon=month, y=year)) def convert_ones(bits): return sum(2**i for i, bit in enumerate(bits) if bit == '1') def convert_tens(bits): return 10*convert_ones(bits) def right_parity(bits, parity_bit): num_of_ones = sum(int(bit) for bit in bits) return num_of_ones % 2 == int(parity_bit) def convert_block(bits, parity=False): if parity and not right_parity(bits[:-1], bits[-1]): return -1 ones = bits[:4] tens = bits[4:] return convert_tens(tens) + convert_ones(ones)
Executando o programa, veremos algo como isto:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
Na verdade, isso é tudo mágico. A vantagem desse sistema é que a decodificação é extremamente simples e pode ser feita em qualquer microcontrolador mais simples. Apenas conte a duração dos pulsos, acumule 60 bits e, ao final de cada minuto, obtemos a hora exata. Em comparação com outros métodos de sincronização de tempo (GPS, por exemplo, ou Deus não permita, a Internet :), essa sincronização de rádio praticamente não requer eletricidade - por exemplo, uma estação meteorológica doméstica comum funciona por cerca de um ano a partir de 2 pilhas AA. Portanto, até um relógio de pulso é feito com sincronização de rádio, sem mencionar, é claro, sobre uma parede ou uma estação de rua.
A conveniência e simplicidade do DCF atraem os amantes de produtos caseiros. Por apenas US $ 10-20, você pode comprar um módulo pronto a partir de uma antena com um receptor pronto e saída TTL, que pode ser conectada a um Arduino ou outro controlador.

Para o Arduino,
bibliotecas prontas já foram escritas. No entanto, já se sabe que não importa o que você faça no microcontrolador, você recebe um relógio ou uma estação meteorológica. Com esse dispositivo, é realmente fácil obter a hora exata, desde que você esteja na área de recepção. Bem, você pode pendurar a inscrição "Relógio Atômico" no relógio e, ao mesmo tempo, explicar para todos que o desejarem, que o dispositivo está realmente sincronizado usando um relógio atômico.
Aqueles que desejam podem até atualizar os relógios das antigas avós instalando um novo mecanismo com sincronização de rádio:

Você pode encontrar um no ebay usando as palavras-chave "Movimento controlado por rádio".
E, finalmente, um truque para quem leu aqui. Mesmo se não houver um único transmissor de sinal de rádio nos próximos milhares de quilômetros, é fácil gerar um sinal desse tipo independentemente. O Google Play possui um programa chamado "DCF77 Emulator" que emite um sinal para os fones de ouvido. Segundo o autor, se você enrolar o fio do fone de ouvido no relógio, eles capturarão um sinal (eu me pergunto como, porque fones de ouvido comuns não emitem um sinal de 77KHz, mas provavelmente a recepção vem de harmônicos). Meu programa não funcionou no Android 9 - simplesmente não havia som (ou talvez eu não o tenha ouvido - 77KHz, afinal :)), mas talvez alguém tenha mais sorte. Alguns, no entanto, se transformam em um gerador de sinal DCF completo, fácil de fazer no mesmo Arduino ou ESP32:

(source
sgfantasytoys.wordpress.com/2015/05/13/synchronize-radio-controlled-watch-without-access )
Conclusão
O sistema DCF acabou sendo realmente bastante simples e conveniente. Com a ajuda de um receptor simples e barato, você pode ter a hora exata a qualquer hora, em qualquer lugar, é claro, na área de recepção. Parece que, apesar da digitalização generalizada e da "Internet das coisas", essas soluções simples serão demandadas por muito tempo.