2014-10-09 3 views
0

Мне нужно перенести множество «32-битных плавающих» переменных с одного DSP на другой DSP через SPI.передать переменную «32bit float»

Однако регистр является alaways 16bit, что мне нужно разбить переменную «32bit float» на две части.

Я использовал тип C союз как

union mytype { 
    float a; 
    uint16_t b[2]; 
}; 

Это хорошо работает, но я получаю новую проблему, что трудно понять, является ли полученные данные 16bit для Ь [0] или б [1] в запускать. (Два DSP могут включаться в разное время, поэтому 1-й данные не всегда могут быть b [0]).

Я попытался разбить 32-битный поплавок на 4 байта, а когда я передаю 16-битный, я добавляю тег перед 8-битными данными. Это также прекрасно работает. Но у меня производительность снизилась вдвое.

Есть ли способ передать «32-битный поплавок» двумя 16-битными данными? Я знал, что мой диапазон номеров находится в пределах «0.0000001 ~ 1000000» (оба +/-). Или любые другие предложения? Я также думаю о дрожании рук в SPI между двумя DSP, но, похоже, он становится сложным. Я просто хочу захватить данные запуска b [0], затем я могу получить все в последовательности.

БЛАГОДАРЯ

+0

Так что вы хотите разбить поплавок на два 16-битных куска, каждый из которых также несет информацию о том, является ли это первым фрагментом или вторым, верно? –

+0

Да, точно .... – thundium

+0

Это слишком широкий. Читайте о [формате с плавающей точкой] (http://en.wikipedia.org/wiki/Single-precision_floating-point_format). Вы можете попытаться повторно использовать неиспользуемые биты в экспоненциальной части (потому что ваши цифры относительно близки к 1) или опустить младшие бит части дроби. –

ответ

1

Вот идея, если вы можете жить с некоторой минимальной потерей точности на большом количестве:

Потерять два младших бита поплавка (биты 0 и 1). Затем переставить биты поплавка таким образом, что:

  • б [0] содержит 0 и биты 16..2 поплавка
  • б [1] содержит 1 и биты 31..17 из плавать

Затем, когда вы получите 16 разрядное целое число, проверить значащий бит, чтобы увидеть, если это абы [0] или абы [1], и восстановить ваш поплавок с 2 нулями на битах 0 и 1.

Потеря точности должна быть минимальной по диапазону нужных чисел, и это преобразование требует только логических операций , поэтому он должен быть быстрым.

+0

Отбрасывая последний бит, цифры, такие как 0.9876543 и 0.9876542, отправляются как 0.9876542. Если терпимо, хорошая идея. – chux

+0

@chux Да, это потеря точности, о которой я говорю :) – Cantfindname

+1

Учитывая узкий диапазон, вы могли бы взять два бита из ведущих битов экспоненты, а не по значению. Это сохранит исходную точность, но уменьшит поддерживаемый диапазон. –

0

Если данные полезной нагрузки не содержат NaN, периодически отправляйте два куска по одному биту. Когда приемник запускается, он сканирует данные до тех пор, пока не увидит такую ​​пару, а затем берет следующий фрагмент с хотя бы одним нулевым битом как ab [0], следующий фрагмент как его b [1] и т. Д.

Каждый последующий раз, когда он видит пару с одним битом, он должен игнорировать его.

У вас возникнет компромисс между тем, сколько трафика вы тратите на отправку ненужных пар «все-бит-1», а также количество данных, которое получает, прежде чем получать синхронизацию и обработку реальных данных при запуске.

1

Сложите идею @Cantfindname, но удалите из экспоненты 2 бита. Нет потери точности.

Кроме того, отверните любые пары из последовательности, чтобы предотвратить формирование float из половин, которые не принадлежат друг другу.

Я вижу @Patricia Shanahan прокомментировал это.

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

void encode(float f, uint16_t *u16) { 
    volatile union { 
    float f; 
    uint32_t u; 
    } x; 
    x.f = f; 
    x.u -= 0x30000000u; 
    u16[0] = 0x0000u | ((x.u >> 0) & 0x7FFFu); 
    u16[1] = 0x8000u | ((x.u >> 17) & 0x4000u) | ((x.u >> 15) & 0x3FFFu); 
} 

int decode(const uint16_t *u16, float *f) { 
    volatile union { 
    float f; 
    uint32_t u; 
    } x; 
    if (((u16[0] & 0x8000u) != 0x0000u) || ((u16[1] & 0x8000u) != 0x8000u)) { 
    printf("Fail\n"); 
    return 1; // fail 
    } 
    x.u = (u16[1] & 0x4000ul) << 17; 
    x.u |= (u16[1] & 0x3FFFul) << 15; 
    x.u |= (u16[0] & 0x7FFFu); 
    x.u += 0x30000000u; 
    *f = x.f; 
    return 0; 
} 

int test(float f) { 
    uint16_t u[2]; 
    encode(f, u); 
    float f2; 
    decode(u, &f2); 
    if (f != f2) { 
    printf("%.8e %.8e\n", f, f2); 
    } 
    return f != f2; 
} 

#include <math.h> 

int main(void) { 
    float f; 
    for (f= 0.0000001; f <= 1000000.0; f = nextafterf(f,2*f)) { 
    test(f); 
    test(-f); 
    } 
    return 0; 
    puts("Done"); 
} 

Учитывая диапазон "0,0000001 ~ 1 млн", то MSBits из в binary32 float всегда S011 в s100. s - это бит знака. Вычитая 3, диапазон равен s000s001. Это позволяет игнорировать средние 2 бита, и тогда необходимо поддерживать только 30 бит 32-битного поплавка. Отправка 2 16-битных сообщений, каждый с «фазным» битом и 15-битной частью из 30 бит, позволяет полностью восстановить оригинал float.

Если принимающая сторона получает сообщение не в фазе, оно должно игнорировать сообщения до тех пор, пока не поступит последовательная фаза-0/фаза-1.


Пути вычитания других значений, по меньшей мере, один бит больше, может быть проигнорирован, позволяя дополнительный номер бита последовательности, дополнительно гарантируя правильное повторное сочетание. В конце концов, используется только 340 000 000 комбинаций из 4 294 967 296 floats.

0

Если этот диапазон является абсолютным, вам нужно всего лишь 28 бит, чтобы выразить его. Это оставляет вам 4 делать то, что вы хотите. Я бы рекомендовал сделать первые 2 бита либо uint16 идентификатором, чтобы, когда вы его получите, вы можете выполнить некоторую операцию над ним, чтобы решить, какая часть его целого.

+0

. Пожалуйста, подробно объясните, как «0.0000001 ~ 1000000» (оба +/-) «нужно всего 20 бит, чтобы выразить это. считал, что это любые +/- 6 или 7-значные числа в диапазоне экспонентов 10^-7 до 10^6. Или около 23 (значащий) + 4 (expo) + 1 знак = 28 бит, но это может быть чрезмерно консервативным – chux

+0

Я думаю, что вы правы, но у вас все еще есть бит, чтобы подписать – ragingSloth

Смежные вопросы